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
Exemplo n.º 16
0
    # --------------------------------------------------------------------------
    #   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
    # --------------------------------------------------------------------------