|
13 | 13 | import os |
14 | 14 | import sys |
15 | 15 | import time |
16 | | -from typing import Union |
17 | 16 |
|
18 | 17 | import qtpy |
19 | 18 | from qtpy import QtCore, QtGui, QtWidgets as QtWid |
|
26 | 25 | from dvg_pyqtgraph_threadsafe import HistoryChartCurve, PlotManager |
27 | 26 | from dvg_pyqt_filelogger import FileLogger |
28 | 27 | import dvg_pyqt_controls as controls |
29 | | -from dvg_qdeviceio import QDeviceIO, DAQ_TRIGGER |
30 | 28 |
|
31 | 29 | from WaveGeneratorArduino import WaveGeneratorArduino, FakeWaveGeneratorArduino |
| 30 | +from WaveGeneratorArduino_qdev import WaveGeneratorArduino_qdev |
32 | 31 |
|
33 | | -# fmt: off |
34 | 32 | # Constants |
35 | | -DAQ_INTERVAL_MS = 10 # 10 [ms] |
36 | | -CHART_INTERVAL_MS = 20 # 20 [ms] |
37 | | -CHART_HISTORY_TIME = 10 # 10 [s] |
| 33 | +DAQ_INTERVAL_MS = 10 |
| 34 | +"""[ms] Update interval for the data acquisition (DAQ)""" |
| 35 | +CHART_INTERVAL_MS = 20 |
| 36 | +"""[ms] Update interval for the chart""" |
| 37 | +CHART_HISTORY_TIME = 10 |
| 38 | +"""[s] History length of the chart""" |
38 | 39 |
|
39 | 40 | # Global flags |
| 41 | +# fmt: off |
40 | 42 | TRY_USING_OPENGL = True |
41 | 43 | USE_LARGER_TEXT = False # For demonstration on a beamer |
42 | 44 | USE_PC_TIME = True # Use Arduino time or PC time? |
@@ -83,86 +85,6 @@ def current_date_time_strings(): |
83 | 85 | ) |
84 | 86 |
|
85 | 87 |
|
86 | | -# ------------------------------------------------------------------------------ |
87 | | -# WaveGeneratorArduino_qdev |
88 | | -# ------------------------------------------------------------------------------ |
89 | | - |
90 | | - |
91 | | -class WaveGeneratorArduino_qdev(QDeviceIO): |
92 | | - """Manages multithreaded communication and periodical data acquisition for |
93 | | - a wave generator Arduino, referred to as the 'device'.""" |
94 | | - |
95 | | - def __init__( |
96 | | - self, |
97 | | - dev: Union[WaveGeneratorArduino, FakeWaveGeneratorArduino], |
98 | | - DAQ_interval_ms=DAQ_INTERVAL_MS, |
99 | | - DAQ_timer_type=QtCore.Qt.TimerType.PreciseTimer, |
100 | | - critical_not_alive_count=1, |
101 | | - debug=False, |
102 | | - **kwargs, |
103 | | - ): |
104 | | - super().__init__(dev, **kwargs) # Pass kwargs onto QtCore.QObject() |
105 | | - self.dev: WaveGeneratorArduino # Enforce type: removes `_NoDevice()` |
106 | | - |
107 | | - self.create_worker_DAQ( |
108 | | - DAQ_trigger=DAQ_TRIGGER.INTERNAL_TIMER, |
109 | | - DAQ_function=self.DAQ_function, |
110 | | - DAQ_interval_ms=DAQ_interval_ms, |
111 | | - DAQ_timer_type=DAQ_timer_type, |
112 | | - critical_not_alive_count=critical_not_alive_count, |
113 | | - debug=debug, |
114 | | - ) |
115 | | - self.create_worker_jobs(debug=debug) |
116 | | - |
117 | | - def set_waveform_to_sine(self): |
118 | | - self.send(self.dev.set_waveform_to_sine) |
119 | | - |
120 | | - def set_waveform_to_square(self): |
121 | | - self.send(self.dev.set_waveform_to_square) |
122 | | - |
123 | | - def set_waveform_to_sawtooth(self): |
124 | | - self.send(self.dev.set_waveform_to_sawtooth) |
125 | | - |
126 | | - # -------------------------------------------------------------------------- |
127 | | - # DAQ_function |
128 | | - # -------------------------------------------------------------------------- |
129 | | - |
130 | | - def DAQ_function(self) -> bool: |
131 | | - # Query the Arduino for its state |
132 | | - success, tmp_state = self.dev.query_ascii_values("?", delimiter="\t") |
133 | | - if not success: |
134 | | - str_cur_date, str_cur_time = current_date_time_strings() |
135 | | - dprint( |
136 | | - f"'{self.dev.name}' reports IOError @ " |
137 | | - f"{str_cur_date} {str_cur_time}" |
138 | | - ) |
139 | | - return False |
140 | | - |
141 | | - # Parse readings into separate state variables |
142 | | - try: |
143 | | - self.dev.state.time, self.dev.state.reading_1 = tmp_state |
144 | | - self.dev.state.time /= 1000 |
145 | | - except Exception as err: # pylint: disable=broad-except |
146 | | - pft(err, 3) |
147 | | - str_cur_date, str_cur_time = current_date_time_strings() |
148 | | - dprint( |
149 | | - f"'{self.dev.name}' reports IOError @ " |
150 | | - f"{str_cur_date} {str_cur_time}" |
151 | | - ) |
152 | | - return False |
153 | | - |
154 | | - # Use Arduino time or PC time? |
155 | | - now = time.perf_counter() if USE_PC_TIME else self.dev.state.time |
156 | | - if self.update_counter_DAQ == 1: |
157 | | - self.dev.state.time_0 = now |
158 | | - self.dev.state.time = 0 |
159 | | - else: |
160 | | - self.dev.state.time = now - self.dev.state.time_0 |
161 | | - |
162 | | - # Return success |
163 | | - return True |
164 | | - |
165 | | - |
166 | 88 | # ------------------------------------------------------------------------------ |
167 | 89 | # MainWindow |
168 | 90 | # ------------------------------------------------------------------------------ |
@@ -340,12 +262,16 @@ def __init__( |
340 | 262 |
|
341 | 263 | # 'Wave type' |
342 | 264 | self.qpbt_wave_sine = QtWid.QPushButton("Sine") |
343 | | - self.qpbt_wave_sine.clicked.connect(self.qdev.set_waveform_to_sine) |
| 265 | + self.qpbt_wave_sine.clicked.connect( |
| 266 | + self.qdev.request_set_waveform_to_sine |
| 267 | + ) |
344 | 268 | self.qpbt_wave_square = QtWid.QPushButton("Square") |
345 | | - self.qpbt_wave_square.clicked.connect(self.qdev.set_waveform_to_square) |
| 269 | + self.qpbt_wave_square.clicked.connect( |
| 270 | + self.qdev.request_set_waveform_to_square |
| 271 | + ) |
346 | 272 | self.qpbt_wave_sawtooth = QtWid.QPushButton("Sawtooth") |
347 | 273 | self.qpbt_wave_sawtooth.clicked.connect( |
348 | | - self.qdev.set_waveform_to_sawtooth |
| 274 | + self.qdev.request_set_waveform_to_sawtooth |
349 | 275 | ) |
350 | 276 |
|
351 | 277 | # fmt: off |
@@ -508,7 +434,55 @@ def update_chart(self): |
508 | 434 | # Set up multithreaded communication with the Arduino |
509 | 435 | # -------------------------------------------------------------------------- |
510 | 436 |
|
511 | | - ard_qdev = WaveGeneratorArduino_qdev(dev=ard, debug=DEBUG) |
| 437 | + def DAQ_function() -> bool: |
| 438 | + # Query the Arduino for its state |
| 439 | + success, tmp_state = ard.query_ascii_values("?", delimiter="\t") |
| 440 | + if not success: |
| 441 | + str_cur_date, str_cur_time = current_date_time_strings() |
| 442 | + dprint( |
| 443 | + f"'{ard.name}' reports IOError @ " |
| 444 | + f"{str_cur_date} {str_cur_time}" |
| 445 | + ) |
| 446 | + return False |
| 447 | + |
| 448 | + # Parse readings into separate state variables |
| 449 | + try: |
| 450 | + ard.state.time, ard.state.reading_1 = tmp_state |
| 451 | + ard.state.time /= 1000 |
| 452 | + except Exception as err: # pylint: disable=broad-except |
| 453 | + pft(err, 3) |
| 454 | + str_cur_date, str_cur_time = current_date_time_strings() |
| 455 | + dprint( |
| 456 | + f"'{ard.name}' reports IOError @ " |
| 457 | + f"{str_cur_date} {str_cur_time}" |
| 458 | + ) |
| 459 | + return False |
| 460 | + |
| 461 | + # Use Arduino time or PC time? |
| 462 | + now = time.perf_counter() if USE_PC_TIME else ard.state.time |
| 463 | + if ard_qdev.update_counter_DAQ == 1: |
| 464 | + ard.state.time_0 = now |
| 465 | + ard.state.time = 0 |
| 466 | + else: |
| 467 | + ard.state.time = now - ard.state.time_0 |
| 468 | + |
| 469 | + # Add readings to chart history |
| 470 | + window.history_chart_curve.appendData( |
| 471 | + ard.state.time, ard.state.reading_1 |
| 472 | + ) |
| 473 | + |
| 474 | + # Add readings to the log |
| 475 | + log.update() |
| 476 | + |
| 477 | + # Return success |
| 478 | + return True |
| 479 | + |
| 480 | + ard_qdev = WaveGeneratorArduino_qdev( |
| 481 | + dev=ard, |
| 482 | + DAQ_function=DAQ_function, |
| 483 | + DAQ_interval_ms=DAQ_INTERVAL_MS, |
| 484 | + debug=DEBUG, |
| 485 | + ) |
512 | 486 |
|
513 | 487 | # -------------------------------------------------------------------------- |
514 | 488 | # File logger |
@@ -538,19 +512,6 @@ def write_data_to_log(): |
538 | 512 | lambda: window.qpbt_record.setText("Click to start recording to file") |
539 | 513 | ) |
540 | 514 |
|
541 | | - # -------------------------------------------------------------------------- |
542 | | - # postprocess_DAQ_updated |
543 | | - # -------------------------------------------------------------------------- |
544 | | - |
545 | | - @Slot() |
546 | | - def postprocess_DAQ_updated(): |
547 | | - # Add readings to chart history |
548 | | - window.history_chart_curve.appendData( |
549 | | - ard.state.time, ard.state.reading_1 |
550 | | - ) |
551 | | - # Add readings to the log |
552 | | - log.update() |
553 | | - |
554 | 515 | # -------------------------------------------------------------------------- |
555 | 516 | # Program termination routines |
556 | 517 | # -------------------------------------------------------------------------- |
@@ -588,14 +549,12 @@ def notify_connection_lost(): |
588 | 549 | # Start the main GUI event loop |
589 | 550 | # -------------------------------------------------------------------------- |
590 | 551 |
|
591 | | - ard_qdev.signal_DAQ_updated.connect(postprocess_DAQ_updated) |
592 | | - ard_qdev.signal_connection_lost.connect(notify_connection_lost) |
593 | | - ard_qdev.start(DAQ_priority=QtCore.QThread.Priority.TimeCriticalPriority) |
594 | | - |
595 | | - app.aboutToQuit.connect(about_to_quit) |
596 | | - |
597 | 552 | window = MainWindow(qdev=ard_qdev, qlog=log) |
598 | 553 | window.timer_chart.start(CHART_INTERVAL_MS) |
599 | 554 | window.show() |
600 | 555 |
|
| 556 | + ard_qdev.signal_connection_lost.connect(notify_connection_lost) |
| 557 | + ard_qdev.start(DAQ_priority=QtCore.QThread.Priority.TimeCriticalPriority) |
| 558 | + |
| 559 | + app.aboutToQuit.connect(about_to_quit) |
601 | 560 | sys.exit(app.exec()) |
0 commit comments