|
|
|
|
|
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
|
|
|
|
|
|
QLabel, QLineEdit, QPushButton, QComboBox,
|
|
|
|
|
|
QTabWidget, QMessageBox, QGridLayout, QDoubleSpinBox,
|
|
|
|
|
|
QSpinBox, QFormLayout, QCheckBox)
|
|
|
|
|
|
from PyQt5.QtCore import Qt
|
|
|
|
|
|
|
|
|
|
|
|
class HartCalibrationWidget(QWidget):
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
|
super(HartCalibrationWidget, self).__init__(parent)
|
|
|
|
|
|
self.hartComm = None
|
|
|
|
|
|
self.initUI()
|
|
|
|
|
|
|
|
|
|
|
|
def initUI(self):
|
|
|
|
|
|
# 创建主布局
|
|
|
|
|
|
mainLayout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
|
|
# --- 1. 标准校准区域 ---
|
|
|
|
|
|
calibGroup = QGroupBox("标准校准操作")
|
|
|
|
|
|
calibLayout = QVBoxLayout(calibGroup)
|
|
|
|
|
|
|
|
|
|
|
|
infoLabel1 = QLabel("标准校准操作将校准设备的测量值。请确保在执行校准前已正确连接设备。")
|
|
|
|
|
|
infoLabel1.setWordWrap(True)
|
|
|
|
|
|
calibLayout.addWidget(infoLabel1)
|
|
|
|
|
|
|
|
|
|
|
|
buttonLayout = QGridLayout()
|
|
|
|
|
|
self.calibrate4mAButton = QPushButton("4mA校准 (Command 37)")
|
|
|
|
|
|
self.calibrate20mAButton = QPushButton("20mA校准 (Command 36)")
|
|
|
|
|
|
self.calibrateZeroPointButton = QPushButton("零点校准 (Command 43)")
|
|
|
|
|
|
buttonLayout.addWidget(self.calibrate4mAButton, 0, 0)
|
|
|
|
|
|
buttonLayout.addWidget(self.calibrate20mAButton, 0, 1)
|
|
|
|
|
|
buttonLayout.addWidget(self.calibrateZeroPointButton, 1, 0, 1, 2)
|
|
|
|
|
|
calibLayout.addLayout(buttonLayout)
|
|
|
|
|
|
|
|
|
|
|
|
warningLabel1 = QLabel("警告:校准操作将修改设备的校准参数,请确保您知道您在做什么!")
|
|
|
|
|
|
warningLabel1.setStyleSheet("color: red;")
|
|
|
|
|
|
warningLabel1.setWordWrap(True)
|
|
|
|
|
|
calibLayout.addWidget(warningLabel1)
|
|
|
|
|
|
|
|
|
|
|
|
mainLayout.addWidget(calibGroup)
|
|
|
|
|
|
|
|
|
|
|
|
# --- 2. 环路电流微调区域 ---
|
|
|
|
|
|
trimGroup = QGroupBox("环路电流微调")
|
|
|
|
|
|
trimLayout = QVBoxLayout(trimGroup)
|
|
|
|
|
|
|
|
|
|
|
|
infoLabel2 = QLabel("环路电流微调用于精确调整4mA和20mA输出。请先进入固定电流模式使设备输出固定电流,再使用高精度电流表测量实际输出电流,然后输入测量值进行微调。")
|
|
|
|
|
|
infoLabel2.setWordWrap(True)
|
|
|
|
|
|
trimLayout.addWidget(infoLabel2)
|
|
|
|
|
|
|
|
|
|
|
|
trim4mAGroup = QGroupBox("4mA微调 (Command 45)")
|
|
|
|
|
|
trim4mALayout = QFormLayout(trim4mAGroup)
|
|
|
|
|
|
self.trim4mASpinBox = QDoubleSpinBox()
|
|
|
|
|
|
self.trim4mASpinBox.setRange(3.0, 5.0)
|
|
|
|
|
|
self.trim4mASpinBox.setSingleStep(0.001)
|
|
|
|
|
|
self.trim4mASpinBox.setDecimals(3)
|
|
|
|
|
|
self.trim4mASpinBox.setValue(4.0)
|
|
|
|
|
|
self.trim4mAButton = QPushButton("执行4mA微调")
|
|
|
|
|
|
trim4mALayout.addRow(QLabel("测量的电流值(mA):"), self.trim4mASpinBox)
|
|
|
|
|
|
trim4mALayout.addRow("", self.trim4mAButton)
|
|
|
|
|
|
|
|
|
|
|
|
trim20mAGroup = QGroupBox("20mA微调 (Command 46)")
|
|
|
|
|
|
trim20mALayout = QFormLayout(trim20mAGroup)
|
|
|
|
|
|
self.trim20mASpinBox = QDoubleSpinBox()
|
|
|
|
|
|
self.trim20mASpinBox.setRange(19.0, 21.0)
|
|
|
|
|
|
self.trim20mASpinBox.setSingleStep(0.001)
|
|
|
|
|
|
self.trim20mASpinBox.setDecimals(3)
|
|
|
|
|
|
self.trim20mASpinBox.setValue(20.0)
|
|
|
|
|
|
self.trim20mAButton = QPushButton("执行20mA微调")
|
|
|
|
|
|
trim20mALayout.addRow(QLabel("测量的电流值(mA):"), self.trim20mASpinBox)
|
|
|
|
|
|
trim20mALayout.addRow("", self.trim20mAButton)
|
|
|
|
|
|
|
|
|
|
|
|
trimLayout.addWidget(trim4mAGroup)
|
|
|
|
|
|
trimLayout.addWidget(trim20mAGroup)
|
|
|
|
|
|
|
|
|
|
|
|
warningLabel2 = QLabel("警告:微调操作将修改设备的校准参数,请确保使用高精度电流表测量!")
|
|
|
|
|
|
warningLabel2.setStyleSheet("color: red;")
|
|
|
|
|
|
warningLabel2.setWordWrap(True)
|
|
|
|
|
|
trimLayout.addWidget(warningLabel2)
|
|
|
|
|
|
|
|
|
|
|
|
mainLayout.addWidget(trimGroup)
|
|
|
|
|
|
|
|
|
|
|
|
# --- 3. 固定电流输出区域 ---
|
|
|
|
|
|
fixedCurrentGroup = QGroupBox("固定电流输出 (Command 40)")
|
|
|
|
|
|
fixedCurrentLayout = QVBoxLayout(fixedCurrentGroup)
|
|
|
|
|
|
|
|
|
|
|
|
infoLabel3 = QLabel("固定电流输出模式用于测试和校准目的。在此模式下,设备将输出固定电流值,不受测量值变化的影响。")
|
|
|
|
|
|
infoLabel3.setWordWrap(True)
|
|
|
|
|
|
fixedCurrentLayout.addWidget(infoLabel3)
|
|
|
|
|
|
|
|
|
|
|
|
self.enableFixedCurrentCheckBox = QCheckBox("启用固定电流输出")
|
|
|
|
|
|
fixedCurrentLayout.addWidget(self.enableFixedCurrentCheckBox)
|
|
|
|
|
|
|
|
|
|
|
|
fixedCurrentFormLayout = QFormLayout()
|
|
|
|
|
|
self.fixedCurrentSpinBox = QDoubleSpinBox()
|
|
|
|
|
|
self.fixedCurrentSpinBox.setRange(3.8, 21.0)
|
|
|
|
|
|
self.fixedCurrentSpinBox.setSingleStep(0.1)
|
|
|
|
|
|
self.fixedCurrentSpinBox.setDecimals(2)
|
|
|
|
|
|
self.fixedCurrentSpinBox.setValue(4.0)
|
|
|
|
|
|
self.fixedCurrentSpinBox.setEnabled(False)
|
|
|
|
|
|
fixedCurrentFormLayout.addRow(QLabel("固定电流值(mA):"), self.fixedCurrentSpinBox)
|
|
|
|
|
|
fixedCurrentLayout.addLayout(fixedCurrentFormLayout)
|
|
|
|
|
|
|
|
|
|
|
|
self.applyFixedCurrentButton = QPushButton("应用设置")
|
|
|
|
|
|
fixedCurrentLayout.addWidget(self.applyFixedCurrentButton)
|
|
|
|
|
|
|
|
|
|
|
|
warningLabel3 = QLabel("警告:启用固定电流输出模式将使设备不再响应测量值变化!请在完成测试后务必退出固定电流模式。")
|
|
|
|
|
|
warningLabel3.setStyleSheet("color: red;")
|
|
|
|
|
|
warningLabel3.setWordWrap(True)
|
|
|
|
|
|
fixedCurrentLayout.addWidget(warningLabel3)
|
|
|
|
|
|
|
|
|
|
|
|
mainLayout.addWidget(fixedCurrentGroup)
|
|
|
|
|
|
|
|
|
|
|
|
mainLayout.addStretch(1)
|
|
|
|
|
|
self.setLayout(mainLayout)
|
|
|
|
|
|
|
|
|
|
|
|
# --- 连接所有信号和槽 ---
|
|
|
|
|
|
self.calibrate4mAButton.clicked.connect(self.onCalibrate4mA)
|
|
|
|
|
|
self.calibrate20mAButton.clicked.connect(self.onCalibrate20mA)
|
|
|
|
|
|
self.calibrateZeroPointButton.clicked.connect(self.onCalibrateZeroPoint)
|
|
|
|
|
|
self.trim4mAButton.clicked.connect(self.onTrimLoopCurrent4mA)
|
|
|
|
|
|
self.trim20mAButton.clicked.connect(self.onTrimLoopCurrent20mA)
|
|
|
|
|
|
self.enableFixedCurrentCheckBox.toggled.connect(self.fixedCurrentSpinBox.setEnabled)
|
|
|
|
|
|
self.applyFixedCurrentButton.clicked.connect(self.onSetFixedCurrentOutput)
|
|
|
|
|
|
|
|
|
|
|
|
def setHartComm(self, hartComm):
|
|
|
|
|
|
"""设置HART通信对象"""
|
|
|
|
|
|
self.hartComm = hartComm
|
|
|
|
|
|
|
|
|
|
|
|
def onCalibrate4mA(self):
|
|
|
|
|
|
"""4mA校准 command 37"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", "确定要执行4mA校准吗?此操作将修改设备校准参数。",
|
|
|
|
|
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.calibrate4mA()
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"4mA校准成功!\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"4mA校准失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "4mA校准失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"4mA校准时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def onCalibrate20mA(self):
|
|
|
|
|
|
"""20mA校准 command 36"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", "确定要执行20mA校准吗?此操作将修改设备校准参数。",
|
|
|
|
|
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.calibrate20mA()
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"20mA校准成功!\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"20mA校准失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "20mA校准失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"20mA校准时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def onCalibrateZeroPoint(self):
|
|
|
|
|
|
"""零点校准 command 43"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", "确定要执行零点校准吗?此操作将修改设备校准参数。",
|
|
|
|
|
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.calibrateZeroPoint()
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"零点校准成功!\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"零点校准失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "零点校准失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"零点校准时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def onTrimLoopCurrent4mA(self):
|
|
|
|
|
|
"""微调环路电流4mA command 45"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
measured_current = self.trim4mASpinBox.value()
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", f"确定要使用测量值 {measured_current} mA 执行4mA微调吗?此操作将修改设备校准参数。",
|
|
|
|
|
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.trimLoopCurrent4mA(measured_current)
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"4mA环路电流微调成功!\n测量值: {measured_current} mA\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"4mA环路电流微调失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "4mA环路电流微调失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"4mA环路电流微调时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def onTrimLoopCurrent20mA(self):
|
|
|
|
|
|
"""微调环路电流20mA command 46"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
measured_current = self.trim20mASpinBox.value()
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", f"确定要使用测量值 {measured_current} mA 执行20mA微调吗?此操作将修改设备校准参数。",
|
|
|
|
|
|
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.trimLoopCurrent20mA(measured_current)
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"20mA环路电流微调成功!\n测量值: {measured_current} mA\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"20mA环路电流微调失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "20mA环路电流微调失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"20mA环路电流微调时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def onSetFixedCurrentOutput(self):
|
|
|
|
|
|
"""设置固定电流输出/退出固定模式 command 40"""
|
|
|
|
|
|
if not self.hartComm or not self.hartComm.isConnected():
|
|
|
|
|
|
QMessageBox.warning(self, "警告", "设备未连接,请先连接设备")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
enable = self.enableFixedCurrentCheckBox.isChecked()
|
|
|
|
|
|
current_value = self.fixedCurrentSpinBox.value() if enable else 0.0
|
|
|
|
|
|
|
|
|
|
|
|
if enable:
|
|
|
|
|
|
message = f"确定要启用固定电流输出模式,输出电流值为 {current_value} mA 吗?\n\n警告:启用此模式后,设备将不再响应测量值变化!"
|
|
|
|
|
|
else:
|
|
|
|
|
|
message = "确定要退出固定电流输出模式吗?"
|
|
|
|
|
|
|
|
|
|
|
|
reply = QMessageBox.question(self, "确认", message, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
|
|
|
|
|
if reply != QMessageBox.Yes:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
raw_response = self.hartComm.setFixedCurrentOutput(enable, current_value)
|
|
|
|
|
|
response_dict = raw_response[0] if isinstance(raw_response, list) and raw_response else raw_response
|
|
|
|
|
|
|
|
|
|
|
|
if isinstance(response_dict, dict) and response_dict.get("status") == "success":
|
|
|
|
|
|
details = self.formatResponseDetails(response_dict)
|
|
|
|
|
|
if enable:
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"已启用固定电流输出模式!\n电流值: {current_value} mA\n\n{details}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.information(self, "成功", f"已退出固定电流输出模式!\n\n{details}")
|
|
|
|
|
|
elif isinstance(response_dict, dict):
|
|
|
|
|
|
error_msg = response_dict.get("error", "未知错误")
|
|
|
|
|
|
QMessageBox.critical(self, "错误", f"设置固定电流输出失败: {error_msg}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
QMessageBox.critical(self, "错误", "设置固定电流输出失败: 无效的响应格式")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
QMessageBox.critical(self, "异常", f"设置固定电流输出时发生异常: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
def formatResponseDetails(self, response):
|
|
|
|
|
|
"""格式化响应详细信息"""
|
|
|
|
|
|
details = ""
|
|
|
|
|
|
|
|
|
|
|
|
# 添加消息对象的详细信息
|
|
|
|
|
|
msg = response.get("msg", {})
|
|
|
|
|
|
if msg:
|
|
|
|
|
|
details += "消息详情:\n"
|
|
|
|
|
|
for key, value in msg.items():
|
|
|
|
|
|
# 处理二进制数据,转换为可读形式
|
|
|
|
|
|
if isinstance(value, bytes):
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 尝试解码为ASCII字符串,移除不可打印字符
|
|
|
|
|
|
printable_chars = "".join(chr(c) for c in value if 32 <= c <= 126)
|
|
|
|
|
|
if printable_chars:
|
|
|
|
|
|
value_str = f"{printable_chars} (HEX: {value.hex()})"
|
|
|
|
|
|
else:
|
|
|
|
|
|
value_str = f"HEX: {value.hex()}"
|
|
|
|
|
|
except:
|
|
|
|
|
|
value_str = f"HEX: {value.hex()}"
|
|
|
|
|
|
else:
|
|
|
|
|
|
value_str = str(value)
|
|
|
|
|
|
|
|
|
|
|
|
details += f" {key}: {value_str}\n"
|
|
|
|
|
|
|
|
|
|
|
|
# 添加原始数据的详细信息
|
|
|
|
|
|
raw_data = response.get("raw_data")
|
|
|
|
|
|
if raw_data:
|
|
|
|
|
|
details += "\n原始数据:\n"
|
|
|
|
|
|
details += f" HEX: {raw_data.hex()}"
|
|
|
|
|
|
|
|
|
|
|
|
return details
|