// controllerlink.h - one controller for a GUI application: a RemoteClient in its own thread, // the results as Qt signals (delivered in the thread of the ControllerLink object, normally // the GUI thread). One ControllerLink per serial port. // // After open() the link detects the controller (PING, then ID), polls the keyboard leds // (LEDS, 5 times a second) and executes the command lines given to send() one after the // other (stop-and-wait). Link state: // Closed - the port is closed // NoLink - the port is open, the controller does not answer (detection repeated every 2 s) // Link - connected // 3 requests in a row without an answer = link lost: lost(), state NoLink, detection again. // When the port fails (e.g. the USB adapter was unplugged) the link closes: error(), closed(). // // Example // auto *link = new AdvCtrl::ControllerLink(this); // connect(link, &AdvCtrl::ControllerLink::stateChanged, this, &MyWidget::showLinkState); // connect(link, &AdvCtrl::ControllerLink::reply, this, // [](const QString &command, const QString &result) { qDebug() << command << result; }); // link->open("/dev/ttyUSB0"); // link->send("CAM 2"); // link->send("BR 12"); #ifndef ADVCTRL_CONTROLLERLINK_H #define ADVCTRL_CONTROLLERLINK_H #include "remoteclient.h" #include #include namespace AdvCtrl { class LinkThread; class ControllerLink : public QObject { Q_OBJECT public: enum State { Closed, NoLink, Link }; Q_ENUM(State) static constexpr int LedsPeriodMs = 200; // LEDS polling static constexpr int DetectRetryMs = 2000; // detection retry while not detected static constexpr int LostAfter = 3; // requests in a row without an answer -> link lost explicit ControllerLink(QObject *parent = nullptr); ~ControllerLink() override; // stops the thread and closes the port State state() const; QString portName() const; // port of the running link, "" when closed public slots: void open(const QString &portName, int baudRate = RemoteClient::DefaultBaudRate); void close(); // closed() follows when the port is released void send(const QString &commandLine); // the result comes as reply(commandLine, result) signals: void stateChanged(AdvCtrl::ControllerLink::State state); void detected(const QString &firmware, const QString &cameras, const QString &uid); void notDetected(); // a detection attempt failed (retried every 2 s) void lost(); // 3 requests in a row without an answer void leds(quint32 mask); // keyboard leds, bit order = RemoteClient::LedNames // result: "OK[ data]", "ERR " or "!! " void reply(const QString &commandLine, const QString &result); void error(const QString &message); void closed(); private: friend class LinkThread; void setState(State state); void handleDetected(const QString &firmware, const QString &cameras, const QString &uid); void handleNotDetected(); void handleLost(); void handleClosed(); LinkThread *m_thread = nullptr; State m_state = Closed; QString m_portName; }; } // namespace AdvCtrl #endif // ADVCTRL_CONTROLLERLINK_H