diff --git a/Gui/QtGUIutils/QtApplication.py b/Gui/QtGUIutils/QtApplication.py index c626287..7cb1a12 100644 --- a/Gui/QtGUIutils/QtApplication.py +++ b/Gui/QtGUIutils/QtApplication.py @@ -4,6 +4,7 @@ from PyQt5.QtWidgets import ( QApplication, QCheckBox, + QSpinBox, QComboBox, QDialog, QGridLayout, @@ -48,6 +49,8 @@ from Gui.python.SimplifiedMainWidget import SimplifiedMainWidget # from icicle.icicle.instrument_cluster import BadStatusForOperationError, InstrumentCluster from icicle.icicle.instrument_cluster import InstrumentCluster +from icicle.icicle.f4t_temperature_chamber import F4TTempChamber + @@ -761,6 +764,38 @@ def createMain(self): self.ReviewModuleEdit.setEchoMode(QLineEdit.Normal) self.ReviewModuleEdit.setPlaceholderText("Enter Module ID") + self.ThermalTestButton = QPushButton("&Thermal Test") + self.ThermalTestButton.setEnabled(True) + self.AbortThermalTestButton = QPushButton("&Abort thermal test") + self.AbortThermalTestButton.setEnabled(True) + + # To avoid people trying to push the button without a configured + # chamber, check if the resource is defined in siteConfig first. + # Maybe catching an error isn't the prettiest way to do this + # If it is not, disable the button + try: + site_settings.temp_chamber_resource + except AttributeError: + self.ThermalTestButton.setEnabled(False) + self.AbortThermalTestButton.setEnabled(False) + + + self.AbortThermalTestButton.setMinimumWidth(kMinimumWidth) + self.AbortThermalTestButton.setMaximumWidth(kMaximumWidth) + self.AbortThermalTestButton.setMinimumHeight(kMinimumHeight) + self.AbortThermalTestButton.setMaximumHeight(kMaximumHeight) + self.AbortThermalTestButton.clicked.connect(self.abortThermalTest) + + self.ThermalTestButton.setMinimumWidth(kMinimumWidth) + self.ThermalTestButton.setMaximumWidth(kMaximumWidth) + self.ThermalTestButton.setMinimumHeight(kMinimumHeight) + self.ThermalTestButton.setMaximumHeight(kMaximumHeight) + self.ThermalTestButton.clicked.connect(self.runThermalTest) + + self.ThermalProfileEdit = QLineEdit("") + self.ThermalProfileEdit.setEchoMode(QLineEdit.Normal) + self.ThermalProfileEdit.setPlaceholderText("Enter Profile Number") + self.PeltierCooling = Peltier(100) self.PeltierBox = QGroupBox("Peltier Controller", self) self.PeltierLayout = QGridLayout() @@ -778,11 +813,16 @@ def createMain(self): layout.addWidget(ReviewLabel, 2, 1, 1, 2) layout.addWidget(self.ReviewModuleButton, 3, 0, 1, 1) layout.addWidget(self.ReviewModuleEdit, 3, 1, 1, 2) + self.ChillerOption = QGroupBox("Chiller", self) self.ChillerLayout = QGridLayout() self.ChillerOption.setLayout(self.ChillerLayout) + layout.addWidget(self.ThermalTestButton, 4, 0, 1, 1) + layout.addWidget(self.ThermalProfileEdit, 4, 1, 1, 1) + layout.addWidget(self.AbortThermalTestButton, 5, 0, 1, 1) + #################################################### # Functions for expert mode #################################################### @@ -1039,6 +1079,57 @@ def destroyMain(self): self.mainLayout.removeWidget(self.LogoGroupBox) QApplication.closeAllWindows() + def abortThermalTest(self): + """Stop the current profile running on thermal chamber""" + temp_chamber = F4TTempChamber(resource = site_settings.temp_chamber_resource) + with temp_chamber: + temp_chamber.set('CONTROL_PROFILE', 'STOP') + message_box = QMessageBox() + message_box.setText("Profile Aborted") + message_box.setStandardButtons(QMessageBox.Ok) + message_box.exec() + + def runThermalTest(self): + # Verify input of input data: + profile_number = self.ThermalProfileEdit.text() + + # Check if this value is an int + try: + profile_number = int(profile_number) + except ValueError: + QMessageBox.information( + None, "Error", "Please enter a valid profile number" + ". It must be an integer", QMessageBox.Ok + ) + return + # Import icicle module for temperature chamber + print(site_settings.temp_chamber_resource) + temp_chamber = F4TTempChamber(resource = site_settings.temp_chamber_resource) + + # + with temp_chamber: + temp_chamber.set('SELECT_PROFILE', profile_number) + profile_name = temp_chamber.query('SELECT_PROFILE') + + message_box = QMessageBox() + message_box.setText("Temperature chamber" + f"profile \"{profile_name}\" has been chosen") + message_box.setInformativeText("Is this the correct profile?") + message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) + message_box.setDefaultButton(QMessageBox.Yes) + response = message_box.exec() + + if response == QMessageBox.Yes: + with temp_chamber: + temp_chamber.set('CONTROL_PROFILE', 'START') + + if response == QMessageBox.No: + return + + + + + def openNewProductionTest(self): self.ProdTestPage = QtProductionTestWindow( self, instrumentCluster=self.instruments diff --git a/Gui/QtGUIutils/QtRunWindow.py b/Gui/QtGUIutils/QtRunWindow.py index 376a3b9..2a52187 100644 --- a/Gui/QtGUIutils/QtRunWindow.py +++ b/Gui/QtGUIutils/QtRunWindow.py @@ -22,6 +22,7 @@ import threading import time import logging +import Gui.siteSettings as site_settings from Gui.GUIutils.DBConnection import checkDBConnection from Gui.GUIutils.guiUtils import isActive, isCompositeTest @@ -66,12 +67,13 @@ def __init__(self, master, info, firmware): # Add TestProcedureHandler self.testHandler = TestHandler(self, master, info, firmware) - assert self.master.instruments is not None, logger.error("Unable to setup instruments") - self.testHandler.powerSignal.connect( - lambda: self.master.instruments.off( - hv_delay=0.3, hv_step_size=10, measure=False + if not site_settings.manual_powersupply_control: + assert self.master.instruments is not None, logger.error("Unable to setup instruments") + self.testHandler.powerSignal.connect( + lambda: self.master.instruments.off( + hv_delay=0.3, hv_step_size=10, measure=False + ) ) - ) self.GroupBoxSeg = [1, 10, 1] self.HorizontalSeg = [3, 5] diff --git a/Gui/jsonFiles/instruments_osu_relayboxsldo.json b/Gui/jsonFiles/instruments_osu_relayboxsldo.json index dea8a3a..44d63bc 100644 --- a/Gui/jsonFiles/instruments_osu_relayboxsldo.json +++ b/Gui/jsonFiles/instruments_osu_relayboxsldo.json @@ -23,7 +23,7 @@ }, "relay_board": { "class": "RelayBoard", - "resource": "ASRL/dev/ttyUSB0::INSTR", + "resource": "ASRL/dev/ttyUSB3::INSTR", "sim": false, "default_voltage": 0, "default_current": 0 diff --git a/Gui/python/CentralDBInterface.py b/Gui/python/CentralDBInterface.py index b996d1e..9eaeee3 100644 --- a/Gui/python/CentralDBInterface.py +++ b/Gui/python/CentralDBInterface.py @@ -2,7 +2,7 @@ def ExtractChipData(chipserial): #sqlcommand = f"select c.PART_NAME_LABEL, c.VDDA_TRIM_CODE, c.VDDD_TRIM_CODE, c.EFUSE_CODE from trker_cmsr.c18220 c where c.PART_NAME_LABEL = '{chipserial}'" #example of chipserial is N61F26_16E6_45 - command = f'''python rhapi.py -nx -u https://cmsdca.cern.ch/trk_rhapi "select c.PART_NAME_LABEL, c.VDDA_TRIM_CODE, c.VDDD_TRIM_CODE, c.EFUSE_CODE from trker_cmsr.c13420 c where c.PART_NAME_LABEL like '%{chipserial}%'"''' + command = f'''python rhapi.py -nx -u https://cmsdca.cern.ch/trk_rhapi1 "select c.PART_NAME_LABEL, c.VDDA_TRIM_CODE, c.VDDD_TRIM_CODE, c.EFUSE_CODE from trker_cmsr.c13420 c where c.PART_NAME_LABEL like '%{chipserial}%'"''' #chipdata = os.popen(command).read() chipdataoutput = os.popen(command).read() chipdataoutput = chipdataoutput.split('\n') diff --git a/Gui/python/SLDOScanHandler.py b/Gui/python/SLDOScanHandler.py index e09ecab..d72f3ab 100644 --- a/Gui/python/SLDOScanHandler.py +++ b/Gui/python/SLDOScanHandler.py @@ -43,7 +43,7 @@ def __init__( self.moduleType = moduleType self.PIN_MAPPINGS = { 'DEFAULT': AdcBoard.DEFAULT_PIN_MAP, - 'CROC 1x2': { + 'DOUBLE': { # 0: 'VDDA_ROC2', # 1: 'VDDA_ROC3', # 2: 'VDDD_ROC2', @@ -62,7 +62,7 @@ def __init__( # 15: 'TP7A', #VOFS OUT # 16: 'TP7B', #VOFS OUT }, - 'CROC Quad': { + 'QUAD': { 0: 'VDDA_ROC2', 1: 'VDDA_ROC3', 2: 'VDDD_ROC2', @@ -147,7 +147,7 @@ def runWithADC(self) -> None: Currents_Down = [res[5] for res in data_down] - for index, pin in self.PIN_MAPPINGS[self.moduleType].items(): + for index, pin in self.PIN_MAPPINGS[self.moduleType.split(" ")[-1].replace("1x2","DOUBLE").upper()].items(): ADC_Voltage_Up = [res[6][index] for res in data_up] result_up = np.array([Currents_Up, LV_Voltage_Up, ADC_Voltage_Up]) @@ -180,7 +180,7 @@ def runWithRelayDMM(self) -> None: self.instruments.lv_off() self.multimeter.set("SYSTEM_MODE","REM") logger.info('turned off the lv and hv') - for key in self.relayboard.PIN_MAP[self.moduleType].keys(): + for key in self.relayboard.PIN_MAP[self.moduleType.split(" ")[-1].replace("1x2","DOUBLE").upper()].keys(): if "VDD" in key: self.pin_list.append(key) print('adding {0} to pin_list'.format(key)) @@ -204,7 +204,6 @@ def runWithRelayDMM(self) -> None: measure_args={}, set_property="current", ) - self.determineLVIndex(results) results = results[self.LV_index][1] diff --git a/Gui/python/SimplifiedMainWidget.py b/Gui/python/SimplifiedMainWidget.py index cb50e08..e27aab8 100644 --- a/Gui/python/SimplifiedMainWidget.py +++ b/Gui/python/SimplifiedMainWidget.py @@ -217,11 +217,11 @@ def setupUI(self): self.StartLayout = QHBoxLayout() self.TestGroup = QGroupBox() self.TestGroupLayout = QVBoxLayout() - self.ProductionButton = QRadioButton("&Full Test") - self.QuickButton = QRadioButton("&Quick Test") - self.QuickButton.setChecked(True) - self.TestGroupLayout.addWidget(self.QuickButton) - self.TestGroupLayout.addWidget(self.ProductionButton) + self.FunctionTestButton = QRadioButton("&Functional Test") + self.AssemblyTestButton = QRadioButton("&Assembly QC Test") + self.AssemblyTestButton.setChecked(True) + self.TestGroupLayout.addWidget(self.AssemblyTestButton) + self.TestGroupLayout.addWidget(self.FunctionTestButton) self.TestGroup.setLayout(self.TestGroupLayout) logger.debug("Added Boxes/Layouts to Simplified GUI") @@ -352,10 +352,10 @@ def runNewTest(self): ) return - if self.ProductionButton.isChecked(): - self.info = "ROCTune" - else: - self.info = "QuickTest" + if self.FunctionTestButton.isChecked(): + self.info = "TFPX_Functional_Test" + elif self.AssemblyTestButton.isChecked(): + self.info = "TFPX_Assembly_QC" self.runFlag = True self.RunTest = QtRunWindow(self.master, self.info, self.firmwareDescription) self.RunButton.setDisabled(True) diff --git a/Gui/python/TestHandler.py b/Gui/python/TestHandler.py index 894f774..7f21df7 100644 --- a/Gui/python/TestHandler.py +++ b/Gui/python/TestHandler.py @@ -462,14 +462,22 @@ def runSingleTest(self, testName): self.info_process.setWorkingDirectory( os.environ.get("PH2ACF_BASE_DIR") + "/test/" ) - self.info_process.start( - "echo", - [ - "Running COMMAND: CMSITminiDAQ -f CMSIT.xml -c {}".format( - Test_to_Ph2ACF_Map[self.currentTest] - ) - ], - ) + if self.currentTest == "CommunicationTest": + self.info_process.start( + "echo", + [ + "Running COMMAND: CMSITminiDAQ -f CMSIT.xml -p" + ], + ) + else: + self.info_process.start( + "echo", + [ + "Running COMMAND: CMSITminiDAQ -f CMSIT.xml -c {}".format( + Test_to_Ph2ACF_Map[self.currentTest] + ) + ], + ) self.info_process.waitForFinished() self.run_process.setProcessChannelMode(QtCore.QProcess.MergedChannels) @@ -527,10 +535,21 @@ def runSingleTest(self, testName): "{0}/test/CMSIT.xml".format(os.environ.get("PH2ACF_BASE_DIR")), "DoNSteps" ) - self.run_process.start( - "CMSITminiDAQ", - ["-f", "CMSIT.xml", "-c", "{}".format(Test_to_Ph2ACF_Map[self.currentTest])], - ) + if self.currentTest == "CommunicationTest": + self.run_process.start( + "CMSITminiDAQ", + ["-f", "CMSIT.xml", "-p"], + ) + else: + self.run_process.start( + "CMSITminiDAQ", + ["-f", "CMSIT.xml", "-c", "{}".format(Test_to_Ph2ACF_Map[self.currentTest])], + ) + + #self.run_process.start( + # "CMSITminiDAQ", + # ["-f", "CMSIT.xml", "-c", "{}".format(Test_to_Ph2ACF_Map[self.currentTest])], + #) if Test_to_Ph2ACF_Map[self.currentTest] == "threqu": self.isTDACtuned = True @@ -717,7 +736,8 @@ def on_readyReadStandardOutput(self): except Exception as err: logger.info("Error occures while parsing running time, {0}".format(err)) - + if '@@@ End of CMSIT miniDAQ @@@' in textStr: + self.ProgressingMode = "Summary" if self.ProgressingMode == "Perform": if "Progress:" in textStr: try: @@ -854,6 +874,8 @@ def check_for_end_of_test(self, textStr): return True elif "New injection delay" in textStr: return True + elif "CommunicationTest" == self.currentTest: + return True return False # Reads data that is normally printed to the terminal and saves it to the output file diff --git a/Gui/python/TestValidator.py b/Gui/python/TestValidator.py index 6ea7e92..acff1bc 100644 --- a/Gui/python/TestValidator.py +++ b/Gui/python/TestValidator.py @@ -11,8 +11,8 @@ def ResultGrader(felis, outputDir, testName, testIndexInSequence, runNumber, mod module_name = module_data['module'].getModuleName() module_type = module_data['module'].getModuleType() module_version = module_data['module'].getModuleVersion() - if 'IVCurve' in testName or 'SLDOScan' in testName: - explanation = 'No grading currently available for IVCurve or SLDOScan.' + if 'IVCurve' in testName or 'SLDOScan' in testName or 'CommunicationTest' in testName: + explanation = 'No grading currently available for IVCurve, SLDOScan, or CommunicationTest.' return {module_name:(True, explanation)} root_file_name = testName.split('_')[0] diff --git a/Gui/siteConfig.py b/Gui/siteConfig.py index c6f0a05..dc93a98 100644 --- a/Gui/siteConfig.py +++ b/Gui/siteConfig.py @@ -40,6 +40,12 @@ defaultPeltierWarningTemp = 40 ################################# +# Temperature Chamber Variables +# Only UIC and OSU should be setting this variable. This is to control +# the f4t thermal chamber (this is NOT the same as the UIC coldbox used for standard +# module testing!) +#temp_chamber_resource = "TCPIP::128.146.33.179::5025::SOCKET" + # Icicle variables # Set this variable to use your powersupplies manually diff --git a/InnerTrackerTests b/InnerTrackerTests index f1f829f..1df224a 160000 --- a/InnerTrackerTests +++ b/InnerTrackerTests @@ -1 +1 @@ -Subproject commit f1f829f23165fa73d4a9c077ededd76f26211cfe +Subproject commit 1df224a56039f554e8e2548b9c5bc71c4ed529ba diff --git a/README.md b/README.md index ea61b6d..f71f826 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,23 @@ In Gui/jsonFiles, there are example files written that may be modified to suit y Returning to Gui/siteConfig.py, you should also scroll down to the "FC7List" and edit the fc7.board.* listed there to match the IP addresses of your FC7 device(s). If you scroll down a little further, you will see a dictionary titled "CableMapping." This serves as a mapping of the cable ID you see when adding modules in the simplified GUI to a physical port on your FC7(s). Each cable ID is associated with a dictionary detailing the path to a port. The first key, "FC7," specifies which FC7 that you want that cable ID to be connected to. The FC7 you list should be in the FC7List above. Next, you can name the "FMCID," representing which FMC on the FC7 you wish to use. The possible values for this are "L8" if the FMC is on the left or "L12" if the FMC is on the right. Finally, you can specify which port on that FMC you want to connect to. The leftmost port is "0" and the rightmost port is "3." - +#### Temperature Chamber +This section only applies to UIC and OSU who have the f4t thermal +chamber for thermal cycling of the modules (This is NOT the same thing +as the UIC coldbox used for standard module testing!). You can add +control of the thermal chamber to the GUI by adding in +temp_chamber_resource to the siteConfig.py file. + +``` python +temp_chamber_resource = "TCPIP::::SOCKET" +``` +where ip_address is the ip address of your thermal chamber which can + be obtained through the settings menu on the f4t controller on the + thermal chamber. This will allow you to select your thermal profile + from the GUI and to stop the running of the profile from the GUI as + well. A thermal profile must be loaded on the thermal chamber prior + to using it with the GUI. + 3. Start the docker container: ``` cd .. @@ -198,3 +214,4 @@ run the command ``` xhost +local: ``` +* If the GUI doens't launch and an error stating a QT plugin could not be used even though it was found, reboot your computer. This seems to be an issue with the QT framework that the GUI is written with and we have yet to determine a fix. diff --git a/icicle b/icicle index 22a716b..2dc0fab 160000 --- a/icicle +++ b/icicle @@ -1 +1 @@ -Subproject commit 22a716bf5a0accdb4248dc05b53589f9864d89a4 +Subproject commit 2dc0fab82b680f985dcbb1942dca777be544df97