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___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_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_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
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()
    )
    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)

    # Start workers
    qdev_ard.start(DAQ_priority=QtCore.QThread.TimeCriticalPriority)

    # --------------------------------------------------------------------------
    #   Create plot refresh timer
    # --------------------------------------------------------------------------

    timer_chart = QtCore.QTimer()
    # timer_chart.setTimerType(QtCore.Qt.PreciseTimer)
    timer_chart.timeout.connect(window.update_chart)
    timer_chart.start(CHART_INTERVAL_MS)

    # --------------------------------------------------------------------------
    #   Start the main GUI event loop
    # --------------------------------------------------------------------------
    window.show()
    sys.exit(app.exec_())
#   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_())
Esempio n. 11
0
    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")
    )

    # --------------------------------------------------------------------------
    #   Timers
    # --------------------------------------------------------------------------

    timer_GUI = QtCore.QTimer()
    timer_GUI.timeout.connect(window.update_GUI)
    timer_GUI.start(100)

    timer_charts = QtCore.QTimer()
    timer_charts.timeout.connect(window.update_chart)
    timer_charts.start(CHART_INTERVAL_MS)

    # --------------------------------------------------------------------------
    #   Start the main GUI event loop
    # --------------------------------------------------------------------------

    qdev_ard.start()
    qdev_julabo.start()

    window.show()
    sys.exit(app.exec_())