def test_Worker_DAQ___rate(): print_title("Worker_DAQ - INTERNAL_TIMER - DAQ rate") def DAQ_function(): # Must return True when successful, False otherwise reply = dev.fake_query_1() dprint(" " * 50 + "%.1f Hz" % qdev.obtained_DAQ_rate_Hz) return reply[-4:] == "0101" app = create_QApplication() dev = FakeDevice() qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ(DAQ_trigger=DAQ_TRIGGER.INTERNAL_TIMER, DAQ_function=DAQ_function, DAQ_interval_ms=10, critical_not_alive_count=1, debug=DEBUG) # fmt: on assert qdev.start() == True # Simulate device runtime start_time = time.perf_counter() while time.perf_counter() - start_time < 1.51: app.processEvents() time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit() assert 9 <= qdev.obtained_DAQ_interval_ms <= 11 assert 99 <= qdev.obtained_DAQ_rate_Hz <= 101
def test_Worker_DAQ___quit_without_start(): print_title("Worker_DAQ - quit without start") app = create_QApplication() qdev = QDeviceIO(FakeDevice()) qdev.create_worker_DAQ() tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit()
def test_Worker_DAQ___no_device_attached(): print_title("Worker_DAQ - no device attached") import pytest qdev = QDeviceIO() with pytest.raises(SystemExit) as pytest_wrapped_e: qdev.create_worker_DAQ() assert pytest_wrapped_e.type == SystemExit dprint("Exit code: %i" % pytest_wrapped_e.value.code) assert pytest_wrapped_e.value.code == 99
def test_Worker_DAQ___CONTINUOUS(start_alive=True): print_title("Worker_DAQ - CONTINUOUS" + ("" if start_alive else " - start dead")) def DAQ_function(): # Must return True when successful, False otherwise time.sleep(0.1) # Simulate blocking processing time on the device reply = dev.fake_query_1() return reply[-4:] == "0101" app = create_QApplication() dev = FakeDevice(start_alive=start_alive) qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ( DAQ_trigger=DAQ_TRIGGER.CONTINUOUS, DAQ_function=DAQ_function, critical_not_alive_count=1, debug=DEBUG, ) # fmt: on qdev.signal_DAQ_updated.connect(process_DAQ_updated) qdev.signal_DAQ_paused.connect(process_DAQ_paused) assert qdev.start() == start_alive # Immediately fire a call to test if the worker is ready for it qdev.unpause_DAQ() # Simulate device runtime start_time = time.perf_counter() QtCore.QTimer.singleShot(300, qdev.pause_DAQ) QtCore.QTimer.singleShot(600, qdev.unpause_DAQ) QtCore.QTimer.singleShot(900, qdev.pause_DAQ) QtCore.QTimer.singleShot(1200, qdev.unpause_DAQ) while time.perf_counter() - start_time < 1.6: app.processEvents() if dev.count_commands == 12: break time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit() if start_alive: assert dev.count_commands >= 10 assert dev.count_replies >= 10 assert (cnt_DAQ_updated >= 9 ) # Last signal is not always received before thread is quit assert cnt_DAQ_paused == 3
def test_Worker_DAQ___lose_connection(): print_title("Worker_DAQ - INTERNAL_TIMER - lose connection") def DAQ_function(): # Must return True when successful, False otherwise if qdev.update_counter_DAQ == 10: dev.is_alive = False reply = dev.fake_query_1() return reply[-4:] == "0101" # NOTE: The global 'go' mechanism used here is a quick and dirty way to # pytest. In production, it should be implemented by an boolean external # class member. global go go = True @QtCore.pyqtSlot() def process_connection_lost(): tprint("---> received: connection_lost") global go go = False app = create_QApplication() dev = FakeDevice() # Forcefully remove members as extra test del dev.name del dev.is_alive qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ(DAQ_trigger=DAQ_TRIGGER.INTERNAL_TIMER, DAQ_function=DAQ_function, DAQ_interval_ms=20, critical_not_alive_count=3, debug=DEBUG) # fmt: on qdev.create_worker_jobs(debug=DEBUG) qdev.signal_connection_lost.connect(process_connection_lost) assert qdev.start() == True # Simulate device runtime while go: app.processEvents() time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True assert qdev.quit() == True # Twice, to check for msg 'already closed'. app.quit()
def test_Worker_DAQ___SINGLE_SHOT_WAKE_UP(start_alive=True): print_title("Worker_DAQ - SINGLE_SHOT_WAKE_UP" + ("" if start_alive else " - start dead")) def DAQ_function(): # Must return True when successful, False otherwise reply = dev.fake_query_1() return reply[-4:] == "0101" app = create_QApplication() dev = FakeDevice(start_alive=start_alive) qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ(DAQ_trigger=DAQ_TRIGGER.SINGLE_SHOT_WAKE_UP, DAQ_function=DAQ_function, critical_not_alive_count=1, debug=DEBUG) # fmt: on qdev.signal_DAQ_updated.connect(process_DAQ_updated) assert qdev.start() == start_alive # Immediately fire a call to test if the worker is ready for it qdev.wake_up_DAQ() # Simulate device runtime start_time = time.perf_counter() QtCore.QTimer.singleShot(300, qdev.wake_up_DAQ) QtCore.QTimer.singleShot(600, qdev.wake_up_DAQ) while time.perf_counter() - start_time < 1: app.processEvents() time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit() if start_alive: assert dev.count_commands == 3 assert dev.count_replies == 3 assert cnt_DAQ_updated == 3
def test_Worker_DAQ___INTERNAL_TIMER(start_alive=True): print_title("Worker_DAQ - INTERNAL_TIMER" + ("" if start_alive else " - start dead")) def DAQ_function(): # Must return True when successful, False otherwise reply = dev.fake_query_1() return reply[-4:] == "0101" app = create_QApplication() dev = FakeDevice(start_alive=start_alive) qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ(DAQ_trigger=DAQ_TRIGGER.INTERNAL_TIMER, DAQ_function=DAQ_function, DAQ_interval_ms=100, critical_not_alive_count=10, debug=DEBUG) # fmt: on qdev.signal_DAQ_updated.connect(process_DAQ_updated) assert qdev.start() == start_alive # Simulate device runtime start_time = time.perf_counter() while time.perf_counter() - start_time < 1: app.processEvents() if dev.count_commands == 3: break time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit() if start_alive: assert dev.count_commands >= 3 assert dev.count_replies >= 3 assert (cnt_DAQ_updated >= 2 ) # Last signal is not always received before thread is quit
def test_Worker_DAQ___ILLEGAL_DAQ_FUNCTION(): print_title("Worker_DAQ - ILLEGAL_DAQ_FUNCTION") def DAQ_function(): # Must return True when successful, False otherwise if qdev.update_counter_DAQ == 2: 0 / 0 else: reply = dev.fake_query_1() return reply[-4:] == "0101" app = create_QApplication() dev = FakeDevice() qdev = QDeviceIO(dev) # fmt: off qdev.create_worker_DAQ(DAQ_trigger=DAQ_TRIGGER.INTERNAL_TIMER, DAQ_function=DAQ_function, DAQ_interval_ms=100, debug=DEBUG) # fmt: on qdev.signal_DAQ_updated.connect(process_DAQ_updated) assert qdev.start() == True # Simulate device runtime start_time = time.perf_counter() while time.perf_counter() - start_time < 1: app.processEvents() if dev.count_commands == 3: break time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit()
lambda filepath: window.qpbt_record.setText("Recording to file: %s" % filepath)) log.signal_recording_stopped.connect( lambda: window.qpbt_record.setText("Click to start recording to file")) # -------------------------------------------------------------------------- # Set up multithreaded communication with the Arduino # -------------------------------------------------------------------------- # Create QDeviceIO qdev_ard = QDeviceIO(ard) # Create workers qdev_ard.create_worker_DAQ( DAQ_function=DAQ_function, DAQ_interval_ms=DAQ_INTERVAL_MS, critical_not_alive_count=1, debug=DEBUG, ) qdev_ard.create_worker_jobs(debug=DEBUG) # Connect signals to slots qdev_ard.signal_DAQ_updated.connect(window.update_GUI) qdev_ard.signal_connection_lost.connect(notify_connection_lost) # Hack. TODO: Implement start/stop in `QDeviceIO` def start_stop(): qdev_ard.worker_DAQ.DAQ_function = ( DAQ_function if window.qpbt_running.isChecked() else None) window.qpbt_running.clicked.connect(start_stop)
def __init__(self, qdev): self.qdev = qdev self.name = "Sync" def tick(self): self.qdev.wake_up_DAQ() return True sync = MasterSync(qdev_ard) qdev_sync = QDeviceIO(sync) # Create workers # fmt: off qdev_ard.create_worker_DAQ( DAQ_trigger = DAQ_TRIGGER.SINGLE_SHOT_WAKE_UP, DAQ_function = DAQ_function, debug = DEBUG, ) qdev_sync.create_worker_DAQ( DAQ_trigger = DAQ_TRIGGER.INTERNAL_TIMER, DAQ_function = sync.tick, DAQ_interval_ms = DAQ_INTERVAL_MS, critical_not_alive_count = 1, debug = DEBUG, ) # fmt: on # Connect signals to slots qdev_ard.signal_DAQ_updated.connect(update_terminal) qdev_ard.signal_connection_lost.connect(notify_connection_lost)
# Main # ------------------------------------------------------------------------------ if __name__ == "__main__": app = QtWid.QApplication(sys.argv) app.aboutToQuit.connect(about_to_quit) window = MainWindow() # Fake a device that generates data at a sampling rate of `Fs` Hz. The # data gets generated and transferred to our HistoryChartCurve-instance from # out of a separate thread. This is taken care of by QDeviceIO. class FakeDevice: def __init__(self): self.name = "FakeDevice" self.is_alive = True qdev = QDeviceIO(dev=FakeDevice()) qdev.create_worker_DAQ(DAQ_interval_ms=WORKER_DAQ_INTERVAL_MS, DAQ_function=DAQ_function) qdev.signal_DAQ_updated.connect(window.update_GUI) qdev.start() # Chart refresh timer timer_chart = QtCore.QTimer(timerType=QtCore.Qt.PreciseTimer) timer_chart.timeout.connect(window.update_charts) timer_chart.start(CHART_DRAW_INTERVAL_MS) window.show() sys.exit(app.exec_())