Compare commits

...

7 Commits

Author SHA1 Message Date
linuswck a512614de5 net: add option not to open sock when it is polled
- fix a bug, which mcu can get stuck in State::HardReset indefinitely
2024-09-11 17:54:23 +08:00
linuswck 76f7875e3a gui: await for hard rst and dfu action 2024-09-11 17:54:23 +08:00
linuswck 0d64d62fb0 gui: Add pd_mon config form
- force user to follow a sequence of steps for safely configuring pd_mon
2024-09-11 17:54:18 +08:00
linuswck 0aeffdbf7b ld_pwr_exc_protector: disable irq after pwr off
-setting 0V threshold during power off might trigger IRQ
2024-09-11 17:05:38 +08:00
linuswck 89a1270c02 driver: send cmd err msg to a pyqt sig 2024-09-11 17:05:38 +08:00
linuswck c2e78e6f17 driver: Support ApplyPdParams cmd
- Include handling mechanism for "InvalidSettings"b response msg
2024-09-11 17:05:38 +08:00
linuswck 86e6d3764e laser: check pd_mon params & pwr limit before set
- Design to prevent Issue #47 on hardware kirdy repo from happening
- responsitivity, i_dark & transconductance determine the pwr limit range
- when "ApplyPdParams" and "SetLdPwrLimit" are called, pwr limit range
    is checked before applying new parameter
- Send out a "InvalidSettings" response with error message if settings
    cannot be applied
- Add settable power range to settings json object
2024-09-11 17:05:34 +08:00
10 changed files with 1084 additions and 81 deletions

View File

@ -44,6 +44,7 @@ class CmdList:
SetI = _dt.f32
SetPdResponsitivity = _dt.f32
SetPdDarkCurrent = _dt.f32
ApplyPdParams = _dt.none
SetLdPwrLimit = _dt.f32
ClearAlarm = _dt.none
@ -266,15 +267,19 @@ class Device:
'msg_type': 'Settings', # Indicate it is a 'Settings' json object
'laser': {
'default_pwr_on': False, # Power On Laser Diode at Startup
'ld_drive_current': { # Laser Diode Output Current(A)
'ld_drive_current': { # Laser Diode Output Current (A)
'value': 0.0, # Value Set
'max': 0.3 # Max Value Settable
},
'pd_mon_params': { # Laser Diode Software Current Limit(A)
'responsitivity': None, # Value Set
'i_dark': 0.0 # Max Value Settable
'pd_mon_params': { # Photodiode Parameters
'transconductance': 0.000115258765 # Board Specific Transconductance (1/ohm)
'responsitivity': 0.0141, # Responsitivity (A/W)
'i_dark': 0.0 # Max Value Settable (A)
},
'ld_pwr_limit': { # Laser Diode Power Limit (W)
'value': 0.00975, # Value Set
'max': 0.023321507 # Max Value Settable
},
'ld_pwr_limit': 0.0, # Laser Diode Power Limit(W)
'ld_terms_short: False, # Is Laser Diode Terminals short? (True/False)
},
'thermostat': {
@ -282,19 +287,19 @@ class Device:
'pid_engaged': True, # True: PID Control Mode | False Constant Current Mode
'temperature_setpoint': 25.0, # Temperature Setpoint (Degree Celsius)
'tec_settings': {
'i_set': { # Current TEC Current Set by PID Controller/User
'i_set': { # Current TEC Current Set by PID Controller/User (A)
'value': 0.04330516, # Value Set
'max': 1.0 # Max Value Settable
},
'max_v': { # Max Voltage Across Tec Terminals
'max_v': { # Max Voltage Across Tec Terminals (V)
'value': 4.990857, # Value Set
'max': 5.0 # Max Value Settable
},
'max_i_pos': { # Max Cooling Current Across Tec Terminals
'max_i_pos': { # Max Cooling Current Across Tec Terminals (A)
'value': 0.99628574, # Value Set
'max': 1.0 # Max Value Settable
},
'max_i_neg': { # Max Heating Current Across Tec Terminals
'max_i_neg': { # Max Heating Current Across Tec Terminals (A)
'value': 0.99628574, # Value Set
'max': 1.0 # Max Value Settable
}
@ -396,6 +401,7 @@ class Laser:
async def set_pd_mon_responsitivity(self, responsitivity):
"""
Configure the photodiode monitor responsitivity parameter.
The value is only effective if ApplyPdParams cmd is issued.
- responsitivity: A/W
"""
return await self._send_cmd(self._cmd._target, self._cmd.SetPdResponsitivity, responsitivity)
@ -403,13 +409,26 @@ class Laser:
async def set_pd_mon_dark_current(self, dark_current):
"""
Configure the photodiode monitor dark current parameter.
The value is only effective if ApplyPdParams cmd is issued.
- dark_current: A
"""
return await self._send_cmd(self._cmd._target, self._cmd.SetPdDarkCurrent, dark_current)
async def apply_pd_params(self):
"""
Evaluate and apply photodiode monitor parameters that are set with SetPdDarkCurrent and SetPdResponsitivity cmd.
After Kirdy receives the cmd, it will check if the current power limit is within the newly calculated
power limit range. If it is out of range, the photodiode monitor parameters remains unchanged and Kirdy
sends out a "InvalidSettings" message along with an error message.
"""
return await self._send_cmd(self._cmd._target, self._cmd.ApplyPdParams)
async def set_ld_pwr_limit(self, pwr_limit):
"""
Set the power limit for the power excursion monitor.
If the power limit settings is out of range, power limit remains unchanged and Kirdy
sends out a "InvalidSettings" message along with an error message.
If the calculated power with the params of pd_mon > pwr_limit,
overpower protection is triggered.
- pwr_limit: W
@ -623,6 +642,7 @@ class Kirdy:
# PyQt Signal
self._report_sig = None # Dict
self._connected_sig = None # Bool
self._err_msg_sig = None # Str
self.connected_event = None
@ -643,6 +663,12 @@ class Kirdy:
"""
self._connected_sig = sig
def set_err_msg_sig(self, sig):
"""
Emit a error message to a PyQt Signal(str) when a cmd fails to execute
"""
self._err_msg_sig = sig
def start_session(self, host='192.168.1.128', port=1337):
"""
Start Kirdy Connection Session.
@ -875,20 +901,25 @@ class Kirdy:
response = raw_response.decode('utf-8', errors='ignore').split("\n")
return json.loads(response[0])
def _response_handling(self, msg, msg_type, sig=None):
if msg["msg_type"] in ["InvalidCmd", "InvalidDatatype"]:
raise InvalidCmd
elif msg["msg_type"] == msg_type:
if sig is not None:
sig.emit(msg)
else:
logging.warn(f"Commands fail to execute. {msg['msg_type']}:{msg['msg']}")
if self._err_msg_sig is not None and msg['msg'] is not None:
self._err_msg_sig.emit(msg['msg'])
return msg
async def _send_raw_cmd(self, cmd, msg_type="Acknowledge", sig=None):
if self.connected():
async with self._lock:
self._writer.write(bytes(json.dumps(cmd), "UTF-8"))
await self._writer.drain()
msg = await asyncio.wait_for(self._int_msg_queue.get(), self._timeout)
if msg["msg_type"] == msg_type:
if sig is not None:
sig.emit(msg)
return {"msg_type": "Acknowledge"}
return msg
else:
raise InvalidCmd
return self._response_handling(msg, msg_type, sig)
else:
raise ConnectionError
@ -919,12 +950,4 @@ class Kirdy:
msg = await asyncio.wait_for(self._int_msg_queue.get(), self._timeout)
if isinstance(msg, Exception):
raise msg
if msg['msg_type'] == msg_type:
if sig is not None:
sig.emit(msg)
return {"msg_type": "Acknowledge"}
else:
return msg
else:
raise InvalidCmd
return self._response_handling(msg, msg_type, sig)

View File

@ -26,6 +26,7 @@ from datetime import datetime, timezone, timedelta
from time import time
from typing import Any, Optional, List
from ui.ui_conn_settings_form import Ui_Conn_Settings_Form
from ui.ui_config_pd_mon_form import Ui_Cfg_Pd_Mon_Form
from ui.ui_update_network_settings_form import Ui_Update_Network_Settings_Form
from dateutil import tz
import math
@ -54,6 +55,9 @@ def siConvert(val, suffix, typ=float):
siConvert(0.1, "mA") # returns 100
"""
if val is None:
val = 0.0
val, siprefix, suffix = siParse(str(val)+suffix, FLOAT_REGEX)
v = typ(val)
@ -70,6 +74,7 @@ class Kirdy(QObject):
connected_sig = pyqtSignal(bool)
setting_update_sig = pyqtSignal(dict)
report_update_sig = pyqtSignal(dict)
cmd_fail_sig = pyqtSignal(str)
def __init__(self, parent, kirdy, _poll_interval):
super().__init__(parent)
@ -80,6 +85,7 @@ class Kirdy(QObject):
self.connected_sig.connect(self.connected_setup)
self._kirdy.set_report_sig(self.report_update_sig)
self._kirdy.set_err_msg_sig(self.cmd_fail_sig)
self._timer = QtCore.QBasicTimer()
def connected(self):
@ -317,6 +323,10 @@ class UpdateNetSettingsForm(QtWidgets.QDialog, Ui_Update_Network_Settings_Form):
except (OSError, ValueError):
return None
class CfgPdMonForm(QtWidgets.QDialog, Ui_Cfg_Pd_Mon_Form):
def __init__(self):
super().__init__()
self.setupUi(self)
class ConnSettingsForm(QtWidgets.QDialog, Ui_Conn_Settings_Form):
def __init__(self):
@ -355,18 +365,19 @@ class MainWindow(QtWidgets.QMainWindow):
{'name': 'LF Mod Termination (50 Ohm)', 'type': 'list', 'limits': ['On', 'Off'], 'readonly': True, "compactHeight": False}
]},
{'name': 'Output Config', 'expanded': True, 'type': 'group', 'children': [
{'name': 'LD Current Set', 'type': 'float', 'value': 0, 'step': 0.001, 'decimals': 6, 'limits': (0, 300),
{'name': 'LD Current Set', 'type': 'float', 'value': 0, 'step': 0.001, 'format': '{value:.4f}', 'decimals': 6, 'limits': (0, 300),
'unit': 'mA', 'lock': False, 'target': 'laser', 'action': 'set_i', "compactHeight": False},
{'name': 'LD Terminals Short', 'type': 'bool', 'value': False, 'lock': False, 'target': 'laser', 'action': 'set_ld_terms_short', "compactHeight": False},
{'name': 'Default Power On', 'type': 'bool', 'value': False, 'lock': False, 'target': 'laser', 'action': 'set_default_pwr_on', "compactHeight": False},
]},
{'name': 'Photodiode Monitor Config', 'expanded': False, 'type': 'group', 'children': [
{'name': 'LD Power Limit', 'type': 'float', 'value': 0, 'step': 0.001, 'decimals': 6, 'limits': (0, float("inf")),
{'name': 'LD Power Limit', 'type': 'float', 'value': 0, 'step': 0.001, 'format': '{value:.4f}', 'decimals': 6, 'limits': (0, float("inf")),
'unit': 'mW', 'lock': False, 'target': 'laser', 'action': 'set_ld_pwr_limit', "compactHeight": False},
{'name': 'Responsitivity', 'type': 'float', 'value': 0, 'step': 0.001, 'decimals': 6, 'limits': (0, float("inf")),
'unit': 'mA/W', 'lock': False, 'target': 'laser', 'action': 'set_pd_mon_responsitivity', "compactHeight": False},
{'name': 'Dark Current', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (0, float("inf")),
'unit': 'uA', 'lock': False, 'target': 'laser', 'action': 'set_pd_mon_dark_current', "compactHeight": False},
{'name': 'Responsitivity', 'type': 'float', 'value': 0, 'step': 0.001, 'format': '{value:.4f}', 'decimals': 6, 'limits': (0, float("inf")),
'unit': 'mA/W', 'lock': False, 'target': 'laser', 'action': 'set_pd_mon_responsitivity', "compactHeight": False, 'readonly': True},
{'name': 'Dark Current', 'type': 'float', 'value': 0, 'step': 1, 'format': '{value:.4f}', 'decimals': 6, 'limits': (0, float("inf")),
'unit': 'uA', 'lock': False, 'target': 'laser', 'action': 'set_pd_mon_dark_current', "compactHeight": False, 'readonly': True},
{'name': 'Configure Photodiode Monitor', 'type': 'action'},
]},
]
@ -451,6 +462,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.ip_addr = self.DEFAULT_IP_ADDR
self.port = self.DEFAULT_PORT
self.cfg_pd_mon_form = CfgPdMonForm()
self.conn_settings_form = ConnSettingsForm()
self.conn_settings_form.accepted.connect(self.start_connecting)
@ -502,6 +515,7 @@ class MainWindow(QtWidgets.QMainWindow):
Parameter.create(name=f"Thermostat Parameters", type='group', value=3, children=self.THERMOSTAT_PARAMETERS),
]
self._set_param_tree()
self._set_up_pd_mon_form()
self.tec_i_graph.setTitle("TEC Current")
self.tec_temp_graph.setTitle("TEC Temperature")
@ -516,6 +530,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.kirdy_handler.setting_update_sig.connect(self.update_thermostat_ctrl_panel_settings)
self.kirdy_handler.report_update_sig.connect(self.update_ld_ctrl_panel_readings)
self.kirdy_handler.report_update_sig.connect(self.update_thermostat_ctrl_panel_readings)
self.kirdy_handler.cmd_fail_sig.connect(self.cmd_cannot_execute)
self.graphs = Graphs(self.ld_i_set_graph, self.pd_mon_pwr_graph, self.tec_i_graph, self.tec_temp_graph, max_samples=self.max_samples)
self.kirdy_handler.report_update_sig.connect(self.graphs.plot_append)
@ -548,15 +563,15 @@ class MainWindow(QtWidgets.QMainWindow):
)
self.menu_action_about_gui.triggered.connect(about_gui)
@pyqtSlot(bool)
def dfu_mode(_):
self.kirdy.task_dispatcher(self.kirdy.device.dfu())
@asyncSlot(bool)
async def dfu_mode(_):
await self.kirdy.device.dfu()
self.kirdy_handler.end_session()
self.menu_action_dfu_mode.triggered.connect(dfu_mode)
@pyqtSlot(bool)
def reset_kirdy(_):
self.kirdy.task_dispatcher(self.kirdy.device.hard_reset())
@asyncSlot(bool)
async def reset_kirdy(_):
await self.kirdy.device.hard_reset()
self.kirdy_handler.end_session()
self.menu_action_hard_reset.triggered.connect(reset_kirdy)
@ -586,6 +601,21 @@ class MainWindow(QtWidgets.QMainWindow):
self.update_net_settings_form.show()
self.menu_action_update_net_settings.triggered.connect(show_update_net_settings_form)
def update_pd_mon_form_readings(self, ld_settings):
pwr_unit = self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').opts.get("unit", None)
self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').setOpts(limits= (0, siConvert(ld_settings["ld_pwr_limit"]["max"], pwr_unit)))
self.cfg_pd_mon_form.settable_pwr_range_display_lbl.setText(f" 0 - {siConvert(ld_settings['ld_pwr_limit']['max'], pwr_unit):.4f}")
self.cfg_pd_mon_form.cfg_pwr_limit_spinbox.setMaximum(siConvert(ld_settings['ld_pwr_limit']['max'], pwr_unit))
responsitivity_unit = self.cfg_pd_mon_form.cfg_responsitivity_spinbox.unit
self.cfg_pd_mon_form.cfg_responsitivity_reading.setText(f"{siConvert(ld_settings['pd_mon_params']['responsitivity'], responsitivity_unit):.4f}")
i_dark_unit = self.cfg_pd_mon_form.cfg_dark_current_spinbox.unit
self.cfg_pd_mon_form.cfg_dark_current_reading.setText(f"{siConvert(ld_settings['pd_mon_params']['i_dark'], i_dark_unit):.4f}")
pwr_limit_unit = self.cfg_pd_mon_form.cfg_pwr_limit_spinbox.unit
self.cfg_pd_mon_form.cfg_pwr_limit_reading.setText(f"{siConvert(ld_settings['ld_pwr_limit']['value'], pwr_limit_unit):.4f}")
def show_conn_settings_form(self):
ip_addr = self.ip_addr.split(".")
self.conn_settings_form.addr_in_0.setText(ip_addr[0])
@ -648,6 +678,70 @@ class MainWindow(QtWidgets.QMainWindow):
self.plot_settings.setMenu(self.plot_menu)
def _set_up_pd_mon_form(self):
@pyqtSlot(bool)
def ld_pwr_on(_):
self.kirdy.task_dispatcher(self.kirdy.laser.clear_alarm())
self.kirdy.task_dispatcher(self.kirdy.laser.set_power_on(True))
self.cfg_pd_mon_form.pwr_on_btn.clicked.connect(ld_pwr_on)
@pyqtSlot(bool)
def ld_pwr_off(_):
self.kirdy.task_dispatcher(self.kirdy.laser.set_power_on(False))
self.cfg_pd_mon_form.pwr_off_btn.clicked.connect(ld_pwr_off)
def get_spinbox_value(spinbox):
_, _, suffix = siParse(str(spinbox.value())+spinbox.unit, regex=FLOAT_REGEX)
return siEval(str(spinbox.value())+spinbox.unit, regex=FLOAT_REGEX, suffix=suffix)
def set_spinbox_value(spinbox, val):
spinbox.setValue(siConvert(val, spinbox.unit))
@pyqtSlot(bool)
def apply_pd_params(_):
responsitivity = get_spinbox_value(self.cfg_pd_mon_form.cfg_responsitivity_spinbox)
dark_current = get_spinbox_value(self.cfg_pd_mon_form.cfg_dark_current_spinbox)
self.kirdy.task_dispatcher(self.kirdy.laser.set_pd_mon_responsitivity(responsitivity))
self.kirdy.task_dispatcher(self.kirdy.laser.set_pd_mon_dark_current(dark_current))
self.kirdy.task_dispatcher(self.kirdy.laser.apply_pd_params())
self.cfg_pd_mon_form.apply_pd_params_btn.clicked.connect(apply_pd_params)
@pyqtSlot(bool)
def apply_ld_pwr_limit(_):
pwr_limit = get_spinbox_value(self.cfg_pd_mon_form.cfg_pwr_limit_spinbox)
self.kirdy.task_dispatcher(self.kirdy.laser.set_ld_pwr_limit(pwr_limit))
self.cfg_pd_mon_form.apply_pwr_limit_btn.clicked.connect(apply_ld_pwr_limit)
@pyqtSlot(bool)
def rst_ld_pwr_limit(_):
pwr_limit = self.cfg_pd_mon_form.cfg_pwr_limit_spinbox.value()
self.kirdy.task_dispatcher(self.kirdy.laser.set_ld_pwr_limit(0))
self.cfg_pd_mon_form.rst_ld_pwr_limit_btn.clicked.connect(rst_ld_pwr_limit)
@asyncSlot(bool)
async def apply_ld_pwr_limit_max(_):
settings = await self.kirdy.device.get_settings_summary()
set_spinbox_value(self.cfg_pd_mon_form.cfg_pwr_limit_spinbox, settings['laser']['ld_pwr_limit']['max'])
self.kirdy.task_dispatcher(self.kirdy.laser.set_ld_pwr_limit(settings['laser']['ld_pwr_limit']['max']))
self.cfg_pd_mon_form.apply_pwr_limit_max_btn.clicked.connect(apply_ld_pwr_limit_max)
ld_pwr_limit_unit = self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').opts["unit"]
ld_pwr_limit_text = self.cfg_pd_mon_form.cfg_pwr_limit_lbl.text()
self.cfg_pd_mon_form.cfg_pwr_limit_lbl.setText(ld_pwr_limit_text.replace(":", f" ({ld_pwr_limit_unit}):"))
self.cfg_pd_mon_form.cfg_pwr_limit_spinbox.unit = ld_pwr_limit_unit
settable_pwr_limit_text = self.cfg_pd_mon_form.settable_pwr_range_lbl.text()
self.cfg_pd_mon_form.settable_pwr_range_lbl.setText(settable_pwr_limit_text.replace(":", f" ({ld_pwr_limit_unit}):"))
pd_responsitivity_unit = self.params[1].child('Photodiode Monitor Config', 'Responsitivity').opts["unit"]
pd_responsitivity_text = self.cfg_pd_mon_form.cfg_responsitivity_lbl.text()
self.cfg_pd_mon_form.cfg_responsitivity_lbl.setText(pd_responsitivity_text.replace(":", f" ({pd_responsitivity_unit}):"))
self.cfg_pd_mon_form.cfg_responsitivity_spinbox.unit = pd_responsitivity_unit
pd_dark_current_unit = self.params[1].child('Photodiode Monitor Config', 'Dark Current').opts["unit"]
pd_dark_current_text = self.cfg_pd_mon_form.cfg_dark_current_lbl.text()
self.cfg_pd_mon_form.cfg_dark_current_lbl.setText(pd_dark_current_text.replace(":", f" ({pd_dark_current_unit}):"))
self.cfg_pd_mon_form.cfg_dark_current_spinbox.unit = pd_dark_current_unit
def _set_param_tree(self):
status = self.ld_status
status.setHeaderHidden(True)
@ -695,6 +789,25 @@ class MainWindow(QtWidgets.QMainWindow):
self.loading_spinner.hide()
self.params[3].child('PID Config', 'PID Auto Tune', 'Run').sigActivated.connect(autotune)
@pyqtSlot()
def show_pd_mon_cfg_form(parm):
ld_pwr_limit = self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').value()
pd_responsitivity = self.params[1].child('Photodiode Monitor Config', 'Responsitivity').value()
pd_dark_current = self.params[1].child('Photodiode Monitor Config', 'Dark Current').value()
self.cfg_pd_mon_form.cfg_responsitivity_spinbox.setValue(pd_responsitivity)
self.cfg_pd_mon_form.cfg_pwr_limit_spinbox.setValue(ld_pwr_limit)
self.cfg_pd_mon_form.cfg_dark_current_spinbox.setValue(pd_dark_current)
self.cfg_pd_mon_form.show()
self.params[1].child('Photodiode Monitor Config', 'Configure Photodiode Monitor').sigActivated.connect(show_pd_mon_cfg_form)
@pyqtSlot(str)
def cmd_cannot_execute(self, kirdy_msg):
self.info_box.setText(kirdy_msg)
self.info_box.setWindowTitle("Command fails to execute")
self.info_box.show()
@pyqtSlot(dict)
def autotune_tick(self, report):
match self.autotuner.state():
@ -803,7 +916,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.params[1].child('Output Config', 'LD Current Set').setValuewithLock(settings["ld_drive_current"]['value'])
self.params[1].child('Output Config', 'LD Terminals Short').setValuewithLock(settings["ld_terms_short"])
self.params[1].child('Output Config', 'Default Power On').setValuewithLock(settings["default_pwr_on"])
self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').setValuewithLock(settings["ld_pwr_limit"])
self.params[1].child('Photodiode Monitor Config', 'LD Power Limit').setValuewithLock(settings["ld_pwr_limit"]["value"])
self.update_pd_mon_form_readings(settings)
if settings["pd_mon_params"]["responsitivity"] is not None:
self.params[1].child('Photodiode Monitor Config', 'Responsitivity').setValuewithLock(settings["pd_mon_params"]["responsitivity"])
else:

View File

@ -0,0 +1,488 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Cfg_Pd_Mon_Form</class>
<widget class="QDialog" name="Cfg_Pd_Mon_Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>520</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>520</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>500</width>
<height>520</height>
</size>
</property>
<property name="windowTitle">
<string>config_pd_mon_form</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>481</width>
<height>500</height>
</rect>
</property>
<layout class="QVBoxLayout" name="cfg_pd_mon_form_layout" stretch="0,2,2,2,2,2,1">
<item>
<widget class="QLabel" name="title_lbl">
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>Configure Photodiode Monitor</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="pwr_off_layout" stretch="5,4">
<property name="spacing">
<number>12</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="pwr_off_lbl">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string> Step 1: Turn off Laser Power</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pwr_off_btn">
<property name="text">
<string>Power Off</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="rst_ld_pwr_limit_layout" stretch="5,4">
<item>
<widget class="QLabel" name="rst_ld_pwr_limit_lbl">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string> Step 2: Reset Ld Pwr Limit to 0</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="rst_ld_pwr_limit_btn">
<property name="text">
<string>Reset Ld Pwr Limit</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="cfg_pd_params_layout">
<item>
<widget class="QLabel" name="cfg_pd_params_lbl">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string> Step 3: Configure Photodiode Parameters</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="5,2,2">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string> Value</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Reading</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="cfg_responsitivity_layout" stretch="5,2,2">
<item>
<widget class="QLabel" name="cfg_responsitivity_lbl">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Responsitivity: </string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="cfg_responsitivity_spinbox">
<property name="suffix">
<string/>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cfg_responsitivity_reading">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>0.0000</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="cfg_dark_current_layout" stretch="5,2,2">
<item>
<widget class="QLabel" name="cfg_dark_current_lbl">
<property name="text">
<string>Dark Current: </string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="cfg_dark_current_spinbox">
<property name="decimals">
<number>4</number>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cfg_dark_current_reading">
<property name="text">
<string>0.0000</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="apply_pd_params_layout" stretch="5,4">
<property name="spacing">
<number>12</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="apply_pd_params_btn">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="cfg_pwr_limit_layout">
<item>
<widget class="QLabel" name="cfg_pd_pwr_limit_lbl">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string> Step 4: Configure Laser Diode Power Limit</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="5,2,2">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string> Value</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Reading</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="pwr_limit_layout" stretch="5,2,2">
<item>
<widget class="QLabel" name="cfg_pwr_limit_lbl">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Power Limit:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="cfg_pwr_limit_spinbox">
<property name="decimals">
<number>4</number>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="cfg_pwr_limit_reading">
<property name="text">
<string>0.0000</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="settable_pwr_range_layout" stretch="5,4">
<property name="spacing">
<number>12</number>
</property>
<item>
<widget class="QLabel" name="settable_pwr_range_lbl">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Settable Power Range:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="settable_pwr_range_display_lbl">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>( Power Range )</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="apply_pwr_limit_layout" stretch="2,3,4">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="apply_pwr_limit_max_btn">
<property name="text">
<string>Apply Max</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="apply_pwr_limit_btn">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="pwr_on_layout" stretch="5,4">
<property name="spacing">
<number>12</number>
</property>
<item>
<widget class="QLabel" name="pwr_on_lbl">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string> Step 5: Turn On Laser Power</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pwr_on_btn">
<property name="text">
<string>Clear Alarm and Power On</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="close_btn_layout" stretch="5,4">
<property name="spacing">
<number>12</number>
</property>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="close_btn">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>close_btn</sender>
<signal>clicked()</signal>
<receiver>Cfg_Pd_Mon_Form</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>141</x>
<y>456</y>
</hint>
<hint type="destinationlabel">
<x>281</x>
<y>355</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,295 @@
# Form implementation generated from reading ui file 'config_pd_mon_form.ui'
#
# Created by: PyQt6 UI code generator 6.6.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_Cfg_Pd_Mon_Form(object):
def setupUi(self, Cfg_Pd_Mon_Form):
Cfg_Pd_Mon_Form.setObjectName("Cfg_Pd_Mon_Form")
Cfg_Pd_Mon_Form.resize(500, 520)
Cfg_Pd_Mon_Form.setMinimumSize(QtCore.QSize(500, 520))
Cfg_Pd_Mon_Form.setMaximumSize(QtCore.QSize(500, 520))
self.verticalLayoutWidget_2 = QtWidgets.QWidget(parent=Cfg_Pd_Mon_Form)
self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(10, 10, 481, 500))
self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2")
self.cfg_pd_mon_form_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2)
self.cfg_pd_mon_form_layout.setContentsMargins(0, 0, 0, 0)
self.cfg_pd_mon_form_layout.setObjectName("cfg_pd_mon_form_layout")
self.title_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(22)
self.title_lbl.setFont(font)
self.title_lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.title_lbl.setObjectName("title_lbl")
self.cfg_pd_mon_form_layout.addWidget(self.title_lbl)
self.pwr_off_layout = QtWidgets.QHBoxLayout()
self.pwr_off_layout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetDefaultConstraint)
self.pwr_off_layout.setSpacing(12)
self.pwr_off_layout.setObjectName("pwr_off_layout")
self.pwr_off_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(14)
self.pwr_off_lbl.setFont(font)
self.pwr_off_lbl.setObjectName("pwr_off_lbl")
self.pwr_off_layout.addWidget(self.pwr_off_lbl)
self.pwr_off_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.pwr_off_btn.setObjectName("pwr_off_btn")
self.pwr_off_layout.addWidget(self.pwr_off_btn)
self.pwr_off_layout.setStretch(0, 5)
self.pwr_off_layout.setStretch(1, 4)
self.cfg_pd_mon_form_layout.addLayout(self.pwr_off_layout)
self.rst_ld_pwr_limit_layout = QtWidgets.QHBoxLayout()
self.rst_ld_pwr_limit_layout.setObjectName("rst_ld_pwr_limit_layout")
self.rst_ld_pwr_limit_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(14)
self.rst_ld_pwr_limit_lbl.setFont(font)
self.rst_ld_pwr_limit_lbl.setObjectName("rst_ld_pwr_limit_lbl")
self.rst_ld_pwr_limit_layout.addWidget(self.rst_ld_pwr_limit_lbl)
self.rst_ld_pwr_limit_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.rst_ld_pwr_limit_btn.setObjectName("rst_ld_pwr_limit_btn")
self.rst_ld_pwr_limit_layout.addWidget(self.rst_ld_pwr_limit_btn)
self.rst_ld_pwr_limit_layout.setStretch(0, 5)
self.rst_ld_pwr_limit_layout.setStretch(1, 4)
self.cfg_pd_mon_form_layout.addLayout(self.rst_ld_pwr_limit_layout)
self.cfg_pd_params_layout = QtWidgets.QVBoxLayout()
self.cfg_pd_params_layout.setObjectName("cfg_pd_params_layout")
self.cfg_pd_params_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(14)
self.cfg_pd_params_lbl.setFont(font)
self.cfg_pd_params_lbl.setObjectName("cfg_pd_params_lbl")
self.cfg_pd_params_layout.addWidget(self.cfg_pd_params_lbl)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.label_2 = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.label_2.setObjectName("label_2")
self.horizontalLayout.addWidget(self.label_2)
self.label = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.horizontalLayout.setStretch(0, 5)
self.horizontalLayout.setStretch(1, 2)
self.horizontalLayout.setStretch(2, 2)
self.cfg_pd_params_layout.addLayout(self.horizontalLayout)
self.cfg_responsitivity_layout = QtWidgets.QHBoxLayout()
self.cfg_responsitivity_layout.setObjectName("cfg_responsitivity_layout")
self.cfg_responsitivity_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.cfg_responsitivity_lbl.sizePolicy().hasHeightForWidth())
self.cfg_responsitivity_lbl.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(12)
self.cfg_responsitivity_lbl.setFont(font)
self.cfg_responsitivity_lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.cfg_responsitivity_lbl.setObjectName("cfg_responsitivity_lbl")
self.cfg_responsitivity_layout.addWidget(self.cfg_responsitivity_lbl)
self.cfg_responsitivity_spinbox = QtWidgets.QDoubleSpinBox(parent=self.verticalLayoutWidget_2)
self.cfg_responsitivity_spinbox.setSuffix("")
self.cfg_responsitivity_spinbox.setDecimals(4)
self.cfg_responsitivity_spinbox.setMaximum(1000.0)
self.cfg_responsitivity_spinbox.setSingleStep(0.001)
self.cfg_responsitivity_spinbox.setObjectName("cfg_responsitivity_spinbox")
self.cfg_responsitivity_layout.addWidget(self.cfg_responsitivity_spinbox)
self.cfg_responsitivity_reading = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.cfg_responsitivity_reading.sizePolicy().hasHeightForWidth())
self.cfg_responsitivity_reading.setSizePolicy(sizePolicy)
self.cfg_responsitivity_reading.setObjectName("cfg_responsitivity_reading")
self.cfg_responsitivity_layout.addWidget(self.cfg_responsitivity_reading)
self.cfg_responsitivity_layout.setStretch(0, 5)
self.cfg_responsitivity_layout.setStretch(1, 2)
self.cfg_responsitivity_layout.setStretch(2, 2)
self.cfg_pd_params_layout.addLayout(self.cfg_responsitivity_layout)
self.cfg_dark_current_layout = QtWidgets.QHBoxLayout()
self.cfg_dark_current_layout.setObjectName("cfg_dark_current_layout")
self.cfg_dark_current_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.cfg_dark_current_lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.cfg_dark_current_lbl.setObjectName("cfg_dark_current_lbl")
self.cfg_dark_current_layout.addWidget(self.cfg_dark_current_lbl)
self.cfg_dark_current_spinbox = QtWidgets.QDoubleSpinBox(parent=self.verticalLayoutWidget_2)
self.cfg_dark_current_spinbox.setDecimals(4)
self.cfg_dark_current_spinbox.setSingleStep(0.001)
self.cfg_dark_current_spinbox.setObjectName("cfg_dark_current_spinbox")
self.cfg_dark_current_layout.addWidget(self.cfg_dark_current_spinbox)
self.cfg_dark_current_reading = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.cfg_dark_current_reading.setObjectName("cfg_dark_current_reading")
self.cfg_dark_current_layout.addWidget(self.cfg_dark_current_reading)
self.cfg_dark_current_layout.setStretch(0, 5)
self.cfg_dark_current_layout.setStretch(1, 2)
self.cfg_dark_current_layout.setStretch(2, 2)
self.cfg_pd_params_layout.addLayout(self.cfg_dark_current_layout)
self.apply_pd_params_layout = QtWidgets.QHBoxLayout()
self.apply_pd_params_layout.setSpacing(12)
self.apply_pd_params_layout.setObjectName("apply_pd_params_layout")
spacerItem1 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.apply_pd_params_layout.addItem(spacerItem1)
self.apply_pd_params_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.apply_pd_params_btn.setObjectName("apply_pd_params_btn")
self.apply_pd_params_layout.addWidget(self.apply_pd_params_btn)
self.apply_pd_params_layout.setStretch(0, 5)
self.apply_pd_params_layout.setStretch(1, 4)
self.cfg_pd_params_layout.addLayout(self.apply_pd_params_layout)
self.cfg_pd_mon_form_layout.addLayout(self.cfg_pd_params_layout)
self.cfg_pwr_limit_layout = QtWidgets.QVBoxLayout()
self.cfg_pwr_limit_layout.setObjectName("cfg_pwr_limit_layout")
self.cfg_pd_pwr_limit_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(14)
self.cfg_pd_pwr_limit_lbl.setFont(font)
self.cfg_pd_pwr_limit_lbl.setObjectName("cfg_pd_pwr_limit_lbl")
self.cfg_pwr_limit_layout.addWidget(self.cfg_pd_pwr_limit_lbl)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.horizontalLayout_2.addItem(spacerItem2)
self.label_3 = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.label_3.setObjectName("label_3")
self.horizontalLayout_2.addWidget(self.label_3)
self.label_4 = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.label_4.setObjectName("label_4")
self.horizontalLayout_2.addWidget(self.label_4)
self.horizontalLayout_2.setStretch(0, 5)
self.horizontalLayout_2.setStretch(1, 2)
self.horizontalLayout_2.setStretch(2, 2)
self.cfg_pwr_limit_layout.addLayout(self.horizontalLayout_2)
self.pwr_limit_layout = QtWidgets.QHBoxLayout()
self.pwr_limit_layout.setObjectName("pwr_limit_layout")
self.cfg_pwr_limit_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(12)
self.cfg_pwr_limit_lbl.setFont(font)
self.cfg_pwr_limit_lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.cfg_pwr_limit_lbl.setObjectName("cfg_pwr_limit_lbl")
self.pwr_limit_layout.addWidget(self.cfg_pwr_limit_lbl)
self.cfg_pwr_limit_spinbox = QtWidgets.QDoubleSpinBox(parent=self.verticalLayoutWidget_2)
self.cfg_pwr_limit_spinbox.setDecimals(4)
self.cfg_pwr_limit_spinbox.setSingleStep(0.001)
self.cfg_pwr_limit_spinbox.setObjectName("cfg_pwr_limit_spinbox")
self.pwr_limit_layout.addWidget(self.cfg_pwr_limit_spinbox)
self.cfg_pwr_limit_reading = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.cfg_pwr_limit_reading.setObjectName("cfg_pwr_limit_reading")
self.pwr_limit_layout.addWidget(self.cfg_pwr_limit_reading)
self.pwr_limit_layout.setStretch(0, 5)
self.pwr_limit_layout.setStretch(1, 2)
self.pwr_limit_layout.setStretch(2, 2)
self.cfg_pwr_limit_layout.addLayout(self.pwr_limit_layout)
self.settable_pwr_range_layout = QtWidgets.QHBoxLayout()
self.settable_pwr_range_layout.setSpacing(12)
self.settable_pwr_range_layout.setObjectName("settable_pwr_range_layout")
self.settable_pwr_range_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(12)
self.settable_pwr_range_lbl.setFont(font)
self.settable_pwr_range_lbl.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
self.settable_pwr_range_lbl.setObjectName("settable_pwr_range_lbl")
self.settable_pwr_range_layout.addWidget(self.settable_pwr_range_lbl)
self.settable_pwr_range_display_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
self.settable_pwr_range_display_lbl.setMinimumSize(QtCore.QSize(0, 28))
self.settable_pwr_range_display_lbl.setObjectName("settable_pwr_range_display_lbl")
self.settable_pwr_range_layout.addWidget(self.settable_pwr_range_display_lbl)
self.settable_pwr_range_layout.setStretch(0, 5)
self.settable_pwr_range_layout.setStretch(1, 4)
self.cfg_pwr_limit_layout.addLayout(self.settable_pwr_range_layout)
self.apply_pwr_limit_layout = QtWidgets.QHBoxLayout()
self.apply_pwr_limit_layout.setObjectName("apply_pwr_limit_layout")
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.apply_pwr_limit_layout.addItem(spacerItem3)
self.apply_pwr_limit_max_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.apply_pwr_limit_max_btn.setObjectName("apply_pwr_limit_max_btn")
self.apply_pwr_limit_layout.addWidget(self.apply_pwr_limit_max_btn)
self.apply_pwr_limit_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.apply_pwr_limit_btn.setObjectName("apply_pwr_limit_btn")
self.apply_pwr_limit_layout.addWidget(self.apply_pwr_limit_btn)
self.apply_pwr_limit_layout.setStretch(0, 2)
self.apply_pwr_limit_layout.setStretch(1, 3)
self.apply_pwr_limit_layout.setStretch(2, 4)
self.cfg_pwr_limit_layout.addLayout(self.apply_pwr_limit_layout)
self.cfg_pd_mon_form_layout.addLayout(self.cfg_pwr_limit_layout)
self.pwr_on_layout = QtWidgets.QHBoxLayout()
self.pwr_on_layout.setSpacing(12)
self.pwr_on_layout.setObjectName("pwr_on_layout")
self.pwr_on_lbl = QtWidgets.QLabel(parent=self.verticalLayoutWidget_2)
font = QtGui.QFont()
font.setPointSize(14)
self.pwr_on_lbl.setFont(font)
self.pwr_on_lbl.setObjectName("pwr_on_lbl")
self.pwr_on_layout.addWidget(self.pwr_on_lbl)
self.pwr_on_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.pwr_on_btn.setObjectName("pwr_on_btn")
self.pwr_on_layout.addWidget(self.pwr_on_btn)
self.pwr_on_layout.setStretch(0, 5)
self.pwr_on_layout.setStretch(1, 4)
self.cfg_pd_mon_form_layout.addLayout(self.pwr_on_layout)
self.close_btn_layout = QtWidgets.QHBoxLayout()
self.close_btn_layout.setSpacing(12)
self.close_btn_layout.setObjectName("close_btn_layout")
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.close_btn_layout.addItem(spacerItem4)
self.close_btn = QtWidgets.QPushButton(parent=self.verticalLayoutWidget_2)
self.close_btn.setObjectName("close_btn")
self.close_btn_layout.addWidget(self.close_btn)
self.close_btn_layout.setStretch(0, 5)
self.close_btn_layout.setStretch(1, 4)
self.cfg_pd_mon_form_layout.addLayout(self.close_btn_layout)
self.cfg_pd_mon_form_layout.setStretch(1, 2)
self.cfg_pd_mon_form_layout.setStretch(2, 2)
self.cfg_pd_mon_form_layout.setStretch(3, 2)
self.cfg_pd_mon_form_layout.setStretch(4, 2)
self.cfg_pd_mon_form_layout.setStretch(5, 2)
self.cfg_pd_mon_form_layout.setStretch(6, 1)
self.retranslateUi(Cfg_Pd_Mon_Form)
self.close_btn.clicked.connect(Cfg_Pd_Mon_Form.accept) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Cfg_Pd_Mon_Form)
def retranslateUi(self, Cfg_Pd_Mon_Form):
_translate = QtCore.QCoreApplication.translate
Cfg_Pd_Mon_Form.setWindowTitle(_translate("Cfg_Pd_Mon_Form", "config_pd_mon_form"))
self.title_lbl.setText(_translate("Cfg_Pd_Mon_Form", "Configure Photodiode Monitor"))
self.pwr_off_lbl.setText(_translate("Cfg_Pd_Mon_Form", " Step 1: Turn off Laser Power"))
self.pwr_off_btn.setText(_translate("Cfg_Pd_Mon_Form", "Power Off"))
self.rst_ld_pwr_limit_lbl.setText(_translate("Cfg_Pd_Mon_Form", " Step 2: Reset Ld Pwr Limit to 0"))
self.rst_ld_pwr_limit_btn.setText(_translate("Cfg_Pd_Mon_Form", "Reset Ld Pwr Limit"))
self.cfg_pd_params_lbl.setText(_translate("Cfg_Pd_Mon_Form", " Step 3: Configure Photodiode Parameters"))
self.label_2.setText(_translate("Cfg_Pd_Mon_Form", " Value"))
self.label.setText(_translate("Cfg_Pd_Mon_Form", "Reading"))
self.cfg_responsitivity_lbl.setText(_translate("Cfg_Pd_Mon_Form", "Responsitivity: "))
self.cfg_responsitivity_reading.setText(_translate("Cfg_Pd_Mon_Form", "0.0000"))
self.cfg_dark_current_lbl.setText(_translate("Cfg_Pd_Mon_Form", "Dark Current: "))
self.cfg_dark_current_reading.setText(_translate("Cfg_Pd_Mon_Form", "0.0000"))
self.apply_pd_params_btn.setText(_translate("Cfg_Pd_Mon_Form", "Apply"))
self.cfg_pd_pwr_limit_lbl.setText(_translate("Cfg_Pd_Mon_Form", " Step 4: Configure Laser Diode Power Limit"))
self.label_3.setText(_translate("Cfg_Pd_Mon_Form", " Value"))
self.label_4.setText(_translate("Cfg_Pd_Mon_Form", "Reading"))
self.cfg_pwr_limit_lbl.setText(_translate("Cfg_Pd_Mon_Form", "Power Limit:"))
self.cfg_pwr_limit_reading.setText(_translate("Cfg_Pd_Mon_Form", "0.0000"))
self.settable_pwr_range_lbl.setText(_translate("Cfg_Pd_Mon_Form", "Settable Power Range:"))
self.settable_pwr_range_display_lbl.setText(_translate("Cfg_Pd_Mon_Form", "( Power Range )"))
self.apply_pwr_limit_max_btn.setText(_translate("Cfg_Pd_Mon_Form", "Apply Max"))
self.apply_pwr_limit_btn.setText(_translate("Cfg_Pd_Mon_Form", "Apply"))
self.pwr_on_lbl.setText(_translate("Cfg_Pd_Mon_Form", " Step 5: Turn On Laser Power"))
self.pwr_on_btn.setText(_translate("Cfg_Pd_Mon_Form", "Clear Alarm and Power On"))
self.close_btn.setText(_translate("Cfg_Pd_Mon_Form", "Close"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Cfg_Pd_Mon_Form = QtWidgets.QDialog()
ui = Ui_Cfg_Pd_Mon_Form()
ui.setupUi(Cfg_Pd_Mon_Form)
Cfg_Pd_Mon_Form.show()
sys.exit(app.exec())

View File

@ -2,6 +2,7 @@ use core::marker::PhantomData;
use log::info;
use miniconf::Tree;
use num_traits::Zero;
use serde::{Deserialize, Serialize};
use stm32f4xx_hal::{pac::{ADC3, TIM2},
timer::CounterUs};
@ -42,6 +43,7 @@ struct Settings {
pd_mon_params: pd_mon_params::Parameters,
ld_pwr_limit: Power,
ld_terms_short: bool,
incoming_pd_mon_params: pd_mon_params::Parameters,
}
impl Default for Settings {
@ -51,6 +53,7 @@ impl Default for Settings {
default_pwr_on: false,
ld_drive_current: ElectricCurrent::new::<milliampere>(0.0),
pd_mon_params: pd_mon_params::Parameters::default(),
incoming_pd_mon_params: pd_mon_params::Parameters::default(),
ld_pwr_limit: Power::new::<milliwatt>(0.0),
ld_terms_short: false,
}
@ -181,24 +184,51 @@ impl LdDrive {
}
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
self.settings.pd_mon_params.set(responsitivity);
self.set_ld_power_limit(self.settings.ld_pwr_limit)
self.settings.incoming_pd_mon_params.set_responsitivity(responsitivity);
}
pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) {
self.settings.pd_mon_params.set_i_dark(i_dark);
self.set_ld_power_limit(self.settings.ld_pwr_limit)
self.settings.incoming_pd_mon_params.set_i_dark(i_dark);
}
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) {
LdPwrExcProtector::set_trigger_threshold_v(
pub fn apply_pd_params(&mut self) -> bool {
let prev_pd_params = self.settings.pd_mon_params;
self.settings.incoming_pd_mon_params.transconductance = self.settings.pd_mon_params.transconductance;
self.settings.pd_mon_params = self.settings.incoming_pd_mon_params;
let max_settable_pwr = self.get_ld_power_limit_range();
let is_legal = self.settings.ld_pwr_limit <= max_settable_pwr;
if is_legal {
self.set_ld_power_limit(self.settings.ld_pwr_limit);
} else {
self.settings.pd_mon_params = prev_pd_params;
}
is_legal
}
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) -> bool {
let is_legal = LdPwrExcProtector::set_trigger_threshold_v(
self.settings.pd_mon_params.get_pd_i_from_ld_pwr(pwr_limit) / self.settings.pd_mon_params.transconductance,
);
self.settings.ld_pwr_limit = pwr_limit;
if is_legal {
self.settings.ld_pwr_limit = pwr_limit;
}
is_legal
}
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) {
LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance);
pub fn get_ld_power_limit_range(&mut self) -> Power {
let v_range = LdPwrExcProtector::get_settable_volt_range();
let i_range = self.settings.pd_mon_params.get_pd_i_from_pd_v(v_range);
let max_settable_pwr = self.settings.pd_mon_params.get_ld_pwr_from_ld_i(i_range);
if max_settable_pwr.is_nan() || max_settable_pwr.is_infinite() {
Power::zero()
} else {
max_settable_pwr
}
}
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) -> bool {
return LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance);
}
pub fn set_default_pwr_on(&mut self, pwr_on: bool) {
@ -234,7 +264,10 @@ impl LdDrive {
max: Settings::LD_CURRENT_MAX,
},
pd_mon_params: settings.pd_mon_params,
ld_pwr_limit: settings.ld_pwr_limit,
ld_pwr_limit: LdSettingsSummaryField {
value: settings.ld_pwr_limit,
max: self.get_ld_power_limit_range(),
},
ld_terms_short: settings.ld_terms_short,
}
}
@ -243,10 +276,10 @@ impl LdDrive {
self.power_down();
self.settings.ld_drive_current = settings.ld_drive_current.value;
self.settings.pd_mon_params = settings.pd_mon_params;
self.settings.ld_pwr_limit = settings.ld_pwr_limit;
let max_pwr_limit = self.get_ld_power_limit_range();
self.settings.ld_pwr_limit = settings.ld_pwr_limit.value.min(max_pwr_limit);
self.settings.default_pwr_on = settings.default_pwr_on;
self.set_ld_power_limit(settings.ld_pwr_limit);
self.set_ld_power_limit(self.settings.ld_pwr_limit);
if self.settings.ld_terms_short {
self.ld_short();
@ -267,7 +300,7 @@ pub struct LdSettingsSummary {
default_pwr_on: bool,
ld_drive_current: LdSettingsSummaryField<ElectricCurrent>,
pd_mon_params: pd_mon_params::Parameters,
ld_pwr_limit: Power,
ld_pwr_limit: LdSettingsSummaryField<Power>,
ld_terms_short: bool,
}

View File

@ -1,4 +1,4 @@
use num_traits::Zero;
use num_traits::{Float, Zero};
use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
Adc},
gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull},
@ -167,14 +167,18 @@ impl LdPwrExcProtector {
ElectricPotential::new::<millivolt>(0.0)
}
pub fn set_trigger_threshold_v(htr: ElectricPotential) {
pub fn set_trigger_threshold_v(htr: ElectricPotential) -> bool {
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
let code: u32 = ((((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>()
* (MAX_SAMPLE as f32)) as u32)
+ wdg.offset)
.min(MAX_SAMPLE as u32);
wdg.pac.htr.write(|w| unsafe { w.bits(code) });
let code: u32 = (((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>()
* (MAX_SAMPLE as f32))
.ceil() as u32)
+ wdg.offset;
if code <= MAX_SAMPLE as u32 {
wdg.pac.htr.write(|w| unsafe { w.bits(code) });
return true;
}
}
false
}
pub fn set_calibrated_vdda(val: u32) {
@ -209,6 +213,15 @@ impl LdPwrExcProtector {
Status::default()
}
pub fn get_settable_volt_range() -> ElectricPotential {
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
return ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32)
* ((MAX_SAMPLE as u32 - wdg.offset) as f32)
/ MAX_SAMPLE as f32;
}
ElectricPotential::zero()
}
pub fn pwr_on_and_arm_protection() {
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
if !wdg.alarm_status.pwr_excursion {
@ -257,7 +270,8 @@ impl LdPwrExcProtector {
pub fn pwr_off() {
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
wdg.alarm_status.pwr_engaged = false;
wdg.phy.pwr_en_ch0.set_low()
wdg.phy.pwr_en_ch0.set_low();
LdPwrExcProtector::disable_watchdog_interrupt();
}
}

View File

@ -33,14 +33,22 @@ impl Parameters {
(v * self.transconductance).max(ElectricCurrent::zero())
}
pub fn set(&mut self, responsitivity: ResponsitivityUnit) {
pub fn set_responsitivity(&mut self, responsitivity: ResponsitivityUnit) {
self.responsitivity = responsitivity;
}
pub fn get_responsitivity(&mut self) -> ResponsitivityUnit {
self.responsitivity
}
pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) {
self.i_dark = i_dark;
}
pub fn get_i_dark(&mut self) -> ElectricCurrent {
self.i_dark
}
pub fn set_transconductance(&mut self, transconductance: ElectricalConductance) {
self.transconductance = transconductance;
}

View File

@ -167,7 +167,7 @@ fn main() -> ! {
}
net::net::for_each(|mut socket, id| {
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
if net::net::eth_is_socket_active(socket, true) && net::net::eth_is_socket_connected(socket) {
if active_report[id] {
if net::net::eth_can_sock_send(socket) {
net::cmd_handler::send_status_report(
@ -191,7 +191,7 @@ fn main() -> ! {
let mut oldest_connected_sock_id: usize = 0;
net::net::for_each(|mut socket, id| {
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
if net::net::eth_is_socket_active(socket, true) && net::net::eth_is_socket_connected(socket) {
if net::net::eth_can_sock_recv(socket) && net::net::eth_can_sock_send(socket) {
let bytes = net::net::eth_recv(eth_data_buffer, socket);
if bytes != 0 {
@ -289,7 +289,7 @@ fn main() -> ! {
laser.power_down();
thermostat.power_down();
net::net::for_each(|mut socket, _| {
if net::net::eth_is_socket_active(socket) {
if net::net::eth_is_socket_active(socket, false) {
net::cmd_handler::send_response(
eth_data_buffer,
net::cmd_handler::ResponseEnum::HardReset,
@ -308,7 +308,7 @@ fn main() -> ! {
laser.power_down();
thermostat.power_down();
net::net::for_each(|mut socket, _| {
if net::net::eth_is_socket_active(socket) {
if net::net::eth_is_socket_active(socket, false) {
net::cmd_handler::send_response(
eth_data_buffer,
net::cmd_handler::ResponseEnum::Dfu,
@ -326,7 +326,7 @@ fn main() -> ! {
thermostat.power_down();
let mut any_socket_alive = false;
net::net::for_each(|socket, _| {
if net::net::eth_is_socket_active(socket) {
if net::net::eth_is_socket_active(socket, false) {
net::net::eth_close_socket(socket);
any_socket_alive = true;
}

View File

@ -29,6 +29,7 @@ pub enum ResponseEnum {
HwRev,
Acknowledge,
InvalidDatatype,
InvalidSettings,
InvalidCmd,
HardReset,
Dfu,
@ -89,6 +90,7 @@ enum LdCmdEnum {
// PD Mon Related
SetPdResponsitivity,
SetPdDarkCurrent,
ApplyPdParams,
SetLdPwrLimit,
ClearAlarm,
}
@ -135,6 +137,8 @@ const ERR_MSG_MISSING_SINC5SINC1ODR: &str = "Required field \"sinc5sinc1odr\" do
const ERR_MSG_MISSING_SINC3ODR: &str = "Required field \"sinc3odr\" does not exist";
const ERR_MSG_MISSING_POSTFILTER: &str = "Required field \"PostFilter\" does not exist";
const ERR_MSG_MISSING_SINC3FINEODR: &str = "Required field \"sinc3fineodr\" does not exist";
const ERR_MSG_INVALID_PDMON_SETTINGS: &str = "Invalid PD Mon Parameter Setting(s)";
const ERR_MSG_INVALID_LD_PWR_LIMIT_SETTING: &str = "Invalid LD Power Limit Setting";
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
pub struct CmdJsonObj {
@ -453,12 +457,12 @@ pub fn execute_cmd(
},
Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 {
Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
laser.set_pd_responsitivity(ResponsitivityUnit {
dimension: PhantomData,
units: PhantomData,
value: val,
})
});
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
}
None => {
send_response(
@ -471,8 +475,8 @@ pub fn execute_cmd(
},
Some(LdCmdEnum::SetPdDarkCurrent) => match cmd.json.data_f32 {
Some(val) => {
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(val));
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(val))
}
None => {
send_response(
@ -483,10 +487,32 @@ pub fn execute_cmd(
);
}
},
Some(LdCmdEnum::ApplyPdParams) => {
let is_legal = laser.apply_pd_params();
if is_legal {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
} else {
send_response(
buffer,
ResponseEnum::InvalidSettings,
Some(ERR_MSG_INVALID_PDMON_SETTINGS),
socket,
)
}
}
Some(LdCmdEnum::SetLdPwrLimit) => match cmd.json.data_f32 {
Some(val) => {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
laser.set_ld_power_limit(Power::new::<watt>(val))
let is_legal = laser.set_ld_power_limit(Power::new::<watt>(val));
if is_legal {
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
} else {
send_response(
buffer,
ResponseEnum::InvalidSettings,
Some(ERR_MSG_INVALID_LD_PWR_LIMIT_SETTING),
socket,
)
}
}
None => {
send_response(

View File

@ -268,14 +268,16 @@ impl ServerHandle {
socket.state() == State::Established
}
pub fn poll_socket_status(&mut self, socket_handles: SocketHandle) -> bool {
pub fn poll_socket_status(&mut self, socket_handles: SocketHandle, reopen_sock: bool) -> bool {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
socket.abort();
socket.listen(self.socket_addr).ok();
info!("Disconnected... Reopening listening socket.");
if reopen_sock {
socket.abort();
socket.listen(self.socket_addr).ok();
info!("Disconnected... Reopening listening socket.");
}
return false;
} else if socket.state() == State::Closed || socket.state() == State::Closing {
} else if socket.state() == State::Closed || socket.state() == State::Closing || socket.is_listening() {
return false;
}
return true;
@ -485,10 +487,10 @@ pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool {
}
}
pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool {
pub fn eth_is_socket_active(socket_handles: SocketHandle, reopen_sock: bool) -> bool {
unsafe {
if let Some(ref mut server_handle) = SERVER_HANDLE {
server_handle.poll_socket_status(socket_handles)
server_handle.poll_socket_status(socket_handles, reopen_sock)
} else {
panic!("eth_is_socket_active is called before init");
}