From 572e2dbc5d9012c94c1636c6dbb02546f6ab8a34 Mon Sep 17 00:00:00 2001 From: linuswck Date: Mon, 5 Aug 2024 15:23:54 +0800 Subject: [PATCH] gui: update for the new driver code - Default to use active report mode - Connection will be retried upon abnormal disconnection - Remove poll every _s and apply btn --- pykirdy/driver/kirdy.py | 6 - pykirdy/kirdy_qt.py | 379 ++++++++++++++++++---------------------- pykirdy/ui/kirdy_qt.ui | 138 +-------------- 3 files changed, 173 insertions(+), 350 deletions(-) diff --git a/pykirdy/driver/kirdy.py b/pykirdy/driver/kirdy.py index d630181..b516792 100644 --- a/pykirdy/driver/kirdy.py +++ b/pykirdy/driver/kirdy.py @@ -152,12 +152,6 @@ class InvalidDataType(Exception): class InvalidCmd(Exception): pass -class NoAckRecv(Exception): - pass - -class StoppedConnecting(Exception): - pass - class Device: def __init__(self, send_cmd_handler, send_raw_cmd_handler, read_msg_queue): self._cmd = CmdList.device diff --git a/pykirdy/kirdy_qt.py b/pykirdy/kirdy_qt.py index 0e61492..eef9639 100644 --- a/pykirdy/kirdy_qt.py +++ b/pykirdy/kirdy_qt.py @@ -18,9 +18,9 @@ import os import argparse import logging import asyncio -from driver.kirdy_async import Kirdy, StoppedConnecting +from driver.kirdy import Kirdy as Kirdy_Driver import qasync -from qasync import asyncSlot, asyncClose +from qasync import asyncClose from collections import deque from datetime import datetime, timezone, timedelta from time import time @@ -68,77 +68,65 @@ def siConvert(val, suffix, typ=float): else: return v -class KirdyDataWatcher(QObject): - """ - This class provides various signals for Mainwindow to update various kinds of GUI objects - """ - connection_error_sig = pyqtSignal() +class Kirdy(QObject): + connected_sig = pyqtSignal(bool) setting_update_sig = pyqtSignal(dict) report_update_sig = pyqtSignal(dict) - - def __init__(self, parent, kirdy, update_s): - self._update_s = update_s - self._kirdy = kirdy - self._watch_task = None - self._report_mode_task = None - self._poll_for_report = True + + def __init__(self, parent, kirdy, _poll_interval): super().__init__(parent) + self._poll_interval = _poll_interval + self._kirdy = kirdy + self._kirdy.set_connected_sig(self.connected_sig) + self.connected_sig.connect(self.start_polling) + self.connected_sig.connect(self.connected_setup) - async def signal_emitter(self): - settings_summary = await self._kirdy.device.get_settings_summary() - self.setting_update_sig.emit(settings_summary) - if self._poll_for_report: - status_report = await self._kirdy.device.get_status_report() - self.report_update_sig.emit(status_report) - - async def run(self): - try: - task = asyncio.create_task(self.signal_emitter()) - while True: - if task.done(): - _ = task.result() - task = asyncio.create_task(self.signal_emitter()) - await asyncio.sleep(self._update_s) - except asyncio.CancelledError: - task.cancel() - except Exception as e: - logging.error(COMMON_ERROR_MSG) - self._kirdy.stop_report_mode() - self.connection_error_sig.emit() + self._kirdy.set_report_sig(self.report_update_sig) + self._timer = QtCore.QBasicTimer() - def start_watching(self): - self._watch_task = asyncio.create_task(self.run()) + def connected(self): + return self._kirdy.connected() - async def stop_watching(self): - if self._watch_task is not None: - self._watch_task.cancel() - await self._watch_task - self._watch_task = None - await self.set_report_mode(False) + def connecting(self): + return self._kirdy.connecting() - async def set_report_mode(self, enabled: bool): - self._poll_for_report = not enabled - if enabled: - self._report_mode_task = asyncio.create_task(self.report_mode()) + def start_session(self, host, port): + self._kirdy.start_session(host=host, port=port) + + def end_session(self): + if self._timer.isActive(): + self._timer.stop() + self._kirdy.end_session() + + @pyqtSlot(bool) + def connected_setup(self, connected): + if connected: + self._kirdy.device.set_active_report_mode(True) + + def timerEvent(self, event): + self._kirdy.device.get_settings_summary(sig=self.setting_update_sig) + + @pyqtSlot(bool) + def start_polling(self, start): + if start: + if not(self._timer.isActive()): + self._timer.start(int(self._poll_interval*1000), self) + else: + logging.debug("Kirdy Polling Timer has been started already.") else: - if self._report_mode_task is not None: - self._kirdy.stop_report_mode() - await self._report_mode_task - self._report_mode_task = None - - async def report_mode(self): - try: - async for status_report in self._kirdy.report_mode(): - if status_report["msg_type"] == "Exception": - raise TimeoutError("Connection Timeout") - self.report_update_sig.emit(status_report) - except Exception as e: - logging.error(f"{COMMON_ERROR_MSG}") - self.connection_error_sig.emit() + self._timer.stop() @pyqtSlot(float) - def set_update_s(self, update_s): - self._update_s = update_s + def set_update_s(self, interval): + self._poll_interval = interval + self.update_polling_rate() + + def update_polling_rate(self): + if self._timer.isActive(): + self._timer.stop() + self.start_polling() + else: + logging.debug("Attempt to update polling timer when it is stopped") class Graphs: def __init__(self, ld_i_set_graph, pd_mon_pwr_graph, tec_i_graph, tec_temp_graph, max_samples=1000): @@ -152,7 +140,7 @@ class Graphs: self._tec_i_target_plot = LiveLinePlot(name="Target", pen=pg.mkPen('r')) self._tec_i_measure_plot = LiveLinePlot(name="Measure", pen=pg.mkPen('g')) - self._temp_setpoint_line = tec_temp_graph.getPlotItem().addLine(label='{value} °C', pen=pg.mkPen('g')) + self._temp_setpoint_line = tec_temp_graph.getPlotItem().addLine(label='{value} ℃', pen=pg.mkPen('g')) # Render the temperature setpoint line on top of the temperature being plotted self._temp_setpoint_line.setZValue(10) self._temp_setpoint_line.setVisible(False) @@ -192,7 +180,7 @@ class Graphs: self.pd_mon_pwr_connector = DataConnector(self._pd_mon_pwr_plot, max_points=self.max_samples) self.connectors += [self.pd_mon_pwr_connector] - tec_temp_axis = LiveAxis('left', text="Temperature", units="°C") + tec_temp_axis = LiveAxis('left', text="Temperature", units="℃") tec_temp_axis.showLabel() tec_temp_graph.setAxisItems({'left': tec_temp_axis}) tec_temp_graph.addItem(self._tec_setpoint_plot) @@ -271,7 +259,7 @@ class Graphs: # PyQtGraph normally does not update this text when the line # is not visible, so make sure that the temperature label # gets updated always, and doesn't stay at an old value. - self._temp_setpoint_line.label.setText(f"{temp} °C", color='g') + self._temp_setpoint_line.label.setText(f"{temp} ℃", color='g') class MutexParameter(pTypes.ListParameter): """ @@ -386,7 +374,7 @@ class MainWindow(QtWidgets.QMainWindow): THERMOSTAT_PARAMETERS = [ {'name': 'Readings', 'expanded': True, 'type': 'group', 'children': [ - {'name': 'Temperature', 'type': 'float', 'format': '{value:.4f} °C', 'readonly': True}, + {'name': 'Temperature', 'type': 'float', 'format': '{value:.4f} ℃', 'readonly': True}, {'name': 'Current through TEC', 'type': 'float', 'suffix': 'A', 'siPrefix': True, 'decimals': 6, 'readonly': True}, ]}, {'name': 'Output Config', 'expanded': True, 'type': 'group', 'children': [ @@ -395,7 +383,7 @@ class MainWindow(QtWidgets.QMainWindow): {'name': 'Set Current', 'type': 'float', 'value': 0, 'step': 1, 'limits': (-1000, 1000), 'triggerOnShow': True, 'decimals': 6, 'unit': 'mA', 'lock': False, 'target': 'thermostat', 'action': 'set_tec_i_out'}, {'name': 'Set Temperature', 'type': 'float', 'value': 25, 'step': 0.0001, 'limits': (-273, 300), 'format': '{value:.4f}', - 'unit': '°C', 'lock': False, 'target': 'thermostat', 'action': 'set_temperature_setpoint'}, + 'unit': '℃', 'lock': False, 'target': 'thermostat', 'action': 'set_temperature_setpoint'}, ]}, {'name': 'Limits', 'expanded': False, 'type': 'group', 'children': [ {'name': 'Max Cooling Current', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (0, 1000), @@ -410,22 +398,22 @@ class MainWindow(QtWidgets.QMainWindow): # TODO Temperature ADC Filter Settings {'name': 'Temperature Monitor Config', 'expanded': False, 'type': 'group', 'children': [ {'name': 'Upper Limit', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (-273, 300), - 'unit': '°C', 'lock': False, 'target': 'thermostat', 'action': 'set_temp_mon_upper_limit'}, + 'unit': '℃', 'lock': False, 'target': 'thermostat', 'action': 'set_temp_mon_upper_limit'}, {'name': 'Lower Limit', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (-273, 300), - 'unit': '°C', 'lock': False, 'target': 'thermostat', 'action': 'set_temp_mon_lower_limit'}, + 'unit': '℃', 'lock': False, 'target': 'thermostat', 'action': 'set_temp_mon_lower_limit'}, ]}, {'name': 'Thermistor Settings','expanded': False, 'type': 'group', 'children': [ {'name': 'T₀', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'limits': (-273, 300), - 'unit': '°C', 'lock': False, 'target': 'thermostat', 'action': 'set_sh_t0'}, + 'unit': '℃', 'lock': False, 'target': 'thermostat', 'action': 'set_sh_t0'}, {'name': 'R₀', 'type': 'float', 'value': 0, 'step': 1, 'decimals': 6, 'unit': 'kΩ', 'lock': False, 'target': 'thermostat', 'action': 'set_sh_r0'}, {'name': 'B', 'type': 'float', 'value': 3950, 'step': 1, 'decimals': 4, 'unit': 'K', 'lock': False, 'target': 'thermostat', 'action': 'set_sh_beta'}, ]}, {'name': 'PID Config', 'expanded': False, 'type': 'group', 'children': [ - {'name': 'Kp', 'type': 'float', 'step': 0.1, 'lock': False, 'target': 'thermostat', 'action': 'set_pid_kp'}, - {'name': 'Ki', 'type': 'float', 'step': 0.1, 'unit': 'Hz', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_ki'}, - {'name': 'Kd', 'type': 'float', 'step': 0.1, 'unit': 's', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_kd'}, + {'name': 'Kp', 'type': 'float', 'step': 0.1, 'decimals': 16, 'lock': False, 'target': 'thermostat', 'action': 'set_pid_kp'}, + {'name': 'Ki', 'type': 'float', 'step': 0.1, 'decimals': 16, 'unit': 'Hz', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_ki'}, + {'name': 'Kd', 'type': 'float', 'step': 0.1, 'decimals': 16, 'unit': 's', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_kd'}, {'name': "PID Output Clamping", 'expanded': True, 'type': 'group', 'children': [ {'name': 'Minimum', 'type': 'float', 'step': 1, 'limits': (-1000, 1000), 'decimals': 6, 'unit': 'mA', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_output_min'}, @@ -433,9 +421,9 @@ class MainWindow(QtWidgets.QMainWindow): 'unit': 'mA', 'lock': False, 'target': 'thermostat', 'action': 'set_pid_output_max'}, ]}, {'name': 'PID Auto Tune', 'expanded': False, 'type': 'group', 'children': [ - {'name': 'Target Temperature', 'type': 'float', 'value': 20.0, 'step': 0.1, 'unit': '°C', 'format': '{value:.4f}'}, - {'name': 'Test Current', 'type': 'float', 'value': 1000, 'decimals': 6, 'step': 100, 'limits': (-3000, 3000), 'unit': 'mA'}, - {'name': 'Temperature Swing', 'type': 'float', 'value': 0.0, 'step': 0.001, 'prefix': '±', 'unit': '°C', 'format': '{value:.4f}'}, + {'name': 'Target Temperature', 'type': 'float', 'value': 20.0, 'step': 0.1, 'unit': '℃', 'format': '{value:.4f}'}, + {'name': 'Test Current', 'type': 'float', 'value': 1000, 'decimals': 6, 'step': 100, 'limits': (-1000, 1000), 'unit': 'mA'}, + {'name': 'Temperature Swing', 'type': 'float', 'value': 0.0, 'step': 0.0001, 'prefix': '±', 'unit': '℃', 'format': '{value:.4f}'}, {'name': 'Lookback', 'type': 'float', 'value': 5.0, 'step': 0.1, 'unit': 's', 'format': '{value:.4f}'}, {'name': 'Run', 'type': 'action', 'tip': 'Run'}, ]}, @@ -443,7 +431,7 @@ class MainWindow(QtWidgets.QMainWindow): ] def __init__(self, args): super(MainWindow, self).__init__() - self.kirdy = Kirdy() + self.kirdy = Kirdy_Driver() ui_file_path = importlib.resources.files("ui").joinpath("kirdy_qt.ui") uic.loadUi(ui_file_path, self) @@ -517,23 +505,19 @@ class MainWindow(QtWidgets.QMainWindow): self.pd_mon_pwr_graph.setTitle("PD Mon Power") self.connect_btn.clicked.connect(self.show_conn_settings_form) - self.report_box.stateChanged.connect(self.on_report_box_stateChanged) - self.kirdy_data_watcher = KirdyDataWatcher(self, self.kirdy, self.report_refresh_spin.value()) - self.kirdy_data_watcher.connection_error_sig.connect(self.bail) - # TODO: Identify the usable range of set_update_s - self.report_apply_btn.clicked.connect( - lambda: self.kirdy_data_watcher.set_update_s(self.report_refresh_spin.value()) - ) - self.kirdy_data_watcher.setting_update_sig.connect(self.update_ld_ctrl_panel_settings) - self.kirdy_data_watcher.setting_update_sig.connect(self.update_thermostat_ctrl_panel_settings) - self.kirdy_data_watcher.report_update_sig.connect(self.update_ld_ctrl_panel_readings) - self.kirdy_data_watcher.report_update_sig.connect(self.update_thermostat_ctrl_panel_readings) + self.kirdy_handler = Kirdy(self, self.kirdy, 1.0) + + self.kirdy_handler.setting_update_sig.connect(self.update_ld_ctrl_panel_settings) + 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.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_data_watcher.report_update_sig.connect(self.graphs.plot_append) + self.kirdy_handler.report_update_sig.connect(self.graphs.plot_append) self.loading_spinner.hide() + self.kirdy_handler.connected_sig.connect(self._on_connection_changed) def setup_menu_bar(self): @pyqtSlot(bool) @@ -560,20 +544,21 @@ class MainWindow(QtWidgets.QMainWindow): ) self.menu_action_about_gui.triggered.connect(about_gui) - @asyncSlot(bool) - async def dfu_mode(_): - await self.kirdy.device.dfu() - await self._on_connection_changed(False) + @pyqtSlot(bool) + def dfu_mode(_): + self.kirdy.device.dfu() + self.kirdy_handler.end_session() self.menu_action_dfu_mode.triggered.connect(dfu_mode) - @asyncSlot(bool) - async def reset_kirdy(_): - await self._on_connection_changed(False, hard_reset=True) + @pyqtSlot(bool) + def reset_kirdy(_): + self.kirdy.device.hard_reset() + self.kirdy_handler.end_session() self.menu_action_hard_reset.triggered.connect(reset_kirdy) - @asyncSlot(bool) - async def save_settings(_): - await self.kirdy.device.save_current_settings_to_flash() + @pyqtSlot(bool) + def save_settings(_): + self.kirdy.device.save_current_settings_to_flash() saved = QtWidgets.QMessageBox(self) saved.setWindowTitle("Config saved") saved.setText(f"Laser diode and thermostat configs have been saved into flash.") @@ -581,9 +566,9 @@ class MainWindow(QtWidgets.QMainWindow): saved.show() self.menu_action_save.triggered.connect(save_settings) - @asyncSlot(bool) - async def load_settings(_): - await self.kirdy.device.restore_settings_from_flash() + @pyqtSlot(bool) + def load_settings(_): + self.kirdy.device.restore_settings_from_flash() loaded = QtWidgets.QMessageBox(self) loaded.setWindowTitle("Config loaded") loaded.setText(f"Laser Diode and Thermostat configs have been loaded from flash.") @@ -591,8 +576,8 @@ class MainWindow(QtWidgets.QMainWindow): loaded.show() self.menu_action_load.triggered.connect(load_settings) - @asyncSlot(bool) - async def show_update_net_settings_form(_): + @pyqtSlot(bool) + def show_update_net_settings_form(_): self.update_net_settings_form.retranslateUi(self.update_net_settings_form) self.update_net_settings_form.show() self.menu_action_update_net_settings.triggered.connect(show_update_net_settings_form) @@ -607,34 +592,34 @@ class MainWindow(QtWidgets.QMainWindow): self.conn_settings_form.show() def _set_up_ctrl_btns(self): - @asyncSlot(bool) - async def ld_pwr_on(_): - await self.kirdy.laser.set_power_on(True) + @pyqtSlot(bool) + def ld_pwr_on(_): + self.kirdy.laser.set_power_on(True) self.ld_pwr_on_btn.clicked.connect(ld_pwr_on) - @asyncSlot(bool) - async def ld_pwr_off(_): - await self.kirdy.laser.set_power_on(False) + @pyqtSlot(bool) + def ld_pwr_off(_): + self.kirdy.laser.set_power_on(False) self.ld_pwr_off_btn.clicked.connect(ld_pwr_off) - @asyncSlot(bool) - async def ld_clear_alarm(_): - await self.kirdy.laser.clear_alarm() + @pyqtSlot(bool) + def ld_clear_alarm(_): + self.kirdy.laser.clear_alarm() self.ld_clear_alarm_btn.clicked.connect(ld_clear_alarm) - @asyncSlot(bool) - async def tec_pwr_on(_): - await self.kirdy.thermostat.set_power_on(True) + @pyqtSlot(bool) + def tec_pwr_on(_): + self.kirdy.thermostat.set_power_on(True) self.tec_pwr_on_btn.clicked.connect(tec_pwr_on) - @asyncSlot(bool) - async def tec_pwr_off(_): - await self.kirdy.thermostat.set_power_on(False) + @pyqtSlot(bool) + def tec_pwr_off(_): + self.kirdy.thermostat.set_power_on(False) self.tec_pwr_off_btn.clicked.connect(tec_pwr_off) - @asyncSlot(bool) - async def tec_clear_alarm(_): - await self.kirdy.thermostat.clear_alarm() + @pyqtSlot(bool) + def tec_clear_alarm(_): + self.kirdy.thermostat.clear_alarm() self.tec_clear_alarm_btn.clicked.connect(tec_clear_alarm) def _set_up_plot_menu(self): @@ -678,11 +663,11 @@ class MainWindow(QtWidgets.QMainWindow): tree.setParameters(self.params[3], showTop=False) self.params[3].sigTreeStateChanged.connect(self.send_command) - @asyncSlot() - async def autotune(param): + @pyqtSlot() + def autotune(param): match self.autotuner.state(): case PIDAutotuneState.STATE_OFF: - settings = await self.kirdy.device.get_settings_summary() + settings = self.kirdy.device.get_settings_summary() self.autotuner.setParam( param.parent().child('Target Temperature').value(), param.parent().child('Test Current').value() / 1000, @@ -691,37 +676,37 @@ class MainWindow(QtWidgets.QMainWindow): param.parent().child('Lookback').value()) self.autotuner.setReady() param.setOpts(title="Stop") - await self.kirdy.thermostat.set_constant_current_control_mode() - self.kirdy_data_watcher.report_update_sig.connect(self.autotune_tick) + self.kirdy.thermostat.set_constant_current_control_mode() + self.kirdy_handler.report_update_sig.connect(self.autotune_tick) self.loading_spinner.show() self.loading_spinner.start() self.background_task_lbl.setText("Autotuning") case PIDAutotuneState.STATE_READY | PIDAutotuneState.STATE_RELAY_STEP_UP | PIDAutotuneState.STATE_RELAY_STEP_DOWN: self.autotuner.setOff() param.setOpts(title="Run") - await self.kirdy.thermostat.set_tec_i_out(0.0) - self.kirdy_data_watcher.report_update_sig.disconnect(self.autotune_tick) + self.kirdy.thermostat.set_tec_i_out(0.0) + self.kirdy_handler.report_update_sig.disconnect(self.autotune_tick) self.background_task_lbl.setText("Ready.") self.loading_spinner.stop() self.loading_spinner.hide() self.params[3].child('PID Config', 'PID Auto Tune', 'Run').sigActivated.connect(autotune) - @asyncSlot(dict) - async def autotune_tick(self, report): + @pyqtSlot(dict) + def autotune_tick(self, report): match self.autotuner.state(): case PIDAutotuneState.STATE_READY | PIDAutotuneState.STATE_RELAY_STEP_UP | PIDAutotuneState.STATE_RELAY_STEP_DOWN: self.autotuner.run(report['thermostat']['temperature'], report['ts']/1000) - await self.kirdy.thermostat.set_tec_i_out(self.autotuner.output()) + self.kirdy.thermostat.set_tec_i_out(self.autotuner.output()) case PIDAutotuneState.STATE_SUCCEEDED: kp, ki, kd = self.autotuner.get_tec_pid() self.autotuner.setOff() self.params[3].child('PID Config', 'PID Auto Tune', 'Run').setOpts(title="Run") - await self.kirdy.thermostat.set_pid_kp(kp) - await self.kirdy.thermostat.set_pid_ki(ki) - await self.kirdy.thermostat.set_pid_kd(kd) - await self.kirdy.thermostat.set_pid_control_mode() - await self.kirdy.thermostat.set_temperature_setpoint(self.params[3].child('PID Config', 'PID Auto Tune', 'Target Temperature').value()) - self.kirdy_data_watcher.report_update_sig.disconnect(self.autotune_tick) + self.kirdy.thermostat.set_pid_kp(kp) + self.kirdy.thermostat.set_pid_ki(ki) + self.kirdy.thermostat.set_pid_kd(kd) + self.kirdy.thermostat.set_pid_control_mode() + self.kirdy.thermostat.set_temperature_setpoint(self.params[3].child('PID Config', 'PID Auto Tune', 'Target Temperature').value()) + self.kirdy_handler.report_update_sig.disconnect(self.autotune_tick) self.background_task_lbl.setText("Ready.") self.loading_spinner.stop() self.loading_spinner.hide() @@ -732,8 +717,8 @@ class MainWindow(QtWidgets.QMainWindow): case PIDAutotuneState.STATE_FAILED: self.autotuner.setOff() self.params[3].child('PID Config', 'PID Auto Tune', 'Run').setOpts(title="Run") - await self.kirdy.thermostat.set_tec_i_out(0.0) - self.kirdy_data_watcher.report_update_sig.disconnect(self.autotune_tick) + self.kirdy.thermostat.set_tec_i_out(0.0) + self.kirdy_handler.report_update_sig.disconnect(self.autotune_tick) self.background_task_lbl.setText("Ready.") self.loading_spinner.stop() self.loading_spinner.hide() @@ -741,7 +726,8 @@ class MainWindow(QtWidgets.QMainWindow): self.info_box.setText("PID Autotune is failed.") self.info_box.show() - async def _on_connection_changed(self, result, hard_reset=False): + @pyqtSlot(bool) + def _on_connection_changed(self, result): def ctrl_panel_setEnable(result): self.ld_status.setEnabled(result) self.ld_tree.setEnabled(result) @@ -773,50 +759,41 @@ class MainWindow(QtWidgets.QMainWindow): self.tec_temp_graph.setEnabled(result) graph_group_setEnable(result) - self.report_refresh_spin.setEnabled(result) self.report_group.setEnabled(result) - self.report_refresh_spin.setEnabled(result) - self.report_box.setEnabled(result) - self.report_apply_btn.setEnabled(result) - # TODO: Use QStateMachine to manage connections self.connect_btn.clicked.disconnect() if result: self.connect_btn.setText("Disconnect") - self.connect_btn.clicked.connect(self.bail) - else: - self.connect_btn.setText("Connect") - self.connect_btn.clicked.connect(self.show_conn_settings_form) - - if result: - # TODO: self.hw_rev_data = await self.kirdy.hw_rev() + self.connect_btn.clicked.connect(self.kirdy_handler.end_session) + # TODO: self.hw_rev_data = self.kirdy.hw_rev() self._status() - self.kirdy_data_watcher.start_watching() else: - self.clear_graphs() - self.report_box.setChecked(False) - await self.kirdy_data_watcher.stop_watching() - if hard_reset: - await self.kirdy.device.hard_reset() - await self.kirdy.end_session() - self.status_lbl.setText("Disconnected") + if self.kirdy_handler.connecting(): + self.status_lbl.setText(f"Connection is dropped. Reconnecting to {self.ip_addr}:{self.port}.") + self.connect_btn.setText("Stop") + else: + self.connect_btn.setText("Connect") + self.connect_btn.clicked.connect(self.show_conn_settings_form) + self.clear_graphs() + self.status_lbl.setText(f"Disconnected from {self.ip_addr}:{self.port}.") + self.connect_btn.clicked.connect(self.kirdy_handler.end_session) def _status(self): # TODO: Get rev no from Kirdy and then add revision into the text host = self.ip_addr port = self.port - self.status_lbl.setText(f"Connected to Kirdy @ {host}:{port}") + self.status_lbl.setText(f"Connected to {host}:{port}") def clear_graphs(self): self.graphs.clear_data_pts() - @asyncSlot(dict) - async def graphs_update(self, report): + @pyqtSlot(dict) + def graphs_update(self, report): self.graphs.plot_append(report) - @asyncSlot(dict) - async def update_ld_ctrl_panel_settings(self, settings): + @pyqtSlot(dict) + def update_ld_ctrl_panel_settings(self, settings): try: settings = settings['laser'] with QSignalBlocker(self.params[1]): @@ -832,8 +809,8 @@ class MainWindow(QtWidgets.QMainWindow): except Exception as e: logging.error(f"Params tree cannot be updated. Data:{settings}", exc_info=True) - @asyncSlot(dict) - async def update_ld_ctrl_panel_readings(self, report): + @pyqtSlot(dict) + def update_ld_ctrl_panel_readings(self, report): try: report = report['laser'] with QSignalBlocker(self.params[0]): @@ -851,8 +828,8 @@ class MainWindow(QtWidgets.QMainWindow): except Exception as e: logging.error(f"Params tree cannot be updated. Data:{report}", exc_info=True) - @asyncSlot(dict) - async def update_thermostat_ctrl_panel_settings(self, settings): + @pyqtSlot(dict) + def update_thermostat_ctrl_panel_settings(self, settings): try: settings = settings['thermostat'] with QSignalBlocker(self.params[3]): @@ -879,8 +856,8 @@ class MainWindow(QtWidgets.QMainWindow): except Exception as e: logging.error(f"Params tree cannot be updated. Data:{settings}", exc_info=True) - @asyncSlot(dict) - async def update_thermostat_ctrl_panel_readings(self, report): + @pyqtSlot(dict) + def update_thermostat_ctrl_panel_readings(self, report): try: report = report['thermostat'] with QSignalBlocker(self.params[2]): @@ -899,12 +876,9 @@ class MainWindow(QtWidgets.QMainWindow): def set_max_samples(self, samples: int): self.graphs.set_max_samples(samples) - @asyncSlot(int) - async def on_report_box_stateChanged(self, enabled): - await self.kirdy_data_watcher.set_report_mode(enabled) - @asyncSlot() - async def update_net_settings(self): + @pyqtSlot() + def update_net_settings(self): net_settings = self.update_net_settings_form.get_net_settings() if net_settings is None: self.status_lbl.setText("Invalid IP Settings Input") @@ -913,11 +887,11 @@ class MainWindow(QtWidgets.QMainWindow): port = net_settings["port"] prefix_len = net_settings["prefix_len"] gateway = net_settings["gateway_addr"] - await self.kirdy.device.set_ip_settings(addr, port, prefix_len, gateway) + self.kirdy.device.set_ip_settings(addr, port, prefix_len, gateway) self.status_lbl.setText("IP Settings is Updated") - @asyncSlot() - async def start_connecting(self): + @pyqtSlot() + def start_connecting(self): net_settings = self.conn_settings_form.get_net_settings() if net_settings is None: self.status_lbl.setText("Invalid IP Settings Input") @@ -927,25 +901,17 @@ class MainWindow(QtWidgets.QMainWindow): host = self.ip_addr port = self.port - try: - if not (self.kirdy.connecting() or self.kirdy.connected()): - self.status_lbl.setText("Connecting...") - await self.kirdy.start_session(host=host, port=port, timeout=5.0) - await self._on_connection_changed(True) - else: - await self.bail() - except (OSError, TimeoutError, ConnectionResetError) as e: - logging.error(f"Failed communicating to {host}:{port}: {e}") - await self.bail() - self.status_lbl.setText(f"Cannot connect to Kirdy@ {host}:{port}") - @asyncSlot() - async def bail(self): - await self._on_connection_changed(False) - await self.kirdy.end_session() + if not (self.kirdy_handler.connecting() or self.kirdy_handler.connected()): + self.status_lbl.setText("Connecting...") + self.kirdy_handler.start_session(host=host, port=port) - @asyncSlot(object, object) - async def send_command(self, param, changes): + self.connect_btn.setText("Stop") + self.connect_btn.clicked.disconnect() + self.connect_btn.clicked.connect(self.kirdy_handler.end_session) + + @pyqtSlot(object, object) + def send_command(self, param, changes): for inner_param, change, data in changes: if change == 'value': """ cmd translation from mutex type parameter """ @@ -953,7 +919,7 @@ class MainWindow(QtWidgets.QMainWindow): target, action = inner_param.opts['target_action_pair'][inner_param.opts['limits'].index(data)] cmd = getattr(getattr(self.kirdy, target), action) param.child(*param.childPath(inner_param)).setOpts(lock=True) - await cmd() + cmd() param.child(*param.childPath(inner_param)).setOpts(lock=False) continue """ cmd translation from non-mutex type parameter""" @@ -964,28 +930,25 @@ class MainWindow(QtWidgets.QMainWindow): data = siEval(str(data)+inner_param.opts["unit"], regex=FLOAT_REGEX, suffix=suffix) cmd = getattr(getattr(self.kirdy, inner_param.opts["target"]), inner_param.opts["action"]) param.child(*param.childPath(inner_param)).setOpts(lock=True) - await cmd(data) + cmd(data) param.child(*param.childPath(inner_param)).setOpts(lock=False) continue -async def coro_main(): +def coro_main(): args = get_argparser().parse_args() if args.logLevel: logging.basicConfig(level=getattr(logging, args.logLevel)) - app_quit_event = asyncio.Event() - - app = QtWidgets.QApplication.instance() - app.aboutToQuit.connect(app_quit_event.set) + app = QtWidgets.QApplication(sys.argv) main_window = MainWindow(args) main_window.show() - await app_quit_event.wait() + app.aboutToQuit.connect(main_window.kirdy_handler.end_session) + app.exec() def main(): - qasync.run(coro_main()) - + coro_main() if __name__ == '__main__': main() diff --git a/pykirdy/ui/kirdy_qt.ui b/pykirdy/ui/kirdy_qt.ui index ec0c568..2554f78 100644 --- a/pykirdy/ui/kirdy_qt.ui +++ b/pykirdy/ui/kirdy_qt.ui @@ -351,13 +351,13 @@ - 360 + 480 0 - 360 + 480 16777215 @@ -448,140 +448,6 @@ 0 - - - - 6 - - - QLayout::SizeConstraint::SetDefaultConstraint - - - 0 - - - - - Poll every: - - - Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter - - - - - - - false - - - - 0 - 0 - - - - - 70 - 0 - - - - - 70 - 16777215 - - - - - 70 - 0 - - - - s - - - 1 - - - 0.100000000000000 - - - 0.100000000000000 - - - QAbstractSpinBox::StepType::AdaptiveDecimalStepType - - - 1.000000000000000 - - - - - - - false - - - - 0 - 0 - - - - - 80 - 16777215 - - - - - 80 - 0 - - - - Report - - - - - - - false - - - - 0 - 0 - - - - - 80 - 0 - - - - - 80 - 16777215 - - - - - 80 - 0 - - - - Apply - - - - -