def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.analyze = Data_Analysis(self.config) #json output, note module version number defined here self.jsondict = {'type':'baseline_test'} self.jsondict['monitor_code_version'] = '1.1' self.jsondict['monitor_timestamp'] = datetime.datetime.today().strftime('%Y%m%d%H%M%S')
def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.sync_functions = self.functions.sync self.plotting = self.functions.sync.plot #json output, note module version number defined here self.syncdict = {'type': 'sync_adcs'} self.syncdict['sync_code_version'] = '1.1' self.syncdict['sync_timestamp'] = datetime.datetime.today().strftime( '%Y%m%d%H%M%S')
class MONITOR_TESTER(object): def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.analyze = Data_Analysis(self.config) #json output, note module version number defined here self.jsondict = {'type':'baseline_test'} self.jsondict['monitor_code_version'] = '1.1' self.jsondict['monitor_timestamp'] = datetime.datetime.today().strftime('%Y%m%d%H%M%S') def check_setup(self): print("MONITOR - SETUP") self.functions.initBoard(default_sync = False) if (self.params['using_power_supply'] == True): self.PowerSupply = Power_Supply(self.config) if (self.PowerSupply.interface == None): sys.exit("SYNCHRONIZATION --> Power Supply not found!") def record_data(self): print("MONITOR - COLLECT DATA") #Read from TEST output ADCs self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_READOUT_OPTIONS"]), int(self.config["DEFINITIONS"]["READOUT_TEST_ADC"])) #Select the monitor readout to ADC self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_ADC_GND"])) #Adds tracer bits on data coming in when the internal pulser has an edge self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_TAGGING"]), int(self.config["DEFINITIONS"]["TAGGING_ON"])) #Get the ASIC to send out pulses self.low_level.setInternalPulser(period = int(self.config["MONITOR_SETTINGS"]["MONITOR_FREQ"]), shift = int(self.config["MONITOR_SETTINGS"]["MONITOR_DLY"]), enable = True) self.low_level.setExternalPulser(enable = False) self.power_info_total = [] for i in self.params['working_chips']: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join(chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) os.makedirs(data_directory, exist_ok=True) for chn in range(int(self.config["DEFAULT"]["NASICCH_MIN"]), int(self.config["DEFAULT"]["NASICCH_MAX"]) + 1, 1): self.functions.configFeAsic(test_cap="on", base=self.config["SYNC_SETTINGS"]["SYNC_BASELINE"], gain=self.config["SYNC_SETTINGS"]["SYNC_GAIN"], shape=self.config["SYNC_SETTINGS"]["SYNC_PEAK"], monitor_ch=None, buffer=self.config["SYNC_SETTINGS"]["SYNC_BUFFER"], leak = self.config["SYNC_SETTINGS"]["SYNC_LEAK"], monitor_param = None, s16=None, acdc=self.config["SYNC_SETTINGS"]["SYNC_ACDC"], test_dac="test_int", dac_value=int(self.config["MONITOR_SETTINGS"]["MONITOR_AMPL"])) self.functions.FE_Regs.set_fe_chn(chip = i, chn = chn, smn = 1) self.functions.writeFE() monitor_file_notation = self.config["FILENAMES"]["MONITOR_NAMING"] filename = monitor_file_notation.format(chn) full_filename = os.path.join(data_directory,filename) packets = int(self.config["MONITOR_SETTINGS"]["MONITOR_PACKETS"]) data = self.low_level.get_data_chipXchnX_tagged(chip = i, chn = chn, packets = packets, data_format = "bin", header = False) buffer = len(data) bin_data = struct.pack(">%dH"%buffer, *data) with open(full_filename,"wb") as f: f.write(bin_data) f.close() power_info = self.functions.PCB_power_monitor(chips = i) self.power_info_total.append(power_info) if (self.params['using_power_supply'] == True): pwr = self.config["POWER_SUPPLY"] self.heating_results = self.PowerSupply.measure_params(channel = int(pwr["PS_HEATING_CHN"])) self.quad_results = self.PowerSupply.measure_params(channel = int(pwr["PS_QUAD_CHN"])) self.fpga_results = self.PowerSupply.measure_params(channel = int(pwr["PS_FPGA_CHN"])) #Bring things back to normal self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_READOUT_OPTIONS"]), int(self.config["DEFINITIONS"]["READOUT_NORMAL"])) self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_TAGGING"]), int(self.config["DEFINITIONS"]["TAGGING_OFF"])) self.low_level.setInternalPulser(period = int(self.config["SYNC_SETTINGS"]["SYNC_INTERNAL_PULSE_FREQ"]), shift = int(self.config["SYNC_SETTINGS"]["SYNC_INTERNAL_PULSE_DLY"]), enable = False) def do_analysis(self): print("MONITOR - ANALYZE") self.results = [] self.peaks = [] self.differences = [] self.average_peak = [] for i in self.params["working_chips"]: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join(chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) #To grab baseline jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],self.config["FILENAMES"]["RESULTS"]) with open(jsonFile,'r') as f: existing_json = json.load(f) baseline_outlabel = existing_json["baseline_outlabel"] jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],baseline_outlabel, self.config["FILENAMES"]["RESULTS"]) result, peaks, differences, average_peak = self.analyze.monitor_directory(chip_outpathlabel, data_directory, chip_name, i, jsonFile) self.results.append(result) self.peaks.append(peaks) self.differences.append(differences) self.average_peak.append(average_peak) def archiveResults(self): print("MONITOR - ARCHIVE") self.jsondict['monitor_executable'] = self.params['executable'] self.jsondict['monitor_datasubdir'] = self.params['datasubdir'] self.jsondict['monitor_outlabel'] = self.params['outlabel'] if (self.params['using_power_supply'] == True): self.jsondict['PS_heating_voltage'] = self.heating_results[0] self.jsondict['PS_heating_current'] = self.heating_results[1] self.jsondict['PS_quad_voltage'] = self.quad_results[0] self.jsondict['PS_quad_current'] = self.quad_results[1] self.jsondict['PS_fpga_voltage'] = self.fpga_results[0] self.jsondict['PS_fpga_current'] = self.fpga_results[1] for num, i in enumerate(self.params['working_chips']): chip_name = self.params['chip_list'][i][1] jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],self.params["outlabel"], self.config["FILENAMES"]["RESULTS"]) if (self.results[num] == True): self.jsondict['monitor_result'] = "PASS" elif (self.results[num] == False): self.jsondict['monitor_result'] = "FAIL" else: self.jsondict['monitor_result'] = "N/A" self.jsondict['monitor_average_peak'] = self.average_peak[num] self.jsondict['vdda_shunt_voltage'] = self.power_info_total[num][0][0] self.jsondict['vdda_bus_voltage'] = self.power_info_total[num][0][1] self.jsondict['vdda_current'] = self.power_info_total[num][0][2] self.jsondict['vddp_shunt_voltage'] = self.power_info_total[num][1][0] self.jsondict['vddp_bus_voltage'] = self.power_info_total[num][1][1] self.jsondict['vddp_current'] = self.power_info_total[num][1][2] for chn in range(int(self.config["DEFAULT"]["NASICCH_MIN"]), int(self.config["DEFAULT"]["NASICCH_MAX"]) + 1, 1): jsname = "monitor_peak{}".format(chn) self.jsondict[jsname] = self.peaks[num][chn][1] jsname = "monitor_difference{}".format(chn) self.jsondict[jsname] = self.differences[num][chn] with open(jsonFile,'a') as outfile: json.dump(self.jsondict, outfile, indent=4) jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],self.config["FILENAMES"]["RESULTS"]) with open(jsonFile,'r') as f: existing_json = json.load(f) existing_json['monitor_outlabel'] = self.params['outlabel'] with open(jsonFile,'w') as outfile: json.dump(existing_json, outfile, indent=4)
def __init__(self, master=None): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) #Gets the low level module to do UDP packets self.femb = self.functions.lower_functions self.master = master self.functions.configFeAsic( test_cap="on", base=self.config["SYNC_SETTINGS"]["SYNC_BASELINE"], gain=self.config["SYNC_SETTINGS"]["SYNC_GAIN"], shape=self.config["SYNC_SETTINGS"]["SYNC_PEAK"], monitor_ch=None, buffer=self.config["SYNC_SETTINGS"]["SYNC_BUFFER"], leak=self.config["SYNC_SETTINGS"]["SYNC_LEAK"], monitor_param=None, s16=None, acdc=self.config["SYNC_SETTINGS"]["SYNC_ACDC"], test_dac="test_int", dac_value=int( self.config["SYNC_SETTINGS"]["SYNC_DAC_PEAK_HEIGHT"])) self.functions.writeFE() #Creates Tkinter object Tk.Frame.__init__(self, master) # hack to make work in python2 self.pack() #Creates Matplotlib object self.figure = Figure(figsize=(20, 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) #Create toolbar for bottom self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.update() 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) pulse_options = ["None", "Internal Pulse", "External Pulse"] self.pulse_entry_choices = Tk.StringVar(self.master, name="pulse_entry") self.pulse_entry_choices.set(pulse_options[0]) # initial value self.pulse_entry_choices.trace("w", self.gui_callback) self.pulse_entry = Tk.OptionMenu(self, self.pulse_entry_choices, *pulse_options) self.pulse_entry.pack(side=Tk.LEFT) self.chip = 0 chip_options = [] for i in range(int(self.config["DEFAULT"]["NASICS"])): chip_options.append("Chip {}".format(i)) self.chip_entry_choices = Tk.StringVar(self.master, name="chip_entry") self.chip_entry_choices.set(chip_options[0]) # initial value self.chip_entry_choices.trace("w", self.gui_callback) self.chip_entry = Tk.OptionMenu(self, self.chip_entry_choices, *chip_options) self.chip_entry.pack(side=Tk.LEFT) self.packets = 2 self.packet_label = Tk.Label(self, text="Packet Length:", width=11) self.packet_label.pack(side=Tk.LEFT) self.packet_entry = Tk.Spinbox(self, width=5, from_=1, to=100, name="patcket_entry", command=self.packet_change) self.packet_entry.delete(0, "end") self.packet_entry.insert(0, self.packets) self.packet_entry.pack(side=Tk.LEFT) self.manualSyncButton = Tk.Button(self, text="Manual Sync", command=self.manualSync) self.manualSyncButton.pack(side=Tk.LEFT) self.reset()
class TRACE_VIEWER(Tk.Frame): """ This window displays a live ADC readout """ def __init__(self, master=None): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) #Gets the low level module to do UDP packets self.femb = self.functions.lower_functions self.master = master self.functions.configFeAsic( test_cap="on", base=self.config["SYNC_SETTINGS"]["SYNC_BASELINE"], gain=self.config["SYNC_SETTINGS"]["SYNC_GAIN"], shape=self.config["SYNC_SETTINGS"]["SYNC_PEAK"], monitor_ch=None, buffer=self.config["SYNC_SETTINGS"]["SYNC_BUFFER"], leak=self.config["SYNC_SETTINGS"]["SYNC_LEAK"], monitor_param=None, s16=None, acdc=self.config["SYNC_SETTINGS"]["SYNC_ACDC"], test_dac="test_int", dac_value=int( self.config["SYNC_SETTINGS"]["SYNC_DAC_PEAK_HEIGHT"])) self.functions.writeFE() #Creates Tkinter object Tk.Frame.__init__(self, master) # hack to make work in python2 self.pack() #Creates Matplotlib object self.figure = Figure(figsize=(20, 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) #Create toolbar for bottom self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.update() 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) pulse_options = ["None", "Internal Pulse", "External Pulse"] self.pulse_entry_choices = Tk.StringVar(self.master, name="pulse_entry") self.pulse_entry_choices.set(pulse_options[0]) # initial value self.pulse_entry_choices.trace("w", self.gui_callback) self.pulse_entry = Tk.OptionMenu(self, self.pulse_entry_choices, *pulse_options) self.pulse_entry.pack(side=Tk.LEFT) self.chip = 0 chip_options = [] for i in range(int(self.config["DEFAULT"]["NASICS"])): chip_options.append("Chip {}".format(i)) self.chip_entry_choices = Tk.StringVar(self.master, name="chip_entry") self.chip_entry_choices.set(chip_options[0]) # initial value self.chip_entry_choices.trace("w", self.gui_callback) self.chip_entry = Tk.OptionMenu(self, self.chip_entry_choices, *chip_options) self.chip_entry.pack(side=Tk.LEFT) self.packets = 2 self.packet_label = Tk.Label(self, text="Packet Length:", width=11) self.packet_label.pack(side=Tk.LEFT) self.packet_entry = Tk.Spinbox(self, width=5, from_=1, to=100, name="patcket_entry", command=self.packet_change) self.packet_entry.delete(0, "end") self.packet_entry.insert(0, self.packets) self.packet_entry.pack(side=Tk.LEFT) self.manualSyncButton = Tk.Button(self, text="Manual Sync", command=self.manualSync) self.manualSyncButton.pack(side=Tk.LEFT) self.reset() def reset(self): self.figure.clf() self.subgs = [None] * 16 self.ax = [None] * 16 self.plot = [None] * 16 self.figure.text(0.5, 0.02, 'Time [us]', ha='center', color='black', fontsize='25.0', weight='bold') self.figure.text(0.08, 0.625, 'ADC counts', ha='center', rotation=90, color='black', fontsize='25.0', weight='bold') # 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, create axes objects for row in range(4): for col in range(4): ch = col + 4 * row self.subgs[ch] = gridspec.GridSpecFromSubplotSpec( 1, 1, subplot_spec=self.gs[ch], hspace=0.0) self.ax[ch] = self.figure.add_subplot(self.subgs[ch][0]) self.ax[ch].tick_params(axis='x', colors='black', labelsize='medium') self.ax[ch].tick_params(axis='y', colors='black', labelsize='smaller') #Continually updates by calling self.plotData self.ani = animation.FuncAnimation(self.figure, self.plotData, interval=1000, blit=True) self.canvas.draw() def packet_change(self): self.packets = int(self.packet_entry.get()) def gui_callback(self, *args, **kwargs): if (args[0] == "pulse_entry"): if (self.pulse_entry_choices.get() == "None"): self.femb.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_GND"])) elif (self.pulse_entry_choices.get() == "Internal Pulse"): self.femb.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_GND_INTPULSE"])) elif (self.pulse_entry_choices.get() == "External Pulse"): self.femb.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_DACPULSE"])) elif (args[0] == "chip_entry"): self.chip = int( re.findall(r'\d+', self.chip_entry_choices.get())[0]) def pause(self): self.ani.event_source.stop() self.pauseButton['state'] = Tk.DISABLED self.playButton['state'] = Tk.NORMAL def play(self): self.ani.event_source.start() self.pauseButton['state'] = Tk.NORMAL self.playButton['state'] = Tk.DISABLED def plotData(self, iFrame): for a in self.ax: #Clears all previous traces a.cla() #Limits the number of traces on each subplot a.locator_params(tight=True, nbins=3) #In case no data, return an empty plot # self.plot[0] = self.ax[0].plot() t, adc, thistimestamp = self.getData() for r in range(4): for c in range(4): ch = c + 4 * r if not (t is None) and not (adc is None): self.plot[ch] = self.ax[ch].plot(t, adc[ch]) if ch < 12: self.ax[ch].set_xticklabels([]) self.ax[ch].title.set_text("Channel {}".format(ch)) if not (thistimestamp is None): self.figure.suptitle( thistimestamp.replace(microsecond=0).isoformat(" ")) self.canvas.draw() return self.plot[0] def closeSync(self): self.syncWindow.destroy() self.syncWindow.quit() self.syncWindow = None def manualSync(self): self.syncWindow = Tk.Toplevel(self.master) self.app = manSync(self.syncWindow, config=self.config, femb=self.femb) self.syncWindow.title("Manual Synchronization") def getData(self): """ Gets trace from FEMB and returns 4 1D arrays: times, ADC counts """ data = self.femb.get_data_chipX(chip=self.chip, packets=self.packets, data_format="counts", tagged=False, header=False) # data = [[1,2,3,4,5,6,7,8,9,10]]*16 timestamp = datetime.datetime.now() if data == None: return None, None, None if len(data) == 0: return None, None, None xpoint = [] for num, samp in enumerate(data[0]): xpoint.append(num * float(self.config["DEFAULT"]["SAMPLE_PERIOD"])) return xpoint, data, timestamp
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)
class ALIVE_TESTER(object): def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.analyze = Data_Analysis(self.config) #json output, note module version number defined here self.jsondict = {'type':'baseline_test'} self.jsondict['alive_code_version'] = '1.1' self.jsondict['alive_timestamp'] = datetime.datetime.today().strftime('%Y%m%d%H%M%S') def check_setup(self): print("ALIVE - SETUP") self.functions.initBoard(default_sync = False) if (self.params['using_power_supply'] == True): self.PowerSupply = Power_Supply(self.config) if (self.PowerSupply.interface == None): sys.exit("SYNCHRONIZATION --> Power Supply not found!") def record_data(self): print("ALIVE - COLLECT DATA") #Read from regular ADCs self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_READOUT_OPTIONS"]), int(self.config["DEFINITIONS"]["READOUT_NORMAL"])) #Adds tracer bits on data coming in when the internal pulser has an edge self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_TAGGING"]), int(self.config["DEFINITIONS"]["TAGGING_ON"])) #Make sure no unwanted pulses self.low_level.setInternalPulser(enable = False) self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_DACPULSE"])) self.low_level.setExternalPulser(period = int(self.config["MONITOR_SETTINGS"]["MONITOR_FREQ"]), shift = int(self.config["MONITOR_SETTINGS"]["MONITOR_DLY"]), enable = True) self.power_info_total = [] for i in self.params['working_chips']: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join(chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) os.makedirs(data_directory, exist_ok=True) for test in ["test_off", "test_ext"]: self.functions.configFeAsic(test_cap="on", base=self.config["ALIVE_SETTINGS"]["ALIVE_BASELINE"], gain=self.config["ALIVE_SETTINGS"]["ALIVE_GAIN"], shape=self.config["ALIVE_SETTINGS"]["ALIVE_PEAK"], monitor_ch=None, buffer="on", leak = self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"], monitor_param = None, s16=None, acdc=self.config["ALIVE_SETTINGS"]["ALIVE_ACDC"], test_dac=test, dac_value=0) self.functions.writeFE() if (test == "test_off"): self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_DACPULSE"])) self.low_level.setExternalPulser(val = int(self.config["ALIVE_SETTINGS"]["ALIVE_DAC_IN"]), period = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_PERIOD"]), shift = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_SHIFT"]), enable = True) elif (test == "test_ext"): self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_DACPULSE_GND"])) self.low_level.setExternalPulser(val = int(self.config["ALIVE_SETTINGS"]["ALIVE_DAC_MON"]), period = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_PERIOD"]), shift = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_SHIFT"]), enable = True) packets = int(self.config["ALIVE_SETTINGS"]["ALIVE_PACKETS"]) data = self.low_level.get_data_chipX(chip = i, tagged = True, packets = packets, header = False) for chn in range(int(self.config["DEFAULT"]["NASICCH_MIN"]), int(self.config["DEFAULT"]["NASICCH_MAX"]) + 1, 1): alive_file_notation = self.config["FILENAMES"]["ALIVE_NAMING"] filename = alive_file_notation.format(chn,self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"],test) full_filename = os.path.join(data_directory,filename) chn_data = data[chn] buffer = len(chn_data) bin_data = struct.pack(">%dH"%buffer, *chn_data) with open(full_filename,"wb") as f: f.write(bin_data) f.close() power_info = self.functions.PCB_power_monitor(chips = i) self.power_info_total.append(power_info) if (self.params['using_power_supply'] == True): pwr = self.config["POWER_SUPPLY"] self.heating_results = self.PowerSupply.measure_params(channel = int(pwr["PS_HEATING_CHN"])) self.quad_results = self.PowerSupply.measure_params(channel = int(pwr["PS_QUAD_CHN"])) self.fpga_results = self.PowerSupply.measure_params(channel = int(pwr["PS_FPGA_CHN"])) self.power_cycle_PCB_power = [] self.power_cycle_heating_results = [] self.power_cycle_quad_results = [] self.power_cycle_fpga_results = [] temp = self.params['temperature'] if (temp == "LN"): total_cycles = int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_1"]) + int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_2"]) print("Test--> Testing {} power cycles ({} seconds in between for the first {}, {} seconds in between for the next {})".format(total_cycles, self.config["ALIVE_SETTINGS"]["ALIVE_TIME_OFF_1"], self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_1"], self.config["ALIVE_SETTINGS"]["ALIVE_TIME_OFF_2"], self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_2"])) for cycle in range(total_cycles): self.power_cycle_PCB_power.append([]) print("Test--> Cycle {}".format(cycle)) self.functions.turnOffAsics() if (cycle < int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_1"])): time.sleep(float(self.config["ALIVE_SETTINGS"]["ALIVE_TIME_OFF_1"])) else: time.sleep(float(self.config["ALIVE_SETTINGS"]["ALIVE_TIME_OFF_2"])) self.functions.turnOnAsics() for test in ["test_off", "test_ext"]: self.functions.configFeAsic(test_cap="on", base=self.config["ALIVE_SETTINGS"]["ALIVE_BASELINE"], gain=self.config["ALIVE_SETTINGS"]["ALIVE_GAIN"], shape=self.config["ALIVE_SETTINGS"]["ALIVE_PEAK"], monitor_ch=None, buffer="on", leak = self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"], monitor_param = None, s16=None, acdc=self.config["ALIVE_SETTINGS"]["ALIVE_ACDC"], test_dac=test, dac_value=0) self.functions.writeFE() if (test == "test_off"): self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_DACPULSE"])) self.low_level.setExternalPulser(val = int(self.config["ALIVE_SETTINGS"]["ALIVE_DAC_IN"]), period = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_PERIOD"]), shift = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_SHIFT"]), enable = True) elif (test == "test_ext"): self.low_level.femb_udp.write_reg(int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_DACPULSE_GND"])) self.low_level.setExternalPulser(val = int(self.config["ALIVE_SETTINGS"]["ALIVE_DAC_MON"]), period = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_PERIOD"]), shift = int(self.config["ALIVE_SETTINGS"]["ALIVE_TP_SHIFT"]), enable = True) packets = int(self.config["BASELINE_SETTINGS"]["BASELINE_PACKETS"]) for i in self.params['working_chips']: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join(chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) os.makedirs(data_directory, exist_ok=True) data = self.low_level.get_data_chipXchnX_tagged(chn = 1, chip = i, packets = packets, header = False) cycle_file_notation = self.config["FILENAMES"]["ALIVE_NAMING2"] filename = cycle_file_notation.format(self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"],test,cycle) full_filename = os.path.join(data_directory,filename) buffer = len(data) bin_data = struct.pack(">%dH"%buffer, *data) with open(full_filename,"wb") as f: f.write(bin_data) f.close() power_info = self.functions.PCB_power_monitor(chips = i) self.power_cycle_PCB_power[cycle].append(power_info) if (self.params['using_power_supply'] == True): pwr = self.config["POWER_SUPPLY"] self.power_cycle_heating_results.append(self.PowerSupply.measure_params(channel = int(pwr["PS_HEATING_CHN"]))) self.power_cycle_quad_results.append(self.PowerSupply.measure_params(channel = int(pwr["PS_QUAD_CHN"]))) self.power_cycle_fpga_results.append(self.PowerSupply.measure_params(channel = int(pwr["PS_FPGA_CHN"]))) print ("Test--> Input Alive data completed") def do_analysis(self): print("ALIVE - ANALYZE") self.results = [] for i in self.params["working_chips"]: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join(chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) result = self.analyze.alive_directory(chip_outpathlabel, chip_name, data_directory, ["test_off", "test_ext"], self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"], self.params['temperature']) self.results.append(result) def archiveResults(self): print("ALIVE - ARCHIVE") self.jsondict['alive_executable'] = self.params['executable'] self.jsondict['alive_datasubdir'] = self.params['datasubdir'] self.jsondict['alive_outlabel'] = self.params['outlabel'] self.jsondict['alive_gain'] = self.config["ALIVE_SETTINGS"]["ALIVE_GAIN"] self.jsondict['alive_peak'] = self.config["ALIVE_SETTINGS"]["ALIVE_PEAK"] self.jsondict['alive_leak'] = self.config["ALIVE_SETTINGS"]["ALIVE_LEAK"] self.jsondict['alive_acdc'] = self.config["ALIVE_SETTINGS"]["ALIVE_ACDC"] self.jsondict['alive_baseline'] = self.config["ALIVE_SETTINGS"]["ALIVE_BASELINE"] if (self.params['using_power_supply'] == True): self.jsondict['PS_heating_voltage'] = self.heating_results[0] self.jsondict['PS_heating_current'] = self.heating_results[1] self.jsondict['PS_quad_voltage'] = self.quad_results[0] self.jsondict['PS_quad_current'] = self.quad_results[1] self.jsondict['PS_fpga_voltage'] = self.fpga_results[0] self.jsondict['PS_fpga_current'] = self.fpga_results[1] if ((self.params['temperature'] == "LN") and (self.params['using_power_supply'] == True)): total_cycles = int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_1"]) + int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_2"]) for cycle in range(total_cycles): self.jsondict['PS_heating_voltage_cycle{}'.format(cycle)] = self.power_cycle_heating_results[cycle][0] self.jsondict['PS_heating_current_cycle{}'.format(cycle)] = self.power_cycle_heating_results[cycle][1] self.jsondict['PS_quad_voltage_cycle{}'.format(cycle)] = self.power_cycle_quad_results[cycle][0] self.jsondict['PS_quad_current_cycle{}'.format(cycle)] = self.power_cycle_quad_results[cycle][1] self.jsondict['PS_fpga_voltage_cycle{}'.format(cycle)] = self.power_cycle_fpga_results[cycle][0] self.jsondict['PS_fpga_current_cycle{}'.format(cycle)] = self.power_cycle_fpga_results[cycle][1] for num, i in enumerate(self.params['working_chips']): chip_name = self.params['chip_list'][i][1] jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],self.params["outlabel"], self.config["FILENAMES"]["RESULTS"]) if (self.results[num] == True): self.jsondict['alive_result'] = "PASS" elif (self.results[num] == False): self.jsondict['alive_result'] = "FAIL" else: self.jsondict['alive_result'] = "N/A" #TODO add which channels, cycles, tests, failed self.jsondict['vdda_shunt_voltage'] = self.power_info_total[num][0][0] self.jsondict['vdda_bus_voltage'] = self.power_info_total[num][0][1] self.jsondict['vdda_current'] = self.power_info_total[num][0][2] self.jsondict['vddp_shunt_voltage'] = self.power_info_total[num][1][0] self.jsondict['vddp_bus_voltage'] = self.power_info_total[num][1][1] self.jsondict['vddp_current'] = self.power_info_total[num][1][2] if (self.params['temperature'] == "LN"): total_cycles = int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_1"]) + int(self.config["ALIVE_SETTINGS"]["ALIVE_POWER_CYCLES_2"]) for cycle in range(total_cycles): self.jsondict['vdda_shunt_voltage_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][0][0] self.jsondict['vdda_bus_voltage_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][0][1] self.jsondict['vdda_current_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][0][2] self.jsondict['vddp_shunt_voltage_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][1][0] self.jsondict['vddp_bus_voltage_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][1][1] self.jsondict['vddp_current_cycle{}'.format(cycle)] = self.power_cycle_PCB_power[cycle][num][1][2] with open(jsonFile,'a') as outfile: json.dump(self.jsondict, outfile, indent=4) jsonFile = os.path.join(self.params["datadir"],chip_name,self.params["datasubdir"],self.config["FILENAMES"]["RESULTS"]) with open(jsonFile,'r') as f: existing_json = json.load(f) existing_json['alive_outlabel'] = self.params['outlabel'] with open(jsonFile,'w') as outfile: json.dump(existing_json, outfile, indent=4)
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)
class SYNC_ADCS(object): def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.sync_functions = self.functions.sync self.plotting = self.functions.sync.plot #json output, note module version number defined here self.syncdict = {'type': 'sync_adcs'} self.syncdict['sync_code_version'] = '1.1' self.syncdict['sync_timestamp'] = datetime.datetime.today().strftime( '%Y%m%d%H%M%S') def check_setup(self): print("SYNCHRONIZATION - SETUP") self.functions.initBoard(default_sync=False) if (self.params['using_power_supply'] == True): self.PowerSupply = Power_Supply(self.config) if (self.PowerSupply.interface == None): sys.exit("SYNCHRONIZATION --> Power Supply not found!") def sync(self): print("SYNCHRONIZATION - COLLECT DATA") self.return_results = self.sync_functions.syncADC(**self.params) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_TAGGING"]), int(self.config["DEFINITIONS"]["TAGGING_ON"])) self.low_level.setExternalPulser( val=int( self.config["INITIAL_SETTINGS"]["DEFAULT_EXTERNAL_DAC_VAL"], 16), period=int(self.config["INITIAL_SETTINGS"] ["DEFAULT_EXTERNAL_DAC_TP_PERIOD"]), shift=int(self.config["INITIAL_SETTINGS"] ["DEFAULT_EXTERNAL_DAC_TP_SHIFT"]), enable=True) self.functions.configFeAsic( test_cap="on", base=self.config["SYNC_SETTINGS"]["SYNC_BASELINE"], gain=self.config["SYNC_SETTINGS"]["SYNC_GAIN"], shape=self.config["SYNC_SETTINGS"]["SYNC_PEAK"], monitor_ch=None, buffer=self.config["SYNC_SETTINGS"]["SYNC_BUFFER"], leak=self.config["SYNC_SETTINGS"]["SYNC_LEAK"], monitor_param=None, s16=None, acdc=self.config["SYNC_SETTINGS"]["SYNC_ACDC"], test_dac="test_int", dac_value=int( self.config["SYNC_SETTINGS"]["SYNC_DAC_PEAK_HEIGHT"])) self.functions.writeFE() self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_GND_INTPULSE"])) self.power_info_total = [] for i in self.params['working_chips']: chip_index = self.params['chip_list'][i][0] chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data = self.low_level.get_data_chipX( chip=chip_index, packets=int(self.config["SYNC_SETTINGS"]["SYNC_PACKETS"]), tagged=True) print( "quad_sync_adcs--> Printing internal synchronization plot for Chip {}" .format(chip_name)) sync_int_text = self.config["FILENAMES"]["SYNC_FILE_INT"].format( chip_name) savefig = os.path.join(chip_outpathlabel, sync_int_text) power_info = self.functions.PCB_power_monitor(chips=i) self.power_info_total.append(power_info) self.plotting.plot_chip( data=data, plot_name=savefig, title_name= "Chip {} Internal Sync: Gain = {}/fC, Peaking Time = {}". format(chip_name, self.config["SYNC_SETTINGS"]["SYNC_GAIN"], self.config["SYNC_SETTINGS"]["SYNC_PEAK"]), power=power_info, length=1000) if (self.params['using_power_supply'] == True): pwr = self.config["POWER_SUPPLY"] self.heating_results = self.PowerSupply.measure_params( channel=int(pwr["PS_HEATING_CHN"])) self.quad_results = self.PowerSupply.measure_params( channel=int(pwr["PS_QUAD_CHN"])) self.fpga_results = self.PowerSupply.measure_params( channel=int(pwr["PS_FPGA_CHN"])) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_DACPULSE"])) for i in self.params['working_chips']: chip_index = self.params['chip_list'][i][0] chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data = self.low_level.get_data_chipX( chip=chip_index, packets=int(self.config["SYNC_SETTINGS"]["SYNC_PACKETS"]), tagged=True) print( "quad_sync_adcs--> Printing external synchronization plot for Chip {}" .format(chip_name)) sync_ext_text = self.config["FILENAMES"]["SYNC_FILE_EXT"].format( chip_name) savefig = os.path.join(chip_outpathlabel, sync_ext_text) power_info = self.functions.PCB_power_monitor(chips=i) self.plotting.plot_chip( data=data, plot_name=savefig, title_name= "Chip {} External Sync: Gain = {}/fC, Peaking Time = {}". format(chip_name, self.config["SYNC_SETTINGS"]["SYNC_GAIN"], self.config["SYNC_SETTINGS"]["SYNC_PEAK"]), power=power_info, length=1000) self.low_level.setExternalPulser(enable=False) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_GND"])) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_TAGGING"]), int(self.config["DEFINITIONS"]["TAGGING_OFF"])) def do_analysis(self, ): print("SYNCHRONIZATION - ANALYZE") self.results = self.params["chip_list"] for num, i in enumerate(range(len(self.results))): if (self.return_results[num] == True): self.results[i].append("PASS") elif (self.return_results[num] == False): self.results[i].append("FAIL") else: self.results[i].append("NOT TESTED (SPI ERROR)") def archiveResults(self): print("SYNCHRONIZATION - ARCHIVE") self.jsondict = {'boardID': self.params['boardid']} self.jsondict['fw_ver'] = self.params['fw_ver'] self.jsondict['test_category'] = self.params['test_category'] self.jsondict['test_stand'] = self.params['test_stand'] self.jsondict['chipver'] = self.params['chipver'] self.jsondict['sw_version'] = self.params['sw_version'] self.jsondict['fpgamezz'] = self.params['fpgamezz'] self.jsondict['femb_config'] = self.params['femb_config'] self.jsondict['paramfile'] = self.params['paramfile'] self.jsondict['sync_outlabel'] = self.params['outlabel'] for i in self.params['working_chips']: chip_index = self.params['chip_list'][i][0] chip_name = self.params['chip_list'][i][1] jsonFile = os.path.join(self.params["datadir"], chip_name, self.params["datasubdir"], self.config["FILENAMES"]["RESULTS"]) self.jsondict['chip_index'] = chip_index self.jsondict['chip_name'] = chip_name self.jsondict['socket'] = self.params["socket{}id".format( chip_index)] with open(jsonFile, 'a') as outfile: json.dump(self.jsondict, outfile, indent=4) self.syncdict['sync_baseline'] = self.config["SYNC_SETTINGS"][ "SYNC_BASELINE"] self.syncdict['sync_buffer'] = self.config["SYNC_SETTINGS"][ "SYNC_BUFFER"] self.syncdict['sync_gain'] = self.config["SYNC_SETTINGS"]["SYNC_GAIN"] self.syncdict['sync_peak'] = self.config["SYNC_SETTINGS"]["SYNC_PEAK"] self.syncdict['sync_acdc'] = self.config["SYNC_SETTINGS"]["SYNC_ACDC"] self.syncdict['sync_leak'] = self.config["SYNC_SETTINGS"]["SYNC_LEAK"] self.syncdict['sync_executable'] = self.params['executable'] self.syncdict['sync_datasubdir'] = self.params['datasubdir'] if (self.params['using_power_supply'] == True): self.syncdict['PS_heating_voltage'] = self.heating_results[0] self.syncdict['PS_heating_current'] = self.heating_results[1] self.syncdict['PS_quad_voltage'] = self.quad_results[0] self.syncdict['PS_quad_current'] = self.quad_results[1] self.syncdict['PS_fpga_voltage'] = self.fpga_results[0] self.syncdict['PS_fpga_current'] = self.fpga_results[1] for num, i in enumerate(self.params['working_chips']): chip_index = self.params['chip_list'][i][0] chip_name = self.params['chip_list'][i][1] jsonFile = os.path.join(self.params["datadir"], chip_name, self.params["datasubdir"], self.params["outlabel"], self.config["FILENAMES"]["RESULTS"]) self.syncdict['sync_result'] = self.results[chip_index][2] self.syncdict['vdda_shunt_voltage'] = self.power_info_total[num][ 0][0] self.syncdict['vdda_bus_voltage'] = self.power_info_total[num][0][ 1] self.syncdict['vdda_current'] = self.power_info_total[num][0][2] self.syncdict['vddp_shunt_voltage'] = self.power_info_total[num][ 1][0] self.syncdict['vddp_bus_voltage'] = self.power_info_total[num][1][ 1] self.syncdict['vddp_current'] = self.power_info_total[num][1][2] with open(jsonFile, 'a') as outfile: json.dump(self.syncdict, outfile, indent=4)
def __init__(self, master=None, forceQuick=False, forceLong=False): self.use_sumatra = True #Useful to have if we ever want to look back and see what version of femb_python we were using try: repo = git.Repo(__file__, search_parent_directories=True) self.sw_version = repo.head.object.hexsha except: self.sw_version = "Not Found" #It's calling the constructor of the parent tkinter object, the pack method of the class, which is now a tkinter object tk.Frame.__init__(self, master) self.pack() self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.master.title("Quad FE ASIC Test GUI") self.master.protocol("WM_DELETE_WINDOW", lambda arg=self.master: self.on_closing(arg)) self.WF_GUI = None self.analysis = "basic" try: self.PowerSupply = Power_Supply(self.config) except BrokenPipeError: self.PowerSupply = None #Variables that I want to save in the JSON but aren't included in the generic runner self.params = dict(test_category="feasic_quad_cold", sw_version=self.sw_version, use_sumatra=self.use_sumatra) #Look in the root folder for the test name and see if there was a JSON file created with the previous settings #This is used to pre-fill in the fields, much more preferable than putting in the sockets and all that from scratch self.root_dir = getDefaultDirectory() file_name = os.path.join( self.root_dir, self.config["FILENAMES"]["DEFAULT_GUI_FILE_NAME"]) if os.path.isfile(file_name): self.default_settings = dict() with open(file_name, 'r') as f: jsondata = json.load(f) for i in jsondata: self.default_settings[i] = jsondata[i] else: self.default_settings = dict(operator_name="", test_stand="", test_stand_other="", boardid="", boardid_other="", chipver="", chipver_other="", fpgamezz="", fpgamezz_other="", asic0id="", asic1id="", asic2id="", asic3id="", socket0id="", socket1id="", socket2id="", socket3id="") #Define general commands column self.define_test_details_column() #Define general commands column self.define_general_commands_column() return
class GUI_WINDOW(tk.Frame): #GUI window defined entirely in init function def __init__(self, master=None, forceQuick=False, forceLong=False): self.use_sumatra = True #Useful to have if we ever want to look back and see what version of femb_python we were using try: repo = git.Repo(__file__, search_parent_directories=True) self.sw_version = repo.head.object.hexsha except: self.sw_version = "Not Found" #It's calling the constructor of the parent tkinter object, the pack method of the class, which is now a tkinter object tk.Frame.__init__(self, master) self.pack() self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.master.title("Quad FE ASIC Test GUI") self.master.protocol("WM_DELETE_WINDOW", lambda arg=self.master: self.on_closing(arg)) self.WF_GUI = None self.analysis = "basic" try: self.PowerSupply = Power_Supply(self.config) except BrokenPipeError: self.PowerSupply = None #Variables that I want to save in the JSON but aren't included in the generic runner self.params = dict(test_category="feasic_quad_cold", sw_version=self.sw_version, use_sumatra=self.use_sumatra) #Look in the root folder for the test name and see if there was a JSON file created with the previous settings #This is used to pre-fill in the fields, much more preferable than putting in the sockets and all that from scratch self.root_dir = getDefaultDirectory() file_name = os.path.join( self.root_dir, self.config["FILENAMES"]["DEFAULT_GUI_FILE_NAME"]) if os.path.isfile(file_name): self.default_settings = dict() with open(file_name, 'r') as f: jsondata = json.load(f) for i in jsondata: self.default_settings[i] = jsondata[i] else: self.default_settings = dict(operator_name="", test_stand="", test_stand_other="", boardid="", boardid_other="", chipver="", chipver_other="", fpgamezz="", fpgamezz_other="", asic0id="", asic1id="", asic2id="", asic3id="", socket0id="", socket1id="", socket2id="", socket3id="") #Define general commands column self.define_test_details_column() #Define general commands column self.define_general_commands_column() return #For GUI options where there are predefined but have the option for "other" (in case we're testing a new version of something) #Every time a change is made to those fields, this is called to see if "other" was chosen. If it was, it creates a text field to manually write the value #If it's not, it hides that text field def gui_callback(self, *args, **kwargs): #TODO use dictionary map to get this quicker if (args[0] == "test_stand_GUI_variable"): index = 0 elif (args[0] == "boardid_GUI_variable"): index = 1 elif (args[0] == "chipver_GUI_variable"): index = 2 elif (args[0] == "fpgamezz_GUI_variable"): index = 3 if (self.selections[index].get() == "Other"): self.other_entries[index].grid(sticky=tk.W, row=index + 2, column=3) self.others[index] = True else: self.other_entries[index].grid_forget() self.others[index] = False #For fields with predefined values, it gets those values from the config files #There's also a variable to tell if "other" was chosen, so it knows to look at the manual entry field for the value def define_test_details_column(self): columnbase = 1 entry_width = 9 options_width = 5 spinner_width = 8 label_width = 15 self.details_label = tk.Label(self, text="Tests Details") self.details_label.grid(row=0, column=columnbase, columnspan=3) # Adding operator name label and read entry box label = tk.Label(self, text="Operator Name:", width=label_width) label.grid(sticky=tk.W, row=1, column=columnbase + 0) self.operator_entry = tk.Entry(self, width=entry_width) self.operator_entry.insert(tk.END, self.default_settings["operator_name"]) self.operator_entry.grid(sticky=tk.W, row=1, column=columnbase + 1) test_stand = [ "Test Stand #:", "test_stand_GUI_variable", "test_stand", 'KNOWN_TEST_STANDS', self.default_settings["test_stand_other"] ] board_id = [ "Test Board ID:", "boardid_GUI_variable", "boardid", 'KNOWN_QUAD_BOARDS', self.default_settings["boardid_other"] ] chip_ver = [ "Chip Version:", "chipver_GUI_variable", "chipver", 'KNOWN_CHIP_VERSIONS', self.default_settings["chipver_other"] ] fpgamezz = [ "FPGA Board:", "fpgamezz_GUI_variable", "fpgamezz", 'KNOWN_FPGA_MEZZANINES', self.default_settings["fpgamezz_other"] ] self.option_rows = [test_stand, board_id, chip_ver, fpgamezz] self.selections = [] self.entries = [] self.other_entries = [] self.others = [] for num, i in enumerate(self.option_rows): # Adding test stand ID and read entry box label = tk.Label(self, text=i[0], width=label_width) label.grid(sticky=tk.W, row=2 + num, column=columnbase + 0) selection = tk.StringVar(self.master, name=i[1]) selection.set(self.default_settings[i[2]]) # initial value selection.trace("w", self.gui_callback) self.selections.append(selection) options = list(self.config._sections[i[3]].keys()) possible_options = [] for j in range(len(options)): possible_options.append(self.config[i[3]][options[j]]) entry = tk.OptionMenu(self, selection, *possible_options) entry.config(width=options_width) self.entries.append(entry) entry.grid(sticky=tk.W, row=2 + num, column=columnbase + 1) entry_other = tk.Entry(self, width=entry_width) self.other_entries.append(entry_other) if (selection.get() == "Other"): entry_other.insert(tk.END, i[4]) entry_other.grid(sticky=tk.W, row=2 + num, column=3) other = True else: entry_other.grid_forget() other = False self.others.append(other) label = tk.Label(self, text="Chip ID:", width=entry_width) label.grid(sticky=tk.W, row=7, column=columnbase + 1) label = tk.Label(self, text="Socket ID:", width=entry_width) label.grid(sticky=tk.W, row=7, column=columnbase + 2) self.asic_entries = [] self.socket_entries = [] self.asic_enables = [] for i, chip in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): var = tk.BooleanVar(value=True) self.asic_enables.append(var) button = tk.Checkbutton(self, variable=var) button.grid(row=8 + i, column=columnbase - 1) label = tk.Label(self, text="ASIC {}".format(chip), width=label_width) label.grid(sticky=tk.W, row=8 + i, column=columnbase + 0) spinbox = tk.Spinbox(self, width=spinner_width, from_=self.config['GUI_SETTINGS']['CHIP_MIN'], to=self.config['GUI_SETTINGS']['CHIP_MAX']) self.asic_entries.append(spinbox) spinbox.insert(tk.END, self.default_settings["asic{}id".format(chip)]) spinbox.delete(0) spinbox.grid(sticky=tk.W, row=8 + i, column=columnbase + 1) spinbox = tk.Spinbox( self, width=spinner_width, from_=self.config['GUI_SETTINGS']['SOCKET_MIN'], to=self.config['GUI_SETTINGS']['SOCKET_MAX']) self.socket_entries.append(spinbox) spinbox.insert(tk.END, self.default_settings["socket{}id".format(chip)]) spinbox.delete(0) spinbox.grid(sticky=tk.W, row=8 + i, column=columnbase + 2) def define_general_commands_column(self): self.midcolumnbase = 4 self.status_label = tk.Label(self, text="FE ASIC TESTS", width=20) self.status_label.grid(row=0, column=self.midcolumnbase, columnspan=50) #Set up buttons power_on = ["Power On", self.power_on, "green"] power_off = ["Power Off", self.power_off, "red"] test_connection = ["Test Connection", self.test_connection] debug = ["Debug Waveform", self.debug] start = ["Start Cold Tests", self.start_cold_measurements] start_warm = ["Start Warm Tests", self.start_warm_measurements] buttons = [ power_on, power_off, test_connection, debug, start, start_warm ] for num, i in enumerate(buttons): try: button_i = tk.Button(self, text=i[0], bg=i[2], command=i[1], width=10) except IndexError: button_i = tk.Button(self, text=i[0], command=i[1], width=10) button_i.grid(row=1 + num, column=self.midcolumnbase) advanced = tk.Button(self, text="Advanced", command=self.change_analysis_level) advanced.grid(row=3, column=self.midcolumnbase + 1) #Name as appears on GUI, basic or advanced, executible, and name of folder sync_test = ["Sync", "basic", "feasic_quad_sync", "Sync"] baseline_test = [ "Baseline", "basic", "feasic_quad_baseline", "Baseline" ] monitor_test = ["Monitor", "basic", "feasic_quad_monitor", "Monitor"] alive_test = ["Alive", "basic", "feasic_quad_alive", "Alive"] dac_test = ["DAC", "advanced", "feasic_quad_dac", "Internal DAC"] gain_test = ["Pulse", "advanced", "feasic_quad_pulse", "Pulse"] ledge_test = ["Ledge", "advanced", "feasic_quad_ledge", "Ledge"] final_test = ["Final", "basic"] self.all_tests = [ sync_test, baseline_test, monitor_test, alive_test, dac_test, gain_test, ledge_test, final_test ] for num, i in enumerate(self.all_tests): label = tk.Label(self, text=i[0], width=10) i.append(label) var = tk.BooleanVar(value=True) i.append(var) button = tk.Checkbutton(self, variable=var) i.append(button) if (i[1] == "basic"): label.grid(sticky=tk.W, row=7, column=self.midcolumnbase + num + 1) if (i[0] != "Final" and i[0] != "Sync"): button.grid(row=6, column=self.midcolumnbase + num + 1) self.connected_power_supply = ["Connected Power Supply"] self.temperature_cold = ["Cold Test"] self.online_analysis = ["Concurrent Analysis"] self.advanced_options = [ self.connected_power_supply, self.temperature_cold, self.online_analysis ] self.advanced_variables = [] for i in self.advanced_options: label = tk.Label(self, text=i[0], width=20, anchor="w") i.append(label) var = tk.BooleanVar(value=True) self.advanced_variables.append(var) button = tk.Checkbutton(self, variable=var) i.append(button) self.results_array = [] for num, i in enumerate(self.all_tests): test_specific = [] for chips in range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1): label = tk.Label(self, text="----", width=10) if (i[1] == "basic"): label.grid(stick=tk.W, row=8 + chips, column=self.midcolumnbase + num + 1) test_specific.append(label) self.results_array.append(test_specific) #Set up static labels for num, chips in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): label = tk.Label(self, text="ASIC {} Results:".format(chips), width=15) label.grid(sticky=tk.W, row=8 + num, column=self.midcolumnbase + 0) def write_default_file(self): self.params['operator_name'] = self.operator_entry.get() for num, i in enumerate(self.option_rows): using_other = self.others[num] if (using_other == True): self.params[i[2]] = self.other_entries[num].get() else: self.params[i[2]] = self.selections[num].get() #Create that default file self.defaultjson = dict(operator_name=self.operator_entry.get(), test_stand=self.selections[0].get(), test_stand_other=self.other_entries[0].get(), boardid=self.selections[1].get(), boardid_other=self.other_entries[1].get(), chipver=self.selections[2].get(), chipver_other=self.other_entries[2].get(), fpgamezz=self.selections[3].get(), fpgamezz_other=self.other_entries[3].get()) for i, chip in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): self.params['asic{}id'.format(chip)] = self.asic_entries[i].get() self.params['socket{}id'.format( chip)] = self.socket_entries[i].get() self.defaultjson['asic{}id'.format( chip)] = self.asic_entries[i].get() self.defaultjson['socket{}id'.format( chip)] = self.socket_entries[i].get() jsonFile = os.path.join( self.root_dir, self.config["FILENAMES"]["DEFAULT_GUI_FILE_NAME"]) with open(jsonFile, 'w') as outfile: json.dump(self.defaultjson, outfile, indent=4) def start_warm_measurements(self): self.advanced_variables[1].set(value=False) self.start_measurements() def start_cold_measurements(self): self.advanced_variables[1].set(value=True) self.start_measurements() def start_measurements(self): self.write_default_file() self.clear_labels() #Make sure everything was entered ok, that nothing was screwed up gui_check = self.config["GUI_SETTINGS"] asic_tup = [] sock_tup = [] for i, chip in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): asic_tup.append("asic{}id".format(chip)) sock_tup.append("socket{}id".format(chip)) for i in asic_tup: j = self.params[i] if ((int(j) < int(gui_check['CHIP_MIN'])) or (int(j) > int(gui_check['CHIP_MAX']))): print("{}({}) is out of range ({} to {})!".format( i, j, int(gui_check['CHIP_MIN']), int(gui_check['CHIP_MAX']))) self.status_label["text"] = "ENTER REQUIRED INFO" self.update_idletasks() return for i in sock_tup: j = self.params[i] if ((int(j) < int(gui_check['SOCKET_MIN'])) or (int(j) > int(gui_check['SOCKET_MAX']))): print("{}({}) is out of range ({} to {})!".format( i, j, int(gui_check['SOCKET_MIN']), int(gui_check['SOCKET_MAX']))) self.status_label["text"] = "ENTER REQUIRED INFO" self.update_idletasks() return if not (self.params['operator_name'] and self.params['test_stand'] and self.params['boardid'] and self.params['fpgamezz'] and self.params['chipver']): print("ENTER REQUIRED INFO") self.status_label["text"] = "ENTER REQUIRED INFO" self.update_idletasks() return if (self.advanced_variables[0].get() == True): self.params['using_power_supply'] = True self.get_power_supply() if (self.PowerSupply.interface == None): return else: self.power_on() else: self.params['using_power_supply'] = False if (self.advanced_variables[1].get() == True): self.params['temperature'] = "LN" self.get_power_supply() if (self.PowerSupply.interface != None): self.power_on() else: self.params['temperature'] = "RT" fw_ver = self.functions.get_fw_version() self.params['fw_ver'] = hex(fw_ver) if (fw_ver < int(self.config["DEFAULT"]["LATEST_FW"], 16)): messagebox.showinfo( "Warning!", "The FPGA is running firmware version {} when the latest firmware is version {}. Please let an expert know!" .format(hex(fw_ver), hex(int(self.config["DEFAULT"]["LATEST_FW"], 16)))) print("got here") self.functions.turnOnAsics() self.functions.resetBoard() responding_chips = self.functions.initBoard() self.chiplist = [] working_chips = [] for i, chip in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): tup = [i, self.params["asic{}id".format(chip)]] self.chiplist.append(tup) if (self.asic_enables[i].get() == True): if chip in (responding_chips): working_chips.append(chip) self.params['working_chips'] = working_chips tests_to_do = [] if (self.params['temperature'] == "LN"): for i in self.all_tests: if (i[0] != "Final"): if ((i[1] == "basic") and (i[5].get() == True)): tests_to_do.append([i[2], i[3]]) elif (self.analysis == "advanced" and i[1] == "advanced" and i[5].get() == True): tests_to_do.append([i[2], i[3]]) else: sync = self.all_tests[0] tests_to_do.append([sync[2], sync[3]]) alive = self.all_tests[3] tests_to_do.append([alive[2], alive[3]]) self.params['tests_to_do'] = tests_to_do start_time = time.time() self.now = time.strftime("%Y%m%dT%H%M%S", time.localtime(time.time())) print("BEGIN TESTS") self.params.update(chip_list=self.chiplist) self.update_idletasks() params = None #Calls the new generic tester/runner. Note that this is done in a for loop and the generic tester passes values back by using "Yield" #This is the only way I figured out how to get feedback back to the GUI mid-test without changing too much for i in (maintest(**self.params)): self.postResults(i) self.update_idletasks() params = i for i in self.working_chips: chip_name = self.chip_list[i][1] results_file = os.path.join(self.datadir, chip_name, "results.json") with open(results_file, 'r') as f: results = json.load(f) ver = {'verified': False} with open(results_file, 'w') as outfile: results.update(ver) json.dump(results, outfile, indent=4) self.postResults(params) end_time = time.time() self.status_label = "DONE" self.update_idletasks() response = CustomDialog(self, power_supply=self.advanced_variables[0].get(), PS=self.PowerSupply).show() for i in self.working_chips: chip_name = self.chip_list[i][1] results_file = os.path.join(self.datadir, chip_name, "results.json") with open(results_file, 'r') as f: results = json.load(f) ver = {'verified': str(response[i])} with open(results_file, 'w') as outfile: results.update(ver) json.dump(results, outfile, indent=4) run_time = end_time - start_time print("Total run time: {}".format(int(run_time))) self.functions.turnOffAsics() print(self.GetTimeString(int(run_time))) if (self.params['using_power_supply'] == True): self.power_off(channels=[2, 3]) def change_analysis_level(self): if (self.analysis == "basic"): self.analysis = "advanced" for num, i in enumerate(self.all_tests): if (i[1] == "advanced"): label = i[4] label.grid(sticky=tk.W, row=7, column=self.midcolumnbase + num + 1) button = i[6] button.grid(row=6, column=self.midcolumnbase + num + 1) for chips in range( int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1): label = self.results_array[num][chips] label.grid(stick=tk.W, row=8 + chips, column=self.midcolumnbase + num + 1) for num, i in enumerate(self.advanced_options): button = i[2] button.grid(row=1 + num, column=self.midcolumnbase + 2) label = i[1] label.grid(row=1 + num, column=self.midcolumnbase + 3, columnspan=3) elif (self.analysis == "advanced"): self.analysis = "basic" for num, i in enumerate(self.all_tests): if (i[1] == "advanced"): label = i[4] label.grid_forget() button = i[6] button.grid_forget() for chips in range( int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1): label = self.results_array[num][chips] label.grid_forget() for num, i in enumerate(self.advanced_options): button = i[2] button.grid_forget() label = i[1] label.grid_forget() else: print( "GUI_ERROR --> Analysis level should only ever be 'basic' or 'advanced', it was {}" .format(self.analysis)) def power_on(self): self.on_child_closing() self.PowerSupply = self.get_power_supply() if (self.PowerSupply != None): pwr = self.config["POWER_SUPPLY"] self.PowerSupply.on(channels=[ int(pwr["PS_HEATING_CHN"]), int(pwr["PS_QUAD_CHN"]), int(pwr["PS_FPGA_CHN"]) ]) self.update_idletasks() # self.power_button["bg"]="green" def power_off(self, channels=[1, 2, 3]): self.on_child_closing() self.PowerSupply = self.get_power_supply() if (self.PowerSupply.interface != None): self.PowerSupply.off(channels=channels) self.update_idletasks() # self.power_button["bg"]="green" def test_connection(self): #TODO if not on already, turn on and wait self.on_child_closing() self.write_default_file() self.power_on() fw_ver = self.functions.get_fw_version() self.params['fw_ver'] = hex(fw_ver) if (fw_ver < int(self.config["DEFAULT"]["LATEST_FW"], 16)): messagebox.showinfo( "Warning!", "The FPGA is running firmware version {} when the latest firmware is version {}. Please let an expert know!" .format(hex(fw_ver), hex(int(self.config["DEFAULT"]["LATEST_FW"], 16)))) self.functions.turnOnAsics() self.functions.resetBoard() SPI_response = self.functions.initBoard() temp_sync_folder = os.path.join(self.root_dir, "temp_sync_files") if not os.path.exists(temp_sync_folder): os.makedirs(temp_sync_folder) for thing in os.listdir(temp_sync_folder): file_path = os.path.join(temp_sync_folder, thing) try: if (os.path.isfile(file_path)): os.unlink(file_path) if (os.path.isdir(file_path)): shutil.rmtree(file_path) except Exception as e: print(e) chiplist = [] for i, chip in enumerate( range(int(self.config["DEFAULT"]["NASIC_MIN"]), int(self.config["DEFAULT"]["NASIC_MAX"]) + 1, 1)): tup = [i, self.params["asic{}id".format(chip)]] chiplist.append(tup) self.functions.syncADC(datadir=temp_sync_folder, working_chips=SPI_response, chip_list=chiplist, to_print=True) self.WF_GUI = tk.Tk() self.WF_GUI.protocol("WM_DELETE_WINDOW", self.on_child_closing) startWF(self.WF_GUI) def debug(self): self.WF_GUI = tk.Tk() self.WF_GUI.protocol("WM_DELETE_WINDOW", self.on_child_closing) startWF(self.WF_GUI) def postResults(self, params): self.datadir = params['datadir'] self.working_chips = params['working_chips'] self.chip_list = params['chip_list'] #just gets the first "results.json" from the first working chip, just to get the main test paramfile json location chip_name = self.chip_list[self.working_chips[0]][1] results_path = os.path.join(self.datadir, chip_name) jsonFile_chip = os.path.join(results_path, self.config["FILENAMES"]["RESULTS"]) with open(jsonFile_chip, 'r') as f: test_list = json.load(f) paramfile = test_list["paramfile"] with open(paramfile, 'r') as f: param_json = json.load(f) #Now we have the json and can add to it during the loop for i in self.working_chips: chip_name = self.chip_list[i][1] results_path = os.path.join(self.datadir, chip_name) jsonFile_chip = os.path.join(results_path, self.config["FILENAMES"]["RESULTS"]) #Now that we know what the timestamped directory is, we can have a button on the GUI open it directly self.details_label.bind( "<Button-1>", lambda event, arg=self.datadir: self.open_directory(arg)) with open(jsonFile_chip, 'r') as f: test_list = json.load(f) overall_result = True if "sync_outlabel" in test_list: outlabel = test_list["sync_outlabel"] jsonFile = os.path.join(results_path, outlabel, self.config["FILENAMES"]["RESULTS"]) with open(jsonFile, 'r') as f: results = json.load(f) label = self.results_array[0][i] result = results['sync_result'] test_list["sync_result"] = result if (result == "FAIL"): bool_result = False else: bool_result = True overall_result = overall_result and bool_result param_json["sync_result_{}".format(i)] = result self.update_label(label, result) linked_folder = os.path.join(results_path, outlabel) linked_file1 = self.config["FILENAMES"]["SYNC_LINK"].format( chip_name) linked_file2 = self.config["FILENAMES"][ "SYNC_LINK_MONITOR"].format(chip_name) linked_file_path1 = os.path.join(linked_folder, linked_file1) linked_file_path2 = os.path.join(linked_folder, linked_file2) label.bind( "<Button-1>", lambda event, arg=linked_file_path1: self.link_label(arg)) label.bind( "<Button-3>", lambda event, arg=linked_file_path2: self.link_label(arg)) if "baseline_outlabel" in test_list: outlabel = test_list["baseline_outlabel"] jsonFile = os.path.join(results_path, outlabel, self.config["FILENAMES"]["RESULTS"]) with open(jsonFile, 'r') as f: results = json.load(f) label = self.results_array[1][i] result = results['baseline_result'] test_list["baseline_result"] = result if (result == "FAIL"): bool_result = False else: bool_result = True overall_result = overall_result and bool_result param_json["baseline_result_{}".format(i)] = result self.update_label(label, result) linked_folder = os.path.join(results_path, outlabel) linked_file = self.config["FILENAMES"]["BASELINE_LINK"].format( chip_name) linked_file_path = os.path.join(linked_folder, linked_file) label.bind( "<Button-1>", lambda event, arg=linked_file_path: self.link_label(arg)) if "monitor_outlabel" in test_list: outlabel = test_list["monitor_outlabel"] jsonFile = os.path.join(results_path, outlabel, self.config["FILENAMES"]["RESULTS"]) with open(jsonFile, 'r') as f: results = json.load(f) label = self.results_array[2][i] result = results['monitor_result'] test_list["monitor_result"] = result if (result == "FAIL"): bool_result = False else: bool_result = True overall_result = overall_result and bool_result param_json["monitor_result_{}".format(i)] = result self.update_label(label, result) linked_folder = os.path.join(results_path, outlabel) linked_file = self.config["FILENAMES"]["MONITOR_LINK"].format( chip_name) linked_file_path = os.path.join(linked_folder, linked_file) label.bind( "<Button-1>", lambda event, arg=linked_file_path: self.link_label(arg)) if "alive_outlabel" in test_list: outlabel = test_list["alive_outlabel"] jsonFile = os.path.join(results_path, outlabel, self.config["FILENAMES"]["RESULTS"]) with open(jsonFile, 'r') as f: results = json.load(f) label = self.results_array[3][i] result = results['alive_result'] test_list["alive_result"] = result if (result == "FAIL"): bool_result = False else: bool_result = True overall_result = overall_result and bool_result param_json["alive_result_{}".format(i)] = result self.update_label(label, result) linked_folder = os.path.join(results_path, outlabel) linked_file = self.config["FILENAMES"]["ALIVE_LINK"].format( chip_name) linked_file_path = os.path.join(linked_folder, linked_file) label.bind( "<Button-1>", lambda event, arg=linked_file_path: self.link_label(arg)) if "verified" in test_list: if (overall_result): overall_result_string = "PASS" else: overall_result_string = "FAIL" param_json["overall_result_{}".format( i)] = overall_result_string label = self.results_array[7][i] self.update_label(label, overall_result_string) with open(jsonFile_chip, 'w') as outfile: json.dump(test_list, outfile, indent=4) with open(paramfile, 'w') as outfile: json.dump(param_json, outfile, indent=4) def clear_labels(self): for i in range(8): for j in range(4): label = self.results_array[i][j] label["text"] = "----" label["fg"] = "black" def update_label(self, label, result): if (result == "PASS"): label["text"] = "Pass" label["fg"] = "green" elif (result == "FAIL"): label["text"] = "Fail" label["fg"] = "red" else: print( "Top_Level_GUI--> Incorrect result, must 'PASS' or 'FAIL', was {}" .format(result)) def link_label(self, file): #eog is so it opens in the superior Image Viewer without all the junk in Image Magick subprocess.check_call(["eog", file]) def open_directory(self, directory): #xdg-open is so it opens the directory as is subprocess.check_call(["xdg-open", directory]) # Can add additional testing sequences like as above with a method name # like "do_<semantic_label>". def GetTimeString(self, t): sec = timedelta(seconds=t) d = datetime(1, 1, 1) + sec time_str = "{}:{}:{}".format(d.hour, d.minute, d.second) return time_str def on_closing(self, window): self.on_child_closing() window.destroy() window.quit() def on_child_closing(self): if (self.WF_GUI != None): self.WF_GUI.destroy() #self.WF_GUI.quit() self.WF_GUI = None def get_power_supply(self): if (self.advanced_variables[0].get() == True): if (self.PowerSupply.interface != None): self.set_supply_params() return (self.PowerSupply) else: self.PowerSupply = Power_Supply(self.config) if (self.PowerSupply.interface == None): messagebox.showinfo( "Warning!", "No power supply device was detected! Plug in the power supply and try again! " + "If you want to run the test without the power supply connected, uncheck the box in 'Advanced Options', make sure to turn the power " + "on when testing at room temperature, off while cooling down, and on again when doing the cold test." ) return (self.PowerSupply) else: self.set_supply_params() return (self.PowerSupply) else: print("Top Level GUI --> Not using Power Supply") def set_supply_params(self): pwr = self.config["POWER_SUPPLY"] self.PowerSupply.set_channel(channel=int(pwr["PS_HEATING_CHN"]), voltage=float(pwr["PS_HEATING_V"]), v_limit=float(pwr["PS_HEATING_V_LIMIT"]), c_limit=float(pwr["PS_HEATING_I_LIMIT"]), vp=pwr["PS_HEATING_V_PROTECTION"], cp=pwr["PS_HEATING_I_PROTECTION"]) self.PowerSupply.set_channel(channel=int(pwr["PS_QUAD_CHN"]), voltage=float(pwr["PS_QUAD_V"]), v_limit=float(pwr["PS_QUAD_V_LIMIT"]), c_limit=float(pwr["PS_QUAD_I_LIMIT"]), vp=pwr["PS_QUAD_V_PROTECTION"], cp=pwr["PS_QUAD_I_PROTECTION"]) self.PowerSupply.set_channel(channel=int(pwr["PS_FPGA_CHN"]), voltage=float(pwr["PS_FPGA_V"]), v_limit=float(pwr["PS_FPGA_V_LIMIT"]), c_limit=float(pwr["PS_FPGA_I_LIMIT"]), vp=pwr["PS_FPGA_V_PROTECTION"], cp=pwr["PS_FPGA_I_PROTECTION"]) self.PowerSupply.on(channels=[ int(pwr["PS_HEATING_CHN"]), int(pwr["PS_QUAD_CHN"]), int(pwr["PS_FPGA_CHN"]) ])
class BASELINE_TESTER(object): def __init__(self): self.config = CONFIG self.functions = FEMB_CONFIG_BASE(self.config) self.low_level = self.functions.lower_functions self.analyze = Data_Analysis(self.config) #json output, note module version number defined here self.jsondict = {'type': 'baseline_test'} self.jsondict['baseline_code_version'] = '1.1' self.jsondict['baseline_timestamp'] = datetime.datetime.today( ).strftime('%Y%m%d%H%M%S') def check_setup(self): print("BASELINE - SETUP") self.functions.initBoard(default_sync=False) if (self.params['using_power_supply'] == True): self.PowerSupply = Power_Supply(self.config) if (self.PowerSupply.interface == None): sys.exit("SYNCHRONIZATION --> Power Supply not found!") def record_data(self): print("BASELINE - COLLECT DATA") self.power_info_total = [] for i in self.params['working_chips']: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join( chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) os.makedirs(data_directory, exist_ok=True) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_MUX_MODE"]), int(self.config["DEFINITIONS"]["MUX_GND_GND"])) self.gain = self.config["BASELINE_SETTINGS"]["BASELINE_GAIN"] self.shape = self.config["BASELINE_SETTINGS"]["BASELINE_PEAK"] self.leak = self.config["BASELINE_SETTINGS"]["BASELINE_LEAK"] self.buff = self.config["BASELINE_SETTINGS"]["BASELINE_BUFFER"] if (self.buff == "on"): self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_SAMPLESPEED"]), int(self.config["INITIAL_SETTINGS"] ["DEFAULT_SAMPLE_SPEED"])) elif (self.buff == "off"): self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_SAMPLESPEED"]), int(self.config["INITIAL_SETTINGS"] ["UNBUFFERED_SAMPLE_SPEED"])) else: print( "FE_baseline_test --> buffer is not defined. Should be 'on' or 'off', but is {}" .format(self.buff)) for base in ["200mV", "900mV"]: self.functions.configFeAsic(test_cap="off", base=base, gain=self.gain, shape=self.shape, monitor_ch=None, buffer=self.buff, leak=self.leak, monitor_param=None, s16=None, acdc="dc", test_dac="test_off", dac_value=0) self.functions.writeFE() for chn in range( int(self.config["DEFAULT"]["NASICCH_MIN"]), int(self.config["DEFAULT"]["NASICCH_MAX"]) + 1, 1): self.low_level.selectChipChannel(chip=i, chn=chn) baseline_file_notation = self.config["FILENAMES"][ "BASELINE_NAMING"] filename = baseline_file_notation.format( chn, self.gain, self.shape, self.leak, base, self.buff) full_filename = os.path.join(data_directory, filename) packets = int( self.config["BASELINE_SETTINGS"]["BASELINE_PACKETS"]) rawdata = self.low_level.get_data_chipXchnX( chip=i, chn=chn, packets=packets, data_format="bin", header=False) with open(full_filename, "wb") as f: f.write(rawdata) f.close() power_info = self.functions.PCB_power_monitor(chips=i) self.power_info_total.append(power_info) if (self.params['using_power_supply'] == True): pwr = self.config["POWER_SUPPLY"] self.heating_results = self.PowerSupply.measure_params( channel=int(pwr["PS_HEATING_CHN"])) self.quad_results = self.PowerSupply.measure_params( channel=int(pwr["PS_QUAD_CHN"])) self.fpga_results = self.PowerSupply.measure_params( channel=int(pwr["PS_FPGA_CHN"])) self.low_level.femb_udp.write_reg( int(self.config["REGISTERS"]["REG_SAMPLESPEED"]), int(self.config["INITIAL_SETTINGS"]["DEFAULT_SAMPLE_SPEED"])) def do_analysis(self): print("BASELINE - ANALYZE") analysis = ["mean"] self.results = [] self.average_baseline_200 = [] self.average_baseline_900 = [] self.baseline_200 = [] self.baseline_900 = [] for i in self.params["working_chips"]: chip_name = self.params['chip_list'][i][1] chip_outpathlabel = os.path.join(self.params["datadir"], chip_name, self.params["outlabel"]) data_directory = os.path.join( chip_outpathlabel, self.config["FILENAMES"]["DATA_NAME"]) result, average_200, average_900, baselines_200, baselines_900 = self.analyze.baseline_directory( chip_outpathlabel, data_directory, chip_name, i, analysis) self.results.append(result) self.average_baseline_200.append(average_200) self.average_baseline_900.append(average_900) self.baseline_200.append(baselines_200) self.baseline_900.append(baselines_900) def archiveResults(self): print("BASELINE - ARCHIVE") self.jsondict['baseline_executable'] = self.params['executable'] self.jsondict['baseline_datasubdir'] = self.params['datasubdir'] self.jsondict['baseline_outlabel'] = self.params['outlabel'] self.jsondict['baseline_gain'] = self.config["BASELINE_SETTINGS"][ "BASELINE_GAIN"] self.jsondict['baseline_peak'] = self.config["BASELINE_SETTINGS"][ "BASELINE_PEAK"] self.jsondict['baseline_leak'] = self.config["BASELINE_SETTINGS"][ "BASELINE_LEAK"] self.jsondict['baseline_buffer'] = self.config["BASELINE_SETTINGS"][ "BASELINE_BUFFER"] if (self.params['using_power_supply'] == True): self.jsondict['PS_heating_voltage'] = self.heating_results[0] self.jsondict['PS_heating_current'] = self.heating_results[1] self.jsondict['PS_quad_voltage'] = self.quad_results[0] self.jsondict['PS_quad_current'] = self.quad_results[1] self.jsondict['PS_fpga_voltage'] = self.fpga_results[0] self.jsondict['PS_fpga_current'] = self.fpga_results[1] for num, i in enumerate(self.params['working_chips']): chip_name = self.params['chip_list'][i][1] jsonFile = os.path.join(self.params["datadir"], chip_name, self.params["datasubdir"], self.params["outlabel"], self.config["FILENAMES"]["RESULTS"]) if (self.results[num] == True): self.jsondict['baseline_result'] = "PASS" elif (self.results[num] == False): self.jsondict['baseline_result'] = "FAIL" else: self.jsondict['baseline_result'] = "N/A" self.jsondict['baseline_200_average'] = self.average_baseline_200[ num] self.jsondict['baseline_900_average'] = self.average_baseline_900[ num] self.jsondict['vdda_shunt_voltage'] = self.power_info_total[num][ 0][0] self.jsondict['vdda_bus_voltage'] = self.power_info_total[num][0][ 1] self.jsondict['vdda_current'] = self.power_info_total[num][0][2] self.jsondict['vddp_shunt_voltage'] = self.power_info_total[num][ 1][0] self.jsondict['vddp_bus_voltage'] = self.power_info_total[num][1][ 1] self.jsondict['vddp_current'] = self.power_info_total[num][1][2] for chn in range(int(self.config["DEFAULT"]["NASICCH_MIN"]), int(self.config["DEFAULT"]["NASICCH_MAX"]) + 1, 1): jsname = "baseline_200_channel{}".format(chn) self.jsondict[jsname] = self.baseline_200[num][chn] jsname = "baseline_900_channel{}".format(chn) self.jsondict[jsname] = self.baseline_900[num][chn] with open(jsonFile, 'a') as outfile: json.dump(self.jsondict, outfile, indent=4) jsonFile = os.path.join(self.params["datadir"], chip_name, self.params["datasubdir"], self.config["FILENAMES"]["RESULTS"]) with open(jsonFile, 'r') as f: existing_json = json.load(f) existing_json['baseline_outlabel'] = self.params['outlabel'] with open(jsonFile, 'w') as outfile: json.dump(existing_json, outfile, indent=4)