def test_Worker_jobs__start_without_create(): print_title("Worker_jobs - start without create") import pytest qdev = QDeviceIO(FakeDevice()) with pytest.raises(SystemExit) as pytest_wrapped_e: qdev.start_worker_jobs() assert pytest_wrapped_e.type == SystemExit dprint("Exit code: %i" % pytest_wrapped_e.value.code) assert pytest_wrapped_e.value.code == 404
def test_Worker_jobs__quit_without_start(): print_title("Worker_jobs - quit without start") app = create_QApplication() qdev = QDeviceIO(FakeDevice()) qdev.create_worker_jobs() tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit()
def test_attach_device_twice(): print_title("Attach device twice") import pytest qdev = QDeviceIO(FakeDevice()) with pytest.raises(SystemExit) as pytest_wrapped_e: qdev.attach_device(FakeDevice()) assert pytest_wrapped_e.type == SystemExit dprint("Exit code: %i" % pytest_wrapped_e.value.code) assert pytest_wrapped_e.value.code == 22
def test_Worker_jobs__no_device_attached(): print_title("Worker_jobs - no device attached") import pytest qdev = QDeviceIO() with pytest.raises(SystemExit) as pytest_wrapped_e: qdev.create_worker_jobs() 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_jobs__jobs_function(): print_title("Worker_jobs - jobs_function") def jobs_function(func, args): if func == "special command": dev.fake_query_2() else: # Default job handling where, e.g. # func = self.dev.write # args = ("toggle LED",) func(*args) app = create_QApplication() dev = FakeDevice() qdev = QDeviceIO(dev) qdev.create_worker_jobs( jobs_function=jobs_function, debug=DEBUG, ) qdev.signal_jobs_updated.connect(process_jobs_updated) assert qdev.start() == True # Immediately fire a call to test if the worker is ready for it qdev.send(dev.fake_query_2) # fmt: off # Simulate device runtime start_time = time.perf_counter() QtCore.QTimer.singleShot(100, lambda: qdev.send("special command")) QtCore.QTimer.singleShot( 200, lambda: qdev.send(dev.fake_command_with_argument, 0)) # fmt: on while time.perf_counter() - start_time < 0.5: app.processEvents() time.sleep(0.001) # Do not hog the CPU tprint("About to quit") app.processEvents() assert qdev.quit() == True app.quit() assert dev.count_commands == 3 assert dev.count_replies == 2 assert cnt_jobs_updated == 3
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___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___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()
log = FileLogger( write_header_function=write_header_to_log, write_data_function=write_data_to_log, ) log.signal_recording_started.connect( 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`
print("\nCheck connection and try resetting the Arduino.") print("Exiting...\n") sys.exit(0) # -------------------------------------------------------------------------- # Create application # -------------------------------------------------------------------------- app = QtCore.QCoreApplication(sys.argv) app.aboutToQuit.connect(about_to_quit) # -------------------------------------------------------------------------- # Set up multithreaded communication with the Arduino # -------------------------------------------------------------------------- # Create QDeviceIO qdev_ard = QDeviceIO(ard) class MasterSync: 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
# 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_())
def test_Worker_jobs(start_alive=True): print_title("Worker_jobs" + ("" if start_alive else " - start dead")) app = create_QApplication() dev = FakeDevice(start_alive=start_alive) qdev = QDeviceIO(dev) qdev.create_worker_jobs(debug=DEBUG) qdev.signal_jobs_updated.connect(process_jobs_updated) assert qdev.start() == start_alive # Immediately fire a call to test if the worker is ready for it qdev.add_to_jobs_queue(dev.fake_query_2) # fmt: off # Simulate device runtime start_time = time.perf_counter() QtCore.QTimer.singleShot(100, qdev.process_jobs_queue) QtCore.QTimer.singleShot(200, lambda: qdev.send(dev.fake_query_2)) QtCore.QTimer.singleShot( 300, lambda: qdev.add_to_jobs_queue(dev.fake_command_with_argument, 0)) QtCore.QTimer.singleShot( 400, lambda: qdev.add_to_jobs_queue(dev.fake_command_with_argument, 0)) QtCore.QTimer.singleShot( 500, lambda: qdev.add_to_jobs_queue(dev.fake_command_with_argument, 0)) QtCore.QTimer.singleShot(600, qdev.process_jobs_queue) QtCore.QTimer.singleShot( 700, lambda: qdev.send("trigger_illegal_function_call_error")) # fmt: on 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 == 5 assert dev.count_replies == 2 assert cnt_jobs_updated == 4
# -------------------------------------------------------------------------- # Create application # -------------------------------------------------------------------------- QtCore.QThread.currentThread().setObjectName("MAIN") # For DEBUG info app = QtWid.QApplication(sys.argv) app.setFont(QtGui.QFont("Arial", 9)) app.aboutToQuit.connect(about_to_quit) # -------------------------------------------------------------------------- # Set up multithreaded communication with the devices # -------------------------------------------------------------------------- # Arduino qdev_ard = QDeviceIO(ard) qdev_ard.create_worker_DAQ( DAQ_function=DAQ_function, DAQ_interval_ms=DAQ_INTERVAL_MS, critical_not_alive_count=3, debug=DEBUG, ) # Julabo qdev_julabo = Julabo_circulator_qdev( dev=julabo, DAQ_interval_ms=DAQ_INTERVAL_MS, debug=DEBUG ) # -------------------------------------------------------------------------- # Create GUI # --------------------------------------------------------------------------