From 6b5ab0b2a6caf2a75c7e4c527c4319fd58d3791d Mon Sep 17 00:00:00 2001 From: ucart <ucart_groundstation@iastate.edu> Date: Wed, 26 Apr 2017 01:58:52 -0500 Subject: [PATCH] IT WORKS SO WELL! --- groundStation/Makefile | 7 +- groundStation/gui/MicroCART/controlworker.cpp | 142 ++++++++++-------- groundStation/gui/MicroCART/controlworker.h | 6 + groundStation/gui/MicroCART/mainwindow.cpp | 89 ++++++++--- groundStation/gui/MicroCART/mainwindow.h | 12 +- groundStation/gui/MicroCART/mainwindow.ui | 46 ++---- groundStation/gui/MicroCART/trackerworker.cpp | 9 +- groundStation/gui/MicroCART/trackerworker.h | 2 + 8 files changed, 190 insertions(+), 123 deletions(-) diff --git a/groundStation/Makefile b/groundStation/Makefile index c3970786e..e6f47733b 100644 --- a/groundStation/Makefile +++ b/groundStation/Makefile @@ -34,7 +34,7 @@ FECOBJECTS = $(FECSOURCES:$(FESRCDIR)/%.c=$(OBJDIR)/%.o) OBJECTS=$(CLIOBJECTS) $(BECOBJECTS) $(BECPPOBJECTS) $(FECOBJECTS) # Default target -all: quad logs objdir backend cli $(SYMLINKS) frontend.a +all: quad logs objdir backend cli $(SYMLINKS) frontend.a GroundStation quad: $(MAKE) -C ../quad @@ -69,6 +69,11 @@ vrpn/build: mkdir -p src/vrpn/build cd src/vrpn/build && cmake .. && make +GroundStation: + cd gui/MicroCART && qmake-qt5 + cd gui/MicroCART && make + ln -s gui/MicroCART/MicroCART GroundStation + logs: mkdir -p logs diff --git a/groundStation/gui/MicroCART/controlworker.cpp b/groundStation/gui/MicroCART/controlworker.cpp index 0127485bc..aeca8d1ab 100644 --- a/groundStation/gui/MicroCART/controlworker.cpp +++ b/groundStation/gui/MicroCART/controlworker.cpp @@ -5,10 +5,11 @@ #include "graph_blocks.h" #include "frontend_output.h" #include <QProcess> +#include <QDebug> #include <err.h> ControlWorker::ControlWorker(QObject *parent) : - QObject(parent), conn(NULL) + QObject(parent), conn(NULL), nodeIdCache() { } @@ -20,7 +21,12 @@ ControlWorker::~ControlWorker() void ControlWorker::connectBackend() { - conn = ucart_backendConnect(); + if (conn == NULL) { + conn = ucart_backendConnect(); + emit (connected()); + } else { + qInfo() << "Attempted to connect control worker when already connected!"; + } } void ControlWorker::disconnectBackend() @@ -28,6 +34,7 @@ void ControlWorker::disconnectBackend() if (conn) { ucart_backendDisconnect(conn); conn = NULL; + emit (disconnected()); } } @@ -100,32 +107,46 @@ void ControlWorker::getNodes() warn("fopen (/tmp/ucart-tmp-graph.dot)"); } + nodeIdCache.clear(); + for (size_t i = 0; i < num_nodes; i++) { + nodeIdCache[nd[i].name] = nd[i]; + } + /* And here's where I'd put a call to free_graph(), IF I HAD ONE! */ frontend_free_node_data(nd, num_nodes); } } +frontend_node_data ControlWorker::getNodeId(QString node) +{ + if (nodeIdCache.contains(node)) { + return nodeIdCache[node]; + } else { + frontend_node_data nd_invalid; + nd_invalid.block = -1; + nd_invalid.name = NULL; + nd_invalid.type = -1; + return nd_invalid; + } +} + void ControlWorker::getParams(QString node) { if (conn) { - frontend_node_data * nd = NULL; - size_t num_nodes = 0; - frontend_getnodes(conn, &nd, &num_nodes); + frontend_node_data nd = getNodeId(node); + if (nd.block == -1) { + return; + } - for (size_t i = 0; i < num_nodes; i++) { - if (QString(nd[i].name) == node) { - QStringList params; - - /* Get type definition */ - const struct graph_node_type * type = blockDefs[nd[i].type]; - /* Iterate through param names to append, and then emit signal */ - for (ssize_t j = 0; j < type->n_params; j++) { - params.append(QString(type->param_names[j])); - } - emit(gotParams(params)); - } + QStringList params; + + /* Get type definition */ + const struct graph_node_type * type = blockDefs[nd.type]; + /* Iterate through param names to append, and then emit signal */ + for (ssize_t j = 0; j < type->n_params; j++) { + params.append(QString(type->param_names[j])); } - frontend_free_node_data(nd, num_nodes); + emit(gotParams(params)); } } @@ -134,77 +155,66 @@ void ControlWorker::getParams(QString node) void ControlWorker::getParamValue(QString node, QString param) { if (conn) { - frontend_node_data * nd = NULL; - size_t num_nodes = 0; - frontend_getnodes(conn, &nd, &num_nodes); + frontend_node_data nd = getNodeId(node); + if (nd.block == -1) { + return; + } - for (size_t i = 0; i < num_nodes; i++) { - if (QString(nd[i].name) == node) { - frontend_param_data pd; - pd.block = nd[i].block; + frontend_param_data pd; + pd.block = nd.block; - /* Get the type definition, then iterate through to find the param */ - const struct graph_node_type * type = blockDefs[nd[i].type]; - for (ssize_t j = 0; j < type->n_params; j++) { - /* Found param */ - if (QString(type->param_names[j]) == param) { - /* Set pd.param and finish the job */ - pd.param = j; - frontend_getparam(conn, &pd); - emit(gotParamValue(node, param, pd.value)); - } - } + /* Get the type definition, then iterate through to find the param */ + const struct graph_node_type * type = blockDefs[nd.type]; + for (ssize_t j = 0; j < type->n_params; j++) { + /* Found param */ + if (QString(type->param_names[j]) == param) { + /* Set pd.param and finish the job */ + pd.param = j; + frontend_getparam(conn, &pd); + emit(gotParamValue(node, param, pd.value)); } } - frontend_free_node_data(nd, num_nodes); } } void ControlWorker::getNodeOutput(QString node) { if (conn) { - frontend_node_data *nd = NULL; - size_t num_nodes = 0; + frontend_node_data nd = getNodeId(node); + if (nd.block == -1) { + return; + } - frontend_getnodes(conn, &nd, &num_nodes); for (size_t i = 0; i < num_nodes; i++) { - if (QString(nd[i].name) == node) { - frontend_output_data od; - od.block = nd[i].block; + frontend_output_data od; + od.block = nd.block; - od.output = 0; // TODO: Get rid of this assumption + od.output = 0; // TODO: Get rid of this assumption - frontend_getoutput(conn, &od); + frontend_getoutput(conn, &od); - emit(gotNodeOutput(node, od.value)); - } - } - frontend_free_node_data(nd, num_nodes); + emit(gotNodeOutput(node, od.value)); } } void ControlWorker::setParamValue(QString node, QString param, float value) { if (conn) { - frontend_node_data * nd = NULL; - size_t num_nodes = 0; - frontend_getnodes(conn, &nd, &num_nodes); + frontend_node_data nd = getNodeId(node); + if (nd.block == -1) { + return; + } - for (size_t i = 0; i < num_nodes; i++) { - if (QString(nd[i].name) == node) { - frontend_param_data pd; - pd.block = nd[i].block; + frontend_param_data pd; + pd.block = nd.block; - const struct graph_node_type * type = blockDefs[nd[i].type]; - for (ssize_t j = 0; j < type->n_params; j++) { - if (QString(type->param_names[j]) == param) { - pd.param = j; - pd.value = value; - frontend_setparam(conn, &pd); - emit(paramSet(node, param)); - } - } + const struct graph_node_type * type = blockDefs[nd.type]; + for (ssize_t j = 0; j < type->n_params; j++) { + if (QString(type->param_names[j]) == param) { + pd.param = j; + pd.value = value; + frontend_setparam(conn, &pd); + emit(paramSet(node, param)); } } - frontend_free_node_data(nd, num_nodes); } } diff --git a/groundStation/gui/MicroCART/controlworker.h b/groundStation/gui/MicroCART/controlworker.h index c32f46e0d..d0e3b1808 100644 --- a/groundStation/gui/MicroCART/controlworker.h +++ b/groundStation/gui/MicroCART/controlworker.h @@ -3,13 +3,16 @@ #include <QObject> #include <QStringList> +#include <QMap> #include "frontend_common.h" +#include "frontend_nodes.h" class ControlWorker : public QObject { Q_OBJECT public: explicit ControlWorker(QObject *parent = 0); + frontend_node_data getNodeId(QString node); ~ControlWorker(); signals: @@ -20,6 +23,8 @@ signals: void gotConstantBlocks(QStringList blocks); void paramSet(QString node, QString param); void graphRendered(QString graph); + void connected(); + void disconnected(); public slots: void connectBackend(); @@ -32,6 +37,7 @@ public slots: private: struct backend_conn * conn; + QMap<QString, frontend_node_data> nodeIdCache; }; diff --git a/groundStation/gui/MicroCART/mainwindow.cpp b/groundStation/gui/MicroCART/mainwindow.cpp index 0c0b3ffdc..5abedc406 100644 --- a/groundStation/gui/MicroCART/mainwindow.cpp +++ b/groundStation/gui/MicroCART/mainwindow.cpp @@ -7,6 +7,7 @@ #include <QRegExp> #include <QProcessEnvironment> #include <QPixmap> +#include <QProcess> #include "trackerworker.h" #include "controlworker.h" @@ -23,7 +24,10 @@ MainWindow::MainWindow(QWidget *parent) : sp_x(0.0f), sp_y(0.0f), sp_z(0.0f), - trackerTimer(new QTimer(this)) + trackerTimer(new QTimer(this)), + backendProcess(new QProcess(this)), + connectedWorkers(0), + workerStartTimer(new QTimer(this)) { ui->setupUi(this); @@ -33,8 +37,7 @@ MainWindow::MainWindow(QWidget *parent) : topScene->addItem(quad); - /* Set up environment variables */ - ui->socketPath->setText(QProcessEnvironment::systemEnvironment().value("UCART_SOCKET")); + workerStartTimer->setSingleShot(true); /* Create a thread for workers */ QThread* workerThread = new QThread(this); @@ -53,6 +56,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(trackerWorker, SIGNAL (finished(float, float, float, float, float, float)), quad, SLOT(updateQuad(float,float,float,float,float,float))); + backendProcess->setProcessChannelMode(QProcess::MergedChannels); + /* Create another worker for the control graph */ QThread * cwThread = new QThread(this); ControlWorker * controlWorker = new ControlWorker(); @@ -75,11 +80,25 @@ MainWindow::MainWindow(QWidget *parent) : connect(this, SIGNAL (getNodeOutput(QString)), controlWorker, SLOT (getNodeOutput(QString))); /* Connect and disconnect from backend when signals emitted */ + connect(workerStartTimer, SIGNAL (timeout()), trackerWorker, SLOT (connectBackend())); + connect(workerStartTimer, SIGNAL (timeout()), controlWorker, SLOT (connectBackend())); connect(this, SIGNAL (connectWorkers()), trackerWorker, SLOT (connectBackend())); - connect(this, SIGNAL (disconnectWorkers()), trackerWorker, SLOT (disconnectBackend())); connect(this, SIGNAL (connectWorkers()), controlWorker, SLOT (connectBackend())); + connect(this, SIGNAL (disconnectWorkers()), trackerWorker, SLOT (disconnectBackend())); connect(this, SIGNAL (disconnectWorkers()), controlWorker, SLOT (disconnectBackend())); + connect(backendProcess, SIGNAL (started()), this, SLOT (backendStarted())); + connect(backendProcess, SIGNAL (errorOccurred(QProcess::ProcessError)), this, SLOT (backendError(QProcess::ProcessError))); + connect(backendProcess, SIGNAL (finished(int, QProcess::ExitStatus)), this, SLOT (backendFinished(int, QProcess::ExitStatus))); + connect(backendProcess, SIGNAL (readyReadStandardOutput()), this, SLOT (backendRead())); + connect(backendProcess, SIGNAL (readyReadStandardError()), this, SLOT (backendRead())); + + connect(controlWorker, SIGNAL (connected()), this, SLOT (workerConnected())); + connect(controlWorker, SIGNAL (disconnected()), this, SLOT (workerDisconnected())); + + connect(trackerWorker, SIGNAL (connected()), this, SLOT (workerConnected())); + connect(trackerWorker, SIGNAL (disconnected()), this, SLOT (workerDisconnected())); + /* Connect refresh button and refresh timer to tracker worker */ connect(trackerTimer, SIGNAL(timeout()), this, SLOT(updatePosAtt())); connect(ui->pbRefresh, SIGNAL (clicked()), this, SLOT (updatePosAtt())); @@ -153,33 +172,72 @@ void MainWindow::updateTracker(float x, float y, float z, float p, float r, floa void MainWindow::on_pbStart_clicked() { - QProcessEnvironment::systemEnvironment().insert("UCART_SOCKET", ui->socketPath->text()); + backendProcess->setProgram(ui->backendPath->text()); + + backendProcess->start(); +} + +void MainWindow::backendStarted() +{ ui->pbStart->setEnabled(false); ui->pbStop->setEnabled(true); + workerStartTimer->start(750); +} + +void MainWindow::backendError(QProcess::ProcessError error) +{ + ui->vConsole->append(backendProcess->errorString()); +} + +void MainWindow::backendRead() +{ + ui->vConsole->append(backendProcess->readAll()); +} + +void MainWindow::workerConnected() +{ + connectedWorkers++; + if (connectedWorkers == 2) { + ui->pbStart->setEnabled(false); + ui->pbConnect->setEnabled(false); + ui->pbStop->setEnabled(true); + } +} + +void MainWindow::workerDisconnected() +{ + connectedWorkers--; + if (( connectedWorkers == 0) && (backendProcess->state() == QProcess::Running)) { + backendProcess->terminate(); + } else if (connectedWorkers == 0) { + ui->pbStart->setEnabled(true); + ui->pbConnect->setEnabled(true); + ui->pbStop->setEnabled(false); + } +} + +void MainWindow::backendFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + ui->pbStart->setEnabled(true); + ui->pbConnect->setEnabled(true); + ui->pbStop->setEnabled(false); } void MainWindow::on_pbConnect_clicked() { - QProcessEnvironment::systemEnvironment().insert("UCART_SOCKET", ui->socketPath->text()); - ui->pbStart->setEnabled(false); - ui->pbConnect->setEnabled(false); - ui->pbStop->setEnabled(true); emit(connectWorkers()); } void MainWindow::on_pbStop_clicked() { emit(disconnectWorkers()); - ui->pbStart->setEnabled(true); - ui->pbConnect->setEnabled(true); - ui->pbStop->setEnabled(false); } void MainWindow::on_chooseBackend_clicked() { QString backendPath = QFileDialog::getOpenFileName(this, tr("Path to Backend Executable")); - ui->backendPath_2->setText(backendPath); + ui->backendPath->setText(backendPath); } @@ -488,11 +546,6 @@ void MainWindow::on_pbLoadWaypoints_clicked() } } -void MainWindow::on_socketPath_returnPressed() -{ - QProcessEnvironment::systemEnvironment().insert("UCART_SOCKET", ui->socketPath->text()); -} - void MainWindow::on_xSetpoint_returnPressed() { sp_x = ui->xSetpoint->text().toFloat(); diff --git a/groundStation/gui/MicroCART/mainwindow.h b/groundStation/gui/MicroCART/mainwindow.h index a67d22907..db5534abe 100644 --- a/groundStation/gui/MicroCART/mainwindow.h +++ b/groundStation/gui/MicroCART/mainwindow.h @@ -74,8 +74,6 @@ private slots: void on_pbLoadWaypoints_clicked(); - void on_socketPath_returnPressed(); - void on_xSetpoint_returnPressed(); void on_ySetpoint_returnPressed(); @@ -88,6 +86,13 @@ private slots: void on_yawSetpoint_returnPressed(); + void backendStarted(); + void backendFinished(int exitCode, QProcess::ExitStatus exitStatus); + void backendError(QProcess::ProcessError error); + void backendRead(); + void workerConnected(); + void workerDisconnected(); + private: Ui::MainWindow *ui; QStandardItemModel * setpointList; @@ -96,6 +101,9 @@ private: float sp_y; float sp_z; QTimer * trackerTimer; + QTimer * workerStartTimer; + QProcess * backendProcess; + int connectedWorkers; }; #endif // MAINWINDOW_H diff --git a/groundStation/gui/MicroCART/mainwindow.ui b/groundStation/gui/MicroCART/mainwindow.ui index da97a7a4b..1fc6dfc6a 100644 --- a/groundStation/gui/MicroCART/mainwindow.ui +++ b/groundStation/gui/MicroCART/mainwindow.ui @@ -26,42 +26,24 @@ </attribute> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <layout class="QFormLayout" name="formLayout_3"> - <item row="0" column="0"> - <widget class="QLabel" name="socketPathLabel"> - <property name="text"> - <string>UCART_SOCKET_PATH</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="socketPath"> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QLineEdit" name="backendPath"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="text"> - <string/> + <string>./BackEnd</string> </property> </widget> </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_8"> <item> <widget class="QPushButton" name="chooseBackend"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="text"> - <string>Choose Backend</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="backendPath_2"> - <property name="enabled"> - <bool>false</bool> + <string>Choose...</string> </property> </widget> </item> @@ -72,7 +54,7 @@ <item> <widget class="QPushButton" name="pbStart"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="text"> <string>Start</string> @@ -115,17 +97,11 @@ </layout> </item> <item> - <spacer name="verticalSpacer"> + <widget class="Line" name="line_7"> <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>155</height> - </size> + <enum>Qt::Horizontal</enum> </property> - </spacer> + </widget> </item> <item> <widget class="QTextEdit" name="vConsole"> diff --git a/groundStation/gui/MicroCART/trackerworker.cpp b/groundStation/gui/MicroCART/trackerworker.cpp index 13d9c15bc..7eb9456d2 100644 --- a/groundStation/gui/MicroCART/trackerworker.cpp +++ b/groundStation/gui/MicroCART/trackerworker.cpp @@ -3,6 +3,7 @@ #include "frontend_common.h" #include "frontend_tracker.h" #include "quaditem.h" +#include <QDebug> TrackerWorker::TrackerWorker() : QObject(), conn(NULL) @@ -16,7 +17,12 @@ TrackerWorker::~TrackerWorker() void TrackerWorker::connectBackend() { - conn = ucart_backendConnect(); + if (conn == NULL) { + conn = ucart_backendConnect(); + emit (connected()); + } else { + qInfo() << "Attempted to connect trackerworker when already connected!"; + } } void TrackerWorker::disconnectBackend() @@ -24,6 +30,7 @@ void TrackerWorker::disconnectBackend() if (conn) { ucart_backendDisconnect(conn); conn = NULL; + emit (disconnected()); } } diff --git a/groundStation/gui/MicroCART/trackerworker.h b/groundStation/gui/MicroCART/trackerworker.h index b263d6078..8abbacc51 100644 --- a/groundStation/gui/MicroCART/trackerworker.h +++ b/groundStation/gui/MicroCART/trackerworker.h @@ -15,6 +15,8 @@ public: signals: void finished(float, float, float, float, float, float); + void connected(); + void disconnected(); public slots: void process(); -- GitLab