diff --git a/biotracker/BioTrackerApp.h b/biotracker/BioTrackerApp.h index e72e3d52d5ef669d37b8c649aad42df9179cb177..7f825109753757a262424cdec1c710eb5a395187 100644 --- a/biotracker/BioTrackerApp.h +++ b/biotracker/BioTrackerApp.h @@ -15,6 +15,7 @@ #include "settings/Settings.h" #include "TrackerStatus.h" #include "PanZoomState.h" +#include "zmq/ZmqProcessHandler.h" namespace BioTracker { namespace Core { diff --git a/biotracker/ZmqTrackingAlgorithm.h b/biotracker/ZmqTrackingAlgorithm.h index 8f6eed1c71dac42ae9ce483074a3f45c41a94330..2289793606870ba6e913a80d8174aa68bd1f0ea2 100644 --- a/biotracker/ZmqTrackingAlgorithm.h +++ b/biotracker/ZmqTrackingAlgorithm.h @@ -24,6 +24,7 @@ #include "Exceptions.h" #include "zmq/ZmqInfoFile.h" +#include "zmq/ZmqClientProcess.h" namespace BioTracker { namespace Core { @@ -32,7 +33,7 @@ namespace Zmq { class ZmqTrackingAlgorithm : public TrackingAlgorithm { public: - ZmqTrackingAlgorithm(ZmqInfoFile info, Settings &settings); + ZmqTrackingAlgorithm(std::shared_ptr<ZmqClientProcess> process, Settings &settings); virtual ~ZmqTrackingAlgorithm() override; @@ -61,25 +62,18 @@ class ZmqTrackingAlgorithm : public TrackingAlgorithm { void keyPressEvent(QKeyEvent *) override; - void listenToEvents(); - void shutdown(); private Q_SLOTS: - void btnClicked(); - void sldValueChanged(int value); - void processError(QProcess::ProcessError error); - void processHasError(); + void btnClicked(const QString); + void sldValueChanged(const QString, int value); private: - std::unique_ptr<QProcess> m_zmqClient; - bool m_isDead; // if this is true: its OVER bool m_isTracking; std::set<Qt::Key> m_keys; - void *m_context; - void *m_socket; std::shared_ptr<QWidget> m_tools; - std::mutex m_zmqMutex; + std::shared_ptr<ZmqClientProcess> m_process; + EventHandler m_events; }; } } diff --git a/biotracker/src/Registry.cpp b/biotracker/src/Registry.cpp index 21211a13d5b4048be40e896317ee4a523f06d338..3cd6e53714aefd962ce046a27c967eebb5e3109e 100644 --- a/biotracker/src/Registry.cpp +++ b/biotracker/src/Registry.cpp @@ -6,6 +6,8 @@ #include <QLibrary> #include "Exceptions.h" +#include "biotracker/zmq/ZmqProcessHandler.h" +#include "biotracker/zmq/ZmqClientProcess.h" namespace BioTracker { namespace Core { @@ -78,7 +80,9 @@ std::shared_ptr<TrackingAlgorithm> Registry::makeNewTracker( std::shared_ptr<TrackingAlgorithm> Registry::getTracker(Zmq::ZmqInfoFile &info, Settings &s) const { - auto tracker = std::make_shared<Zmq::ZmqTrackingAlgorithm>(info, s); + Zmq::ZmqProcessHandler &handler = Zmq::ZmqProcessHandler::getInstance(); + std::shared_ptr<Zmq::ZmqClientProcess> proc = handler.startProcess(info); + auto tracker = std::make_shared<Zmq::ZmqTrackingAlgorithm>(proc, s); return tracker; } @@ -97,7 +101,10 @@ bool BioTracker::Core::Registry::registerZmqTracker(Zmq::ZmqInfoFile virtual std::shared_ptr<TrackingAlgorithm> operator()(Settings &settings) const override { - return std::make_shared<Zmq::ZmqTrackingAlgorithm>(m_trackerInfo, settings); + Zmq::ZmqProcessHandler &zmqhandler = Zmq::ZmqProcessHandler::getInstance(); + Zmq::ZmqInfoFile info = m_trackerInfo; + std::shared_ptr<Zmq::ZmqClientProcess> proc = zmqhandler.startProcess(info); + return std::make_shared<Zmq::ZmqTrackingAlgorithm>(proc, settings); } Zmq::ZmqInfoFile m_trackerInfo; diff --git a/biotracker/src/ZmqTrackingAlgorithm.cpp b/biotracker/src/ZmqTrackingAlgorithm.cpp index 50a3807b888d52f5292639a54f5b1247ac5f5d11..a62ad389dccb6e25247ef16eeea135295c8a9c75 100644 --- a/biotracker/src/ZmqTrackingAlgorithm.cpp +++ b/biotracker/src/ZmqTrackingAlgorithm.cpp @@ -1,76 +1,40 @@ #include "../ZmqTrackingAlgorithm.h" -#include "zmq/ZmqInfoFile.h" +#include "biotracker/zmq/ZmqInfoFile.h" #include "biotracker/zmq/ZmqHelper.h" +#include "biotracker/zmq/ZmqMessageParser.h" namespace BioTracker { namespace Core { namespace Zmq { -const QString TYPE_TRACK("0"); -const QString TYPE_PAINT("1"); -const QString TYPE_SHUTDOWN("2"); -const QString TYPE_PAINTOVERLAY("3"); -const QString TYPE_REQUEST_WIDGETS("4"); -const QString TYPE_SEND_WIDGET_EVENT("5"); - -const QString WIDGET_EVENT_CLICK("0"); -const QString WIDGET_EVENT_CHANGED("1"); - -const QString EVENT_STOP_LISTENING("99"); -const QString EVENT_NOTIFY_GUI("0"); -const QString EVENT_UPDATE("1"); -const QString EVENT_FORCE_TRACKING("2"); -const QString EVENT_JUMP_TO_FRAME("3"); -const QString EVENT_PLAY_PAUSE("4"); - -const QString EVENT_MSG_FALSE("0"); - - -const int ZMQ_TIMEOUT_IN_MS = 10000; // timeout for the zmq tracker during execution -const int ZMQ_SMALL_TIMEOUT_IN_MS = 1000; // timeout for the startup of the zmq tracker - -inline QString getSenderId(QObject *obj) { - QWidget *w = qobject_cast<QWidget *>(obj); - return w->accessibleName(); -} inline void setSenderId(QWidget *w, const QString id) { w->setAccessibleName(id); } - -ZmqTrackingAlgorithm::ZmqTrackingAlgorithm(ZmqInfoFile info, Settings &settings) : +/** + * @brief ZmqTrackingAlgorithm::ZmqTrackingAlgorithm + * @param process + * @param settings + */ +ZmqTrackingAlgorithm::ZmqTrackingAlgorithm(std::shared_ptr<ZmqClientProcess> process, Settings &settings) : TrackingAlgorithm(settings), m_isTracking(false), - m_context(zmq_ctx_new()), - m_socket(zmq_socket(m_context, ZMQ_PAIR)), - m_tools(std::make_shared<QFrame>()) { - - // set timeout - zmq_setsockopt(m_socket, ZMQ_RCVTIMEO, &ZMQ_SMALL_TIMEOUT_IN_MS, sizeof(int)); - - int rc = zmq_bind(m_socket, "tcp://127.0.0.1:5556"); - if (rc != 0) { - int rno = zmq_errno(); - QString err_msg(zmq_strerror(rno)); - std::cout << "error: " << err_msg.toUtf8().constData() << std::endl; - } - assert(rc == 0); - m_zmqClient = std::make_unique<QProcess>(this); - m_zmqClient->setProcessChannelMode(QProcess::ForwardedChannels); - QString command = info.m_program + " " + info.m_arguments.first(); - - // connect listeners - QObject::connect(m_zmqClient.get(), &QProcess::readyReadStandardError, - this, &ZmqTrackingAlgorithm::processHasError); - - QObject::connect(m_zmqClient.get(), - static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error), - this, &ZmqTrackingAlgorithm::processError); - - m_zmqClient->start(command); - m_zmqClient->waitForStarted(); + m_tools(std::make_shared<QFrame>()), + m_process(process), + m_events(this) { + + // ATTACH EVENTS + QObject::connect(&m_events, &EventHandler::btnClicked, this, &ZmqTrackingAlgorithm::btnClicked); + QObject::connect(&m_events, &EventHandler::sldValueChanged, this, &ZmqTrackingAlgorithm::sldValueChanged); + + QObject::connect(&m_events, &EventHandler::notifyGUI, this, &ZmqTrackingAlgorithm::notifyGUI); + QObject::connect(&m_events, &EventHandler::update, this, &ZmqTrackingAlgorithm::update); + QObject::connect(&m_events, &EventHandler::forceTracking, this, &ZmqTrackingAlgorithm::forceTracking); + QObject::connect(&m_events, &EventHandler::pausePlayback, this, &ZmqTrackingAlgorithm::pausePlayback); + QObject::connect(&m_events, &EventHandler::jumpToFrame, this, &ZmqTrackingAlgorithm::jumpToFrame); + } ZmqTrackingAlgorithm::~ZmqTrackingAlgorithm() { @@ -78,98 +42,23 @@ ZmqTrackingAlgorithm::~ZmqTrackingAlgorithm() { } void ZmqTrackingAlgorithm::track(ulong frameNumber, const cv::Mat &frame) { - if (m_isDead) { - return; - } - m_zmqMutex.lock(); - send_string(m_socket, TYPE_TRACK, ZMQ_SNDMORE); - send_mat(m_socket, frame, frameNumber); - this->listenToEvents(); - m_isTracking = true; - m_zmqMutex.unlock(); + SendTrackMessage message(frame, frameNumber); + m_process->send(message, m_events); } -void ZmqTrackingAlgorithm::paint(ProxyMat &m, const View &) { - if (m_isDead) { - return; - } - m_zmqMutex.lock(); - send_string(m_socket, TYPE_PAINT, ZMQ_SNDMORE); - QString data = QString::number(99); - send_string(m_socket, data, 0); - this->listenToEvents(); - // wait for reply - QString flag = recv_string(m_socket); - if (QString::compare(flag, "Y") == 0) { - recv_mat(m_socket, m.getMat()); - } - m_zmqMutex.unlock(); +void ZmqTrackingAlgorithm::paint(ProxyMat &m, const View &v) { + SendPaintMessage message(99, v.name, m.getMat()); + m_process->send(message, m_events); } -void ZmqTrackingAlgorithm::paintOverlay(QPainter *p, const View &) { - if (m_isDead) { - return; - } - m_zmqMutex.lock(); - send_string(m_socket, TYPE_PAINTOVERLAY, 0); - this->listenToEvents(); - //recv_QPainter(m_socket, p); - m_zmqMutex.unlock(); +void ZmqTrackingAlgorithm::paintOverlay(QPainter *p, const View &v) { + SendPaintOverlayMessage message(v.name, p); + m_process->send(message, m_events); } std::shared_ptr<QWidget> ZmqTrackingAlgorithm::getToolsWidget() { - m_zmqMutex.lock(); - - // request widgets from client - send_string(m_socket, TYPE_REQUEST_WIDGETS, 0); - this->listenToEvents(); - - QVBoxLayout *mainLayout = new QVBoxLayout(m_tools.get()); // LEAK_CHECK? - - // wait for response - // Elements are defined at: - // https://github.com/BioroboticsLab/biotracker_core/wiki/dev_zmq#possible-elements - QString data = recv_string(m_socket); - if (data.length() > 0) { - QStringList batch = data.split(";"); - for (auto &widgetStr : batch) { - const QChar type = widgetStr.at(0); - widgetStr.chop(1); // remove trailing ')' - widgetStr = widgetStr.right(widgetStr.length() - 2); // remove first '_(' - auto widgetElems = widgetStr.split(","); - const QString uniqueId = widgetElems[0]; - if (type == QChar('d')) { - - } else if (type == QChar('t')) { - QLabel *txt = new QLabel(m_tools.get()); - txt->setText(widgetElems[1]); - mainLayout->addWidget(txt); - } else if (type == QChar('b')) { - QPushButton *btn = new QPushButton(m_tools.get()); // LEAK_CHECK? - btn->setText(widgetElems[1]); - setSenderId(btn, uniqueId); - mainLayout->addWidget(btn); - QObject::connect(btn, &QPushButton::clicked, this, &ZmqTrackingAlgorithm::btnClicked); - } else if (type == QChar('s')) { - const int min = widgetElems[2].toInt(); - const int max = widgetElems[3].toInt(); - const int defaultValue = widgetElems[4].toInt(); - QLabel *txt = new QLabel(m_tools.get()); - txt->setText(widgetElems[1]); - mainLayout->addWidget(txt); - QSlider *sld = new QSlider(Qt::Horizontal, m_tools.get()); - setSenderId(sld, uniqueId); - sld->setMinimum(min); - sld->setMaximum(max); - sld->setValue(defaultValue); - mainLayout->addWidget(sld); - QObject::connect(sld, &QSlider::valueChanged, this, &ZmqTrackingAlgorithm::sldValueChanged); - } else { - // silently ignore - } - } - } - m_zmqMutex.unlock(); + SendRequestWidgetsMessage message(m_tools); + m_process->send(message, m_events); return m_tools; } @@ -201,124 +90,21 @@ void ZmqTrackingAlgorithm::keyPressEvent(QKeyEvent *) { } -/** - * @brief ZmqTrackingAlgorithm::listenToEvents - * CAREFUL, this function is NOT THREADSAFE - */ -void ZmqTrackingAlgorithm::listenToEvents() { - if (!m_isDead) { - QString event = recv_string(m_socket); - - switch (zmq_errno()) { - case EAGAIN: - // if we timeout, we wont to notify the tracker.. - m_isDead = true; - return; - } - - while (event != EVENT_STOP_LISTENING) { - // handle event - if (event == EVENT_UPDATE) { - Q_EMIT update(); - } else if (event == EVENT_FORCE_TRACKING) { - Q_EMIT forceTracking(); - } else { - const QStringList eventParts = event.split(","); - if (eventParts[0] == EVENT_NOTIFY_GUI) { - QString message = eventParts[1]; - // as the ',' and ';' characters are special symbols - // for the zmq message transmission they get encoded - // so they dont mess with the zmq message. Here we need - // to restore them - message = message.replace("%2C", ","); - message = message.replace("%3B", ";"); - - const size_t mtypeInt = eventParts[2].toInt(); - const MSGS::MTYPE mtype = MSGS::fromInt(mtypeInt); - Q_EMIT notifyGUI(message.toStdString(), mtype); - } else if (eventParts[0] == EVENT_JUMP_TO_FRAME) { - const size_t frame = eventParts[1].toInt(); - Q_EMIT jumpToFrame(frame); - } else if (eventParts[0] == EVENT_PLAY_PAUSE) { - if (eventParts[1] == EVENT_MSG_FALSE) { - Q_EMIT pausePlayback(false); - } else { - Q_EMIT pausePlayback(true); - } - } else { - assert(false); - } - } - event = recv_string(m_socket); - } - } -} - void ZmqTrackingAlgorithm::shutdown() { - std::cout << "try shutdown!" << std::endl; - m_zmqMutex.lock(); - m_isDead = true; - send_string(m_socket, TYPE_SHUTDOWN, 0); - this->listenToEvents(); - QThread::msleep(500); - m_zmqMutex.unlock(); - m_zmqClient->kill(); - m_zmqClient->waitForFinished(1000); - m_zmqMutex.unlock(); - zmq_disconnect(m_socket, "172.0.0.1:5556"); - zmq_close(m_socket); - zmq_ctx_term(m_context); - std::cout << "end shutdown!" << std::endl; } // == EVENTS == -void ZmqTrackingAlgorithm::btnClicked() { - if (m_isDead) { - return; - } - const QString widgetId = getSenderId(sender()); - QString message; - message.append(WIDGET_EVENT_CLICK); - message.append(","); - message.append(widgetId); - m_zmqMutex.lock(); - send_string(m_socket, TYPE_SEND_WIDGET_EVENT, ZMQ_SNDMORE); - send_string(m_socket, message, 0); - this->listenToEvents(); - m_zmqMutex.unlock(); -} - -void ZmqTrackingAlgorithm::sldValueChanged(int value) { - if (m_isDead) { - return; - } - const QString widgetId = getSenderId(sender()); - QString message; - message.append(WIDGET_EVENT_CHANGED); - message.append(","); - message.append(widgetId); - message.append(","); - message.append(QString::number(value)); - m_zmqMutex.lock(); - send_string(m_socket, TYPE_SEND_WIDGET_EVENT, ZMQ_SNDMORE); - send_string(m_socket, message, 0); - this->listenToEvents(); - m_zmqMutex.unlock(); +void ZmqTrackingAlgorithm::btnClicked(const QString widgetId) { + SendButtonClickMessage message(widgetId); + m_process->send(message, m_events); } -// == EVENTS end == - -void ZmqTrackingAlgorithm::processError(QProcess::ProcessError error) { - const QString errorStr(m_zmqClient->readAllStandardError()); - shutdown(); +void ZmqTrackingAlgorithm::sldValueChanged(const QString widgetId, int value) { + SendValueChangedMessage message(widgetId, value); + m_process->send(message, m_events); } -void ZmqTrackingAlgorithm::processHasError() { - const QString error(m_zmqClient->readAllStandardError()); - shutdown(); - -} } } diff --git a/biotracker/src/zmq/ZmqClientProcess.cpp b/biotracker/src/zmq/ZmqClientProcess.cpp index c98d6bc1c7ebcccd53c720115b409b2c335e6422..94ac5c422b276c88f8dfa0c504f99cffe0e86345 100644 --- a/biotracker/src/zmq/ZmqClientProcess.cpp +++ b/biotracker/src/zmq/ZmqClientProcess.cpp @@ -1,10 +1,10 @@ -#include "zmq/ZmqClientProcess.h" +#include "biotracker/zmq/ZmqClientProcess.h" #include <opencv/cv.hpp> #include <QProcess> #include <QString> -#include "zmq/ZmqHelper.h" +#include "biotracker/zmq/ZmqHelper.h" namespace BioTracker { namespace Core { @@ -92,8 +92,17 @@ void ZmqClientProcess::send(GenericSendMessage &message, EventHandler &handler) m_zmqMutex.unlock(); } -void BioTracker::Core::Zmq::ZmqClientProcess::shutdown() { +void ZmqClientProcess::shutdown() { isFree = true; + m_zmqMutex.lock(); + send_string(SOCKET, TYPE_SHUTDOWN, 0); + EventHandler temp(this); + listenToEvents(temp); + m_zmqClient->kill(); + m_zmqClient->waitForFinished(1000); + zmq_disconnect(SOCKET, "172.0.0.1:5556"); + zmq_close(SOCKET); + m_zmqMutex.unlock(); } // ========================================= @@ -120,7 +129,7 @@ void ZmqClientProcess::paintOverlay(SendPaintOverlayMessage &message, EventHandl } void ZmqClientProcess::requestTools(SendRequestWidgetsMessage &message, EventHandler &handler) { - ReceiveToolsWidgetMessage result(message); + ReceiveToolsWidgetMessage result(message, handler); sendMessage(message); listenToEvents(handler); requestResults(result); @@ -153,7 +162,13 @@ void ZmqClientProcess::sendMessage(GenericSendMessage &message) { flag = ZMQ_SNDMORE; } ZmqMessage m = messageParts[i]; - zmq_send(SOCKET, m.data, m.sizeInBytes, flag); + + if (m.isText) { + send_string(SOCKET, m.text, flag); + } else { // send mat DATA + size_t sizeInBytes = m.mat.total() * m.mat.elemSize(); + zmq_send(SOCKET, m.mat.data, sizeInBytes, flag); + } } } @@ -170,7 +185,8 @@ void recvThatMat(cv::Mat &m) { * @param handler */ void ZmqClientProcess::listenToEvents(EventHandler &handler) { - + recvString func = &recvThisString; + handler.receive(func); } /** @@ -178,18 +194,20 @@ void ZmqClientProcess::listenToEvents(EventHandler &handler) { * @param message */ void ZmqClientProcess::requestResults(GenericReceiveMessage &message) { - + recvString func = &recvThisString; + recvMat funcMat = &recvThatMat; + message.receive(func, funcMat); } // =========================================== // =========================================== void BioTracker::Core::Zmq::ZmqClientProcess::processBadError(QProcess::ProcessError error) { - + // TODO implement error handling } void BioTracker::Core::Zmq::ZmqClientProcess::processError() { - + // TODO implement error handling } } diff --git a/biotracker/src/zmq/ZmqHelper.cpp b/biotracker/src/zmq/ZmqHelper.cpp index 2978f5fb4bd390a2794f1259305877751f65ee9e..e4cb48419224bc8c3fdf85aba8eb697a617b2787 100644 --- a/biotracker/src/zmq/ZmqHelper.cpp +++ b/biotracker/src/zmq/ZmqHelper.cpp @@ -1,4 +1,4 @@ -#include "zmq/ZmqHelper.h" +#include "biotracker/zmq/ZmqHelper.h" namespace BioTracker { namespace Core { diff --git a/biotracker/src/zmq/ZmqInfoFile.cpp b/biotracker/src/zmq/ZmqInfoFile.cpp index 9454e8197b7aef409e25d0a14d5f0a55ffbfecea..2d22047975297ef1c6a6538367c0c1e5ef692e93 100644 --- a/biotracker/src/zmq/ZmqInfoFile.cpp +++ b/biotracker/src/zmq/ZmqInfoFile.cpp @@ -1,8 +1,8 @@ -#include "zmq/ZmqInfoFile.h" +#include "biotracker/zmq/ZmqInfoFile.h" #include <QFile> #include <QTextStream> -#include "Exceptions.h" +#include "biotracker/Exceptions.h" namespace BioTracker { namespace Core { diff --git a/biotracker/src/zmq/ZmqMessageParser.cpp b/biotracker/src/zmq/ZmqMessageParser.cpp index 7bc203ecf59a95a9c307ed983cdb18045d0b1cd3..e513ca9e47f3be1d5ae17173c701e4597a9b5ade 100644 --- a/biotracker/src/zmq/ZmqMessageParser.cpp +++ b/biotracker/src/zmq/ZmqMessageParser.cpp @@ -1,4 +1,4 @@ -#include "zmq/ZmqMessageParser.h" +#include "biotracker/zmq/ZmqMessageParser.h" #include <QVBoxLayout> #include <QLabel> @@ -9,22 +9,12 @@ namespace BioTracker { namespace Core { namespace Zmq { -const QString TYPE_TRACK("0"); -const QString TYPE_PAINT("1"); -const QString TYPE_SHUTDOWN("2"); -const QString TYPE_PAINTOVERLAY("3"); -const QString TYPE_REQUEST_WIDGETS("4"); -const QString TYPE_SEND_WIDGET_EVENT("5"); - -const QString WIDGET_EVENT_CLICK("0"); -const QString WIDGET_EVENT_CHANGED("1"); - // ================================ // GenericSendMessage // ================================ -ZmqMessage GenericSendMessage::fromString(const QString &str) { - ZmqMessage m(str.toUtf8().constData(), str.size()); +ZmqMessage GenericSendMessage::fromString(const QString str) { + ZmqMessage m(str); return m; } @@ -41,8 +31,7 @@ std::vector<ZmqMessage> SendTrackMessage::get() { QString::number(m_frameNumber); message.push_back(fromString(data)); // #2 - size_t sizeInBytes = m_frame.total() * m_frame.elemSize(); - message.push_back(ZmqMessage(m_frame.data, sizeInBytes)); // #3 + message.push_back(ZmqMessage(m_frame)); // #3 return message; } @@ -89,7 +78,6 @@ std::vector<ZmqMessage> SendRequestWidgetsMessage::get() { std::vector<ZmqMessage> SendButtonClickMessage::get() { std::vector<ZmqMessage> message; message.push_back(fromString(TYPE_SEND_WIDGET_EVENT)); - QString click; click.append(WIDGET_EVENT_CLICK); click.append(","); @@ -169,60 +157,31 @@ void EventHandler::receive(BioTracker::Core::Zmq::recvString receiveStr) { } } -// ================================ -// ZmqMessage -// ================================ +inline QString getSenderId(QObject *obj) { + QWidget *w = qobject_cast<QWidget *>(obj); + return w->accessibleName(); +} -QString ZmqMessage::toString() { - return QString::fromLocal8Bit(static_cast<const char *>(data), sizeInBytes); +void EventHandler::btnClickedInternal() { + QWidget *w = qobject_cast<QWidget *>(sender()); + const QString widgetId = w->accessibleName(); + Q_EMIT btnClicked(widgetId); +} + +void EventHandler::sldValueChangedInternal(int value) { + const QString widgetId = getSenderId(sender()); + Q_EMIT sldValueChanged(widgetId, value); } // ================================ // ReceivePaintMessage // ================================ -/* -bool ReceivePaintMessage::receive(ZmqMessage m) -{ - const QString input = m.toString(); - if (m_firstCall) { - m_firstCall = false; - if (input == "Y") { - return true; - } - } else if (m_secondCall) { - // receive matrix shape - QStringRef shape(&input); - QVector<QStringRef> shapeStr = shape.split(","); - m_w = shapeStr.at(0).toInt(); - m_h = shapeStr.at(1).toInt(); - m_type = shapeStr.at(2).toInt(); - return true; - } else { - // receive matrix data - cv::Mat newMat(m_h, m_w, m_type, &m.data); - newMat.copyTo(m_mat); - } - return false; -} -*/ - void ReceivePaintMessage::receive(BioTracker::Core::Zmq::recvString receiveStr, BioTracker::Core::Zmq::recvMat recvMat) { QString input = receiveStr(); - if (input != "Y") { + if (input == "Y") { recvMat(m_mat); - // receive matrix shape - /*input = receiveStr(); - QStringRef shape(&input); - QVector<QStringRef> shapeStr = shape.split(","); - m_w = shapeStr.at(0).toInt(); - m_h = shapeStr.at(1).toInt(); - m_type = shapeStr.at(2).toInt(); - return true; - // receive matrix data - cv::Mat newMat(m_h, m_w, m_type, &m.data); - newMat.copyTo(m_mat);*/ } } @@ -304,7 +263,7 @@ void ReceiveToolsWidgetMessage::receive(BioTracker::Core::Zmq::recvString receiv btn->setText(widgetElems[1]); btn->setAccessibleName(uniqueId); mainLayout->addWidget(btn); - QObject::connect(btn, &QPushButton::clicked, m_buttonClickCallback); + QObject::connect(btn, &QPushButton::clicked, &m_events, &EventHandler::btnClickedInternal); } else if (type == QChar('s')) { const int min = widgetElems[2].toInt(); const int max = widgetElems[3].toInt(); @@ -318,9 +277,10 @@ void ReceiveToolsWidgetMessage::receive(BioTracker::Core::Zmq::recvString receiv sld->setMaximum(max); sld->setValue(defaultValue); mainLayout->addWidget(sld); - QObject::connect(sld, &QSlider::valueChanged, m_sliderChangedCallback); + QObject::connect(sld, &QSlider::valueChanged, &m_events, &EventHandler::sldValueChangedInternal); } else { // silently ignore + // TODO: do something } } } diff --git a/biotracker/src/zmq/ZmqProcessHandler.cpp b/biotracker/src/zmq/ZmqProcessHandler.cpp index 71a0be184a095df6a5d78326e548ac9a02e8e6bc..76fdb64b63588330b9a70c463bbad3e5e13e58bd 100644 --- a/biotracker/src/zmq/ZmqProcessHandler.cpp +++ b/biotracker/src/zmq/ZmqProcessHandler.cpp @@ -1,33 +1,37 @@ -#include "zmq/ZmqProcessHandler.h" +#include "biotracker/zmq/ZmqProcessHandler.h" namespace BioTracker { namespace Core { namespace Zmq { -ZmqProcessHandler::ZmqProcessHandler(QObject *p, const ZmqInfoFile info, void *socket): - QObject(p), - m_socket(socket) { +/** + CTOR + * @brief ZmqProcessHandler::ZmqProcessHandler + * @param parent + */ +ZmqProcessHandler::ZmqProcessHandler(): + m_context(zmq_ctx_new()) { } +/** + DTOR + * @brief ZmqProcessHandler::~ZmqProcessHandler + */ ZmqProcessHandler::~ZmqProcessHandler() { - + zmq_ctx_term(m_context); } -void ZmqProcessHandler::stop() { - -} - -void ZmqProcessHandler::start() { - -} - -void ZmqProcessHandler::processBadError(QProcess::ProcessError error) { - -} +std::shared_ptr<ZmqClientProcess> ZmqProcessHandler::startProcess(ZmqInfoFile &info) { + if (m_currentProcess) { + m_currentProcess->shutdown(); + m_currentProcess.reset(); + } -void ZmqProcessHandler::processError() { + void *socket = zmq_socket(m_context, ZMQ_PAIR); + m_currentProcess = std::make_shared<ZmqClientProcess>(info, std::move(socket)); + return m_currentProcess; } diff --git a/biotracker/zmq/ZmqClientProcess.h b/biotracker/zmq/ZmqClientProcess.h index 0ef49b975570c936de9eec9cefcef2117d858b11..30a25e2fa032c5f615127e37d1a34f2d749ae510 100644 --- a/biotracker/zmq/ZmqClientProcess.h +++ b/biotracker/zmq/ZmqClientProcess.h @@ -7,8 +7,8 @@ #include <QPoint> #include <zmq.h> #include <opencv2/opencv.hpp> -#include "zmq/ZmqMessageParser.h" -#include "zmq/ZmqInfoFile.h" +#include "biotracker/zmq/ZmqMessageParser.h" +#include "biotracker/zmq/ZmqInfoFile.h" namespace BioTracker { namespace Core { diff --git a/biotracker/zmq/ZmqHelper.h b/biotracker/zmq/ZmqHelper.h index d47b9d71beb73c2e72d6952b1422d322be0f00f1..c64e74e256ed7acc2a7b248ddc9d560173a047c2 100644 --- a/biotracker/zmq/ZmqHelper.h +++ b/biotracker/zmq/ZmqHelper.h @@ -80,47 +80,6 @@ inline void send_mat(void *socket, const cv::Mat &mat, const size_t frameNbr) { zmq_send(socket, mat.data, sizeInBytes, 0); } -/* -QColor getColor(const QStringRef content) { - QVector<QStringRef> colorStr = content.split(","); - const int r = colorStr.at(0).toInt(); - const int g = colorStr.at(1).toInt(); - const int b = colorStr.at(2).toInt(); - const int a = colorStr.at(3).toInt(); - QColor color(r, g, b, a); - return color; -} - -QRect getRect(const QStringRef content) { - QVector<QStringRef> colorStr = content.split(","); - const int x = colorStr.at(0).toInt(); - const int y = colorStr.at(1).toInt(); - const int w = colorStr.at(2).toInt(); - const int h = colorStr.at(3).toInt(); - QRect rect(x, y, w, h); - return rect; -} - -void recv_QPainter(void *socket, QPainter *p) { - QString paintBatch = recv_string(socket); - if (paintBatch.length() > 0) { - QStringList batch = paintBatch.split(";"); - for (int i = 0; i < batch.size(); ++i) { - const QString paintOperation = batch.at(i); - int start = 2; - int length = paintOperation.size() - 3; - QStringRef content(&paintOperation, start, length); - if (paintOperation.startsWith("p")) { - p->setPen(getColor(content)); - } else if (paintOperation.startsWith("b")) { - p->setBrush(getColor(content)); - } else if (paintOperation.startsWith("r")) { - p->drawRect(getRect(content)); - } - } - } -} -*/ } } } diff --git a/biotracker/zmq/ZmqMessageParser.h b/biotracker/zmq/ZmqMessageParser.h index 80ac9bcc04f21831589db614514636f438147496..a6d7c9182ee55bbe10696907313ac6aff513c6f4 100644 --- a/biotracker/zmq/ZmqMessageParser.h +++ b/biotracker/zmq/ZmqMessageParser.h @@ -10,25 +10,72 @@ #include <zmq.h> #include <opencv2/opencv.hpp> #include <QProcess> -#include "TrackingAlgorithm.h" -#include "zmq/ZmqInfoFile.h" -#include "settings/Messages.h" +#include "biotracker/TrackingAlgorithm.h" +#include "biotracker/zmq/ZmqInfoFile.h" +#include "biotracker/settings/Messages.h" namespace BioTracker { namespace Core { namespace Zmq { +const QString TYPE_TRACK("0"); +const QString TYPE_PAINT("1"); +const QString TYPE_SHUTDOWN("2"); +const QString TYPE_PAINTOVERLAY("3"); +const QString TYPE_REQUEST_WIDGETS("4"); +const QString TYPE_SEND_WIDGET_EVENT("5"); + +const QString WIDGET_EVENT_CLICK("0"); +const QString WIDGET_EVENT_CHANGED("1"); + + +const cv::Mat DEFAULT_1x1(1,1, CV_8UC3); + +// TODO solve this more elegant with polymorphsm class ZmqMessage { public: - ZmqMessage(const void *d, int s): - data(d), - sizeInBytes(s) {} + ZmqMessage(QString str): + isText(true), + text(str), + mat(DEFAULT_1x1) { + } + ZmqMessage(const cv::Mat &m): + isText(false), + mat(m) {} + + const bool isText; + const QString text; + const cv::Mat &mat; +}; + +typedef QString(*recvString)(); +typedef void (*recvMat)(cv::Mat &mat); + +// ====================================== +// EVENT HANDLER +// ====================================== + +class EventHandler : public QObject { + Q_OBJECT + public: + EventHandler(QObject *p): QObject(p) {} + void receive(recvString receiveStr); + Q_SIGNALS: + void notifyGUI(std::string, MSGS::MTYPE type = MSGS::MTYPE::NOTIFICATION); + void update(); + // cv::Mat requestCurrentScreen(); + void forceTracking(); + //void registerViews(const std::vector<View> views); + void pausePlayback(bool paused); + void jumpToFrame(int frameNumber); - const void *data; - int sizeInBytes; + void btnClicked(const QString widgetId); + void sldValueChanged(const QString widgetId, int value); + public Q_SLOTS: + void btnClickedInternal(); + void sldValueChangedInternal(int value); - QString toString(); }; // ====================================== @@ -45,10 +92,6 @@ enum MessageType { ValueChanged }; -typedef QString(*recvString)(); -typedef void (*recvMat)(cv::Mat &mat); - - class GenericSendMessage { public: GenericSendMessage(const MessageType t): type(t) {} @@ -63,7 +106,7 @@ class GenericSendMessage { const MessageType type; protected: - ZmqMessage fromString(const QString &str); + ZmqMessage fromString(const QString str); }; // ====================================== @@ -181,36 +224,28 @@ class ReceiveQPainterMessage: public GenericReceiveMessage { // REQUESTWIDGETS // ====================================== -typedef void (*ButtonClickCallback)(); -typedef void (*SliderChangedCallback)(int value); - class SendRequestWidgetsMessage: public GenericSendMessage { public: - SendRequestWidgetsMessage(std::shared_ptr<QWidget> tools, - ButtonClickCallback button, SliderChangedCallback slider): + SendRequestWidgetsMessage(std::shared_ptr<QWidget> tools): GenericSendMessage(RequestTools), - m_tools(tools), m_button(button), m_slider(slider) {} + m_tools(tools) {} std::vector<ZmqMessage>get() override; std::shared_ptr<QWidget> m_tools; - ButtonClickCallback m_button; - SliderChangedCallback m_slider; }; // ====================================== class ReceiveToolsWidgetMessage: public GenericReceiveMessage { public: - ReceiveToolsWidgetMessage(SendRequestWidgetsMessage &m): - m_tools(m.m_tools), m_buttonClickCallback(m.m_button), - m_sliderChangedCallback(m.m_slider) {} + ReceiveToolsWidgetMessage(SendRequestWidgetsMessage &m, EventHandler &evt): + m_tools(m.m_tools), m_events(evt) {} void receive(recvString receiveStr, recvMat recvMat) override; private: std::shared_ptr<QWidget> m_tools; - ButtonClickCallback m_buttonClickCallback; - SliderChangedCallback m_sliderChangedCallback; + EventHandler &m_events; }; // ====================================== @@ -242,25 +277,6 @@ class SendValueChangedMessage: public GenericSendMessage { const int m_value; }; -// ====================================== -// EVENT HANDLER -// ====================================== - -class EventHandler : public QObject { - Q_OBJECT - public: - void receive(recvString receiveStr); - Q_SIGNALS: - void notifyGUI(std::string, MSGS::MTYPE type = MSGS::MTYPE::NOTIFICATION); - void update(); - // cv::Mat requestCurrentScreen(); - void forceTracking(); - //void registerViews(const std::vector<View> views); - void pausePlayback(bool paused); - void jumpToFrame(int frameNumber); - -}; - } } diff --git a/biotracker/zmq/ZmqProcessHandler.h b/biotracker/zmq/ZmqProcessHandler.h index 521011224fc16faf1fd1b5b67c3c87eeda2127b1..4a522c526fe8007debe00f0941a8eecf65aafbe7 100644 --- a/biotracker/zmq/ZmqProcessHandler.h +++ b/biotracker/zmq/ZmqProcessHandler.h @@ -10,7 +10,9 @@ #include <zmq.h> #include <opencv2/opencv.hpp> #include <QProcess> -#include "zmq/ZmqInfoFile.h" +#include "ZmqInfoFile.h" +#include "ZmqClientProcess.h" +#include "biotracker/util/singleton.h" namespace BioTracker { namespace Core { @@ -19,29 +21,19 @@ namespace Zmq { /** * @brief The ZmqProcessHandler class */ -class ZmqProcessHandler : public QObject { +class ZmqProcessHandler : public QObject, public Util::Singleton<ZmqProcessHandler> { public: Q_OBJECT public: - ZmqProcessHandler(QObject *parent, const ZmqInfoFile info, void *socket); + ZmqProcessHandler(); ~ZmqProcessHandler(); - void stop(); - - void start(); - - Q_SIGNALS: - void onError(std::string errorMessage); - - private Q_SLOTS: - void processBadError(QProcess::ProcessError error); - void processError(); + std::shared_ptr<ZmqClientProcess> startProcess(ZmqInfoFile &info); private: - void *m_socket; + void *m_context; std::mutex m_zmqMutex; - std::unique_ptr<QProcess> m_zmqClient; - + std::shared_ptr<ZmqClientProcess> m_currentProcess; }; }