From 7e640165dad58d273496588866542ff59f0e17f5 Mon Sep 17 00:00:00 2001 From: Hoop77 <p.badenhoop@gmx.de> Date: Mon, 14 May 2018 14:46:54 +0200 Subject: [PATCH] Message gui --- .../MessageLib/include/MessageLib/Client.h | 57 ++++- .../catkin_ws/src/MessageLib/src/Client.cpp | 72 +++++-- .../src/MessageLib/test/ServerClientTest.cpp | 30 +-- modules/catkin_ws/src/PCGui/.gitignore | 3 +- .../catkin_ws/src/PCGui/PCGui/CMakeLists.txt | 49 +++-- .../PCGui/PCGui/{main.qml => CommandGui.qml} | 2 +- .../catkin_ws/src/PCGui/PCGui/MessageGui.qml | 142 +++++++++++++ .../src/PCGui/PCGui/include/Logger.h | 69 ------ .../src/PCGui/PCGui/include/MessageList.h | 32 +++ .../src/PCGui/PCGui/include/MessageModel.h | 38 ++++ .../src/PCGui/PCGui/include/MessageProducer.h | 23 ++ .../include/QtQuickControlsApplication.h | 24 +++ .../PCGui/include/SortFilterProxyModel.h | 121 +++++++++++ modules/catkin_ws/src/PCGui/PCGui/qml.qrc | 3 +- .../PCGui/src/{main.cpp => CommandGui.cpp} | 2 +- .../catkin_ws/src/PCGui/PCGui/src/Logger.cpp | 48 ----- .../src/PCGui/PCGui/src/MessageGui.cpp | 54 +++++ .../src/PCGui/PCGui/src/MessageList.cpp | 21 ++ .../src/PCGui/PCGui/src/MessageModel.cpp | 78 +++++++ .../PCGui/PCGui/src/SortFilterProxyModel.cpp | 199 ++++++++++++++++++ .../{noUss.launch => noHardware.launch} | 1 - .../catkin_ws/src/car/src/mavLink/MavLink.cpp | 6 +- 22 files changed, 886 insertions(+), 188 deletions(-) rename modules/catkin_ws/src/PCGui/PCGui/{main.qml => CommandGui.qml} (77%) create mode 100644 modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/Logger.h create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/QtQuickControlsApplication.h create mode 100644 modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h rename modules/catkin_ws/src/PCGui/PCGui/src/{main.cpp => CommandGui.cpp} (80%) delete mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/Logger.cpp create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp create mode 100644 modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp rename modules/catkin_ws/src/car/launch/{noUss.launch => noHardware.launch} (88%) diff --git a/modules/catkin_ws/src/MessageLib/include/MessageLib/Client.h b/modules/catkin_ws/src/MessageLib/include/MessageLib/Client.h index 18365c3a..201d8055 100644 --- a/modules/catkin_ws/src/MessageLib/include/MessageLib/Client.h +++ b/modules/catkin_ws/src/MessageLib/include/MessageLib/Client.h @@ -30,18 +30,22 @@ public: using OnMessageProcessedCallback = std::function<void(const Message & message)>; using OnRequestFinishedCallback = std::function<void(const networking::error::ErrorCode & error)>; - static constexpr std::size_t MAX_MESSAGE_SIZE{1024}; + static Ptr create(networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize=1024) + { return std::make_shared<Client>(PrivateTag{}, net, port, maxBufferSize); } - static Ptr create(networking::Networking & net, std::uint16_t port) - { return std::make_shared<Client>(PrivateTag{}, net, port); } - - Client(PrivateTag, networking::Networking & net, std::uint16_t port); + Client(PrivateTag, networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize); void requestMessages(const std::string & host, const networking::time::Duration & timeout, - const Client::OnMessageProcessedCallback & onMessageProcessedCallback, - const Client::OnRequestFinishedCallback & onRequestFinishedCallback = - [](const auto & error) {}); + const OnMessageProcessedCallback & onMessageProcessedCallback, + const OnRequestFinishedCallback & onRequestFinishedCallback = [](const auto & error) {}); + + void requestMessagesPeriodically(const std::string & host, + const networking::time::Duration & requestInterval, + const networking::time::Duration & retryInterval, + const OnMessageProcessedCallback & onMessageProcessedCallback, + const OnRequestFinishedCallback & onRequestFinishedCallback = + [](const auto & error) {}); void stop(); @@ -65,10 +69,47 @@ private: OnRequestFinishedCallback onRequestFinishedCallback; }; + struct PeriodicAsyncState + { + using Ptr = std::shared_ptr<PeriodicAsyncState>; + + PeriodicAsyncState(Client::Ptr self, + const std::string & host, + const networking::time::Duration & requestInterval, + const networking::time::Duration & retryInterval, + const OnMessageProcessedCallback & onMessageProcessedCallback, + const OnRequestFinishedCallback & onRequestFinishedCallback) + : lock(*self) + , self(self) + , host(host) + , requestInterval(requestInterval) + , retryInterval(retryInterval) + , onMessageProcessedCallback(onMessageProcessedCallback) + , onRequestFinishedCallback(onRequestFinishedCallback) + {} + + networking::BusyLock lock; + Client::Ptr self; + std::string host; + networking::time::Duration requestInterval; + networking::time::Duration retryInterval; + OnMessageProcessedCallback onMessageProcessedCallback; + OnRequestFinishedCallback onRequestFinishedCallback; + }; + networking::Networking & net; std::uint16_t port; ServiceClient::Ptr client; Parser parser; + networking::time::Timer::Ptr timer; + std::atomic<bool> requesting{false}; + + void processResponse(const std::string & response, + const OnMessageProcessedCallback & onMessageProcessedCallback); + + void scheduleNextRequest(PeriodicAsyncState::Ptr state, const networking::time::Duration & waitTime); + + void nextRequest(PeriodicAsyncState::Ptr state); }; } diff --git a/modules/catkin_ws/src/MessageLib/src/Client.cpp b/modules/catkin_ws/src/MessageLib/src/Client.cpp index 2f6e4711..a00ef36c 100644 --- a/modules/catkin_ws/src/MessageLib/src/Client.cpp +++ b/modules/catkin_ws/src/MessageLib/src/Client.cpp @@ -8,10 +8,11 @@ namespace message { -Client::Client(Client::PrivateTag, networking::Networking & net, std::uint16_t port) +Client::Client(Client::PrivateTag, networking::Networking & net, std::uint16_t port, std::size_t maxBufferSize) : net(net), port(port) { - client = ServiceClient::create(net, MAX_MESSAGE_SIZE); + client = ServiceClient::create(net, maxBufferSize); + timer = networking::time::Timer::create(net); } void Client::requestMessages(const std::string & host, @@ -25,30 +26,75 @@ void Client::requestMessages(const std::string & host, std::string emptyRequest; client->asyncCall( emptyRequest, host, port, timeout, - [state](const auto & error, auto & responseMessage) + [state](const auto & error, const auto & responseMessage) { if (error) { state->onRequestFinishedCallback(error); return; } - - if (!responseMessage.empty()) - { - auto & parser = state->self->parser; - parser << responseMessage; - Message message; - while (parser >> message) - state->onMessageProcessedCallback(message); - } - + state->self->processResponse(responseMessage, state->onMessageProcessedCallback); state->onRequestFinishedCallback(error); }); } +void Client::requestMessagesPeriodically(const std::string & host, + const networking::time::Duration & requestInterval, + const networking::time::Duration & retryInterval, + const OnMessageProcessedCallback & onMessageProcessedCallback, + const OnRequestFinishedCallback & onRequestFinishedCallback) +{ + auto self = shared_from_this(); + auto state = std::make_shared<PeriodicAsyncState>( + self, host, requestInterval, retryInterval, onMessageProcessedCallback, onRequestFinishedCallback); + requesting = true; + nextRequest(std::move(state)); +} + void Client::stop() { client->stop(); + timer->stop(); + requesting = false; +} + +void Client::processResponse(const std::string & response, + const OnMessageProcessedCallback & onMessageProcessedCallback) +{ + if (!response.empty()) + { + parser << response; + Message message; + while (parser >> message) + onMessageProcessedCallback(message); + } +} + +void Client::nextRequest(PeriodicAsyncState::Ptr state) +{ + using namespace std::chrono_literals; + + if (!requesting) + return; + + std::string emptyRequest; + net.waitWhileBusy(*(state->self->client)); + client->asyncCall( + emptyRequest, state->host, state->self->port, state->retryInterval, + [state](const auto & error, const auto & responseMessage) + { + auto & self = state->self; + if (error) + { + state->onRequestFinishedCallback(error); + self->net.callLater([state] { state->self->nextRequest(state); }); + return; + } + self->processResponse(responseMessage, state->onMessageProcessedCallback); + state->onRequestFinishedCallback(error); + self->timer->startTimeout( + state->requestInterval, [state] { state->self->nextRequest(state); }); + }); } } diff --git a/modules/catkin_ws/src/MessageLib/test/ServerClientTest.cpp b/modules/catkin_ws/src/MessageLib/test/ServerClientTest.cpp index 7b8f7a9a..969b82ac 100644 --- a/modules/catkin_ws/src/MessageLib/test/ServerClientTest.cpp +++ b/modules/catkin_ws/src/MessageLib/test/ServerClientTest.cpp @@ -41,38 +41,16 @@ void fromLocal() while (running); } -void requestNextMessages(networking::Networking & net, - networking::time::Timer::Ptr timer, - message::Client::Ptr client, - const networking::time::Duration & delay) -{ - using namespace std::chrono_literals; - timer->startTimeout(delay, [&net, timer, client] - { - net.waitWhileBusy(*client); - client->requestMessages( - "127.0.0.1", 10s, - [](const auto & message) { printMessage(message); }, - [&net, timer, client](const auto & error) - { - if (error) - { - std::cerr << "Could not connect to car!\n"; - requestNextMessages(net, timer, client, 3s); - } - else requestNextMessages(net, timer, client, 10ms); - }); - }); -} - void fromCar() { using namespace message; using namespace std::chrono_literals; networking::Networking net; auto client = Client::create(net, 10207); - auto timer = networking::time::Timer::create(net); - requestNextMessages(net, timer, client, 10ms); + client->requestMessagesPeriodically( + "127.0.0.1", 10ms, 3s, + [](const auto & message) { printMessage(message); }, + [](const auto & error) { if (error) std::cerr << "Could not connect to car!\n"; }); while (1); } diff --git a/modules/catkin_ws/src/PCGui/.gitignore b/modules/catkin_ws/src/PCGui/.gitignore index 46e00774..9b34f868 100644 --- a/modules/catkin_ws/src/PCGui/.gitignore +++ b/modules/catkin_ws/src/PCGui/.gitignore @@ -1,3 +1,4 @@ .vscode/ build-PCGui-Desktop_Qt_5_7_1_GCC_64bit-Default/ -CMakeLists.txt.* \ No newline at end of file +CMakeLists.txt.* +cmake-build-debug/ \ No newline at end of file diff --git a/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt b/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt index b4caae0f..ac4fc842 100644 --- a/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt +++ b/modules/catkin_ws/src/PCGui/PCGui/CMakeLists.txt @@ -2,12 +2,10 @@ cmake_minimum_required(VERSION 3.5.1) project(PCGui LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 14) - set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS Core Quick REQUIRED) @@ -20,17 +18,38 @@ find_package(Boost REQUIRED COMPONENTS regex system) find_package(NetworkingLib REQUIRED) find_package(PlatoonProtocolLib REQUIRED) find_package(PC2CarLib REQUIRED) +find_package(MessageLib REQUIRED) + +set(LIBS + Qt5::Core Qt5::Quick + NetworkingLib + PlatoonProtocolLib + PC2CarLib + MessageLib) + +set(INCLUDE_DIRS + ${PC2CarLib_INCLUDE_DIRS} + ${MessageLib_INCLUDE_DIRS}) set(SOURCE_FILES - include/Logger.h - src/Logger.cpp - src/main.cpp - qml.qrc) - -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) -target_link_libraries(${PROJECT_NAME} - Qt5::Core Qt5::Quick - NetworkingLib - PlatoonProtocolLib - PC2CarLib) -target_include_directories(${PROJECT_NAME} PUBLIC ${PC2CarLib_INCLUDE_DIRS}) + include/QtQuickControlsApplication.h + qml.qrc) + +add_executable(CommandGui ${SOURCE_FILES} + src/CommandGui.cpp) + +add_executable(MessageGui ${SOURCE_FILES} + include/SortFilterProxyModel.h + include/MessageModel.h + include/MessageList.h + include/MessageProducer.h + src/MessageGui.cpp + src/MessageModel.cpp + src/MessageList.cpp + src/SortFilterProxyModel.cpp) + +target_link_libraries(CommandGui ${LIBS}) +target_link_libraries(MessageGui ${LIBS}) + +target_include_directories(CommandGui PUBLIC ${INCLUDE_DIRS}) +target_include_directories(MessageGui PUBLIC ${INCLUDE_DIRS}) diff --git a/modules/catkin_ws/src/PCGui/PCGui/main.qml b/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml similarity index 77% rename from modules/catkin_ws/src/PCGui/PCGui/main.qml rename to modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml index e097a0e4..9a40ba2d 100644 --- a/modules/catkin_ws/src/PCGui/PCGui/main.qml +++ b/modules/catkin_ws/src/PCGui/PCGui/CommandGui.qml @@ -5,5 +5,5 @@ Window { visible: true width: 640 height: 480 - title: qsTr("Hello World") + title: qsTr("Command Gui") } diff --git a/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml b/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml new file mode 100644 index 00000000..45d0b62e --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/MessageGui.qml @@ -0,0 +1,142 @@ +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 +import car.pcgui 1.0 + +ApplicationWindow { + id: window + visible: true + title: "Message Gui" + + toolBar: ToolBar { + height: 180 + + Label { + id: moduleLabel + text: "Module: " + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.top: parent.top + anchors.topMargin: 20 + } + + TextField { + id: moduleSearchBox + + placeholderText: "Search..." + inputMethodHints: Qt.ImhNoPredictiveText + + anchors.left: moduleLabel.right + anchors.leftMargin: 10 + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.verticalCenter: moduleLabel.verticalCenter + } + + Label { + id: keyLabel + text: "Key: " + anchors.left: moduleLabel.left + anchors.top: moduleLabel.bottom + anchors.topMargin: 20 + } + + TextField { + id: keySearchBox + + placeholderText: "Search..." + inputMethodHints: Qt.ImhNoPredictiveText + + anchors.left: moduleSearchBox.left + anchors.right: moduleSearchBox.right + anchors.verticalCenter: keyLabel.verticalCenter + } + + CheckBox { + id: mostRecentCheckBox + text: "show only most recent values" + checked: false + + anchors.left: moduleLabel.left + anchors.top: keyLabel.bottom + anchors.topMargin: 20 + } + + Label { + id: statusLabel + text: "Status:" + + anchors.left: moduleLabel.left + anchors.top: mostRecentCheckBox.bottom + anchors.topMargin: 20 + } + + Label { + id: status + text: "Disconnected" + color: "red" + + anchors.left: moduleSearchBox.left + anchors.top: statusLabel.top + } + } + + TableView { + id: tableView + + frameVisible: false + sortIndicatorVisible: true + + anchors.fill: parent + + Layout.minimumWidth: 400 + Layout.minimumHeight: 240 + Layout.preferredWidth: 600 + Layout.preferredHeight: 400 + + TableViewColumn { + id: moduleColumn + title: "Module" + role: "module" + movable: false + resizable: true + width: tableView.viewport.width / 3 + } + + TableViewColumn { + id: keyColumn + title: "Key" + role: "key" + movable: false + resizable: true + width: tableView.viewport.width / 3 + } + + TableViewColumn { + id: valueColumn + title: "Value" + role: "value" + movable: false + resizable: true + width: tableView.viewport.width / 3 + } + + // model: SortFilterProxyModel { + // id: proxyModel + // source: sourceModel.count > 0 ? sourceModel : null + + // sortOrder: tableView.sortIndicatorOrder + // sortCaseSensitivity: Qt.CaseInsensitive + // sortRole: sourceModel.count > 0 ? tableView.getColumn(tableView.sortIndicatorColumn).role : "" + + // filterString: moduleSearchBox.text + // filterSyntax: SortFilterProxyModel.FixedString + // filterCaseSensitivity: Qt.CaseInsensitive + // } + + model: MessageModel { + id: messageModel + messageList: messages + } + } +} diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/Logger.h b/modules/catkin_ws/src/PCGui/PCGui/include/Logger.h deleted file mode 100644 index a78e9897..00000000 --- a/modules/catkin_ws/src/PCGui/PCGui/include/Logger.h +++ /dev/null @@ -1,69 +0,0 @@ -// -// Created by philipp on 08.05.18. -// - -#ifndef PC_LOGGER_H -#define PC_LOGGER_H - -#include <memory> -#include <NetworkingLib/Networking.h> -#include <NetworkingLib/ServiceClient.h> - -namespace pc -{ - -class Logger - : public std::enable_shared_from_this<Logger> - , private networking::Busyable -{ -private: - struct PrivateTag - { - }; - - struct LoggingService - { - using RequestMessage = std::string; - using ResponseMessage = std::string; - }; - -public: - using Ptr = std::shared_ptr<Logger>; - using LoggingClient = networking::service::Client<LoggingService>; - - static constexpr std::size_t PORT{10207}; - static constexpr std::size_t MAX_MESSAGE_SIZE{1024}; - - static Ptr create(networking::Networking & net, const std::string & host) - { return std::make_shared<Logger>(PrivateTag{}, net, host); } - - Logger(PrivateTag, networking::Networking & net, const std::string & host); - - void start(); - - void stop(); - -private: - struct AsyncState - { - using Ptr = std::shared_ptr<AsyncState>; - - AsyncState(Logger::Ptr self) - : lock(*self), self(self) - {} - - networking::BusyLock lock; - Logger::Ptr self; - }; - - networking::Networking & net; - std::string host; - LoggingClient::Ptr client; - networking::time::Timer::Ptr timer; - - void log(AsyncState::Ptr state); -}; - -} - -#endif //PC_LOGGER_H diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h new file mode 100644 index 00000000..06ada7ef --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageList.h @@ -0,0 +1,32 @@ +// +// Created by philipp on 13.05.18. +// + +#ifndef PCGUI_MESSAGELIST_H +#define PCGUI_MESSAGELIST_H + +#include <QObject> +#include <MessageLib/Message.h> +#include <QtCore/QVector> + +class MessageList : public QObject +{ + Q_OBJECT + +public: + explicit MessageList(QObject * parent = nullptr); + + const QVector<message::Message> & getItems() const noexcept; + +signals: + void preMessageAppended(); + void postMessageAppended(); + +public slots: + void appendMessage(const message::Message & message); + +private: + QVector<message::Message> items; +}; + +#endif //PCGUI_MESSAGELIST_H diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h new file mode 100644 index 00000000..3434974b --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageModel.h @@ -0,0 +1,38 @@ +#ifndef MESSAGEMODEL_H +#define MESSAGEMODEL_H + +#include <QAbstractListModel> +#include "MessageLib/Message.h" +#include "MessageList.h" + +class MessageModel : public QAbstractListModel +{ +Q_OBJECT + +Q_PROPERTY(MessageList * messageList READ getMessageList WRITE setMessageList) + +public: + explicit MessageModel(QObject * parent = nullptr); + + enum + { + ModuleRole = Qt::UserRole, + KeyRole, + ValueRole + }; + + int rowCount(const QModelIndex & parent = QModelIndex()) const override; + + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; + + QHash<int, QByteArray> roleNames() const override; + + MessageList * getMessageList() const noexcept; + + void setMessageList(MessageList * newMessageList); + +private: + MessageList * messageList; +}; + +#endif // MESSAGEMODEL_H \ No newline at end of file diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h b/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h new file mode 100644 index 00000000..04d36010 --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/include/MessageProducer.h @@ -0,0 +1,23 @@ +// +// Created by philipp on 14.05.18. +// + +#ifndef PCGUI_MESSAGEPRODUCER_H +#define PCGUI_MESSAGEPRODUCER_H + +#include <QObject> +#include "MessageLib/Message.h" + +class MessageProducer : public QObject +{ +Q_OBJECT + +public: + void produceMessage(const message::Message & message) + { emit messageProduced(message); } + +signals: + void messageProduced(message::Message); +}; + +#endif //PCGUI_MESSAGEPRODUCER_H diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/QtQuickControlsApplication.h b/modules/catkin_ws/src/PCGui/PCGui/include/QtQuickControlsApplication.h new file mode 100644 index 00000000..a35ca7e5 --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/include/QtQuickControlsApplication.h @@ -0,0 +1,24 @@ +// +// Created by philipp on 13.05.18. +// + +#ifndef PCGUI_QTQUICKCONTROLSAPPLICATION_H +#define PCGUI_QTQUICKCONTROLSAPPLICATION_H + +#ifdef QT_WIDGETS_LIB +#include <QtWidgets/QApplication> +#else +#include <QtGui/QGuiApplication> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QT_WIDGETS_LIB +#define QtQuickControlsApplication QApplication +#else +#define QtQuickControlsApplication QGuiApplication +#endif + +QT_END_NAMESPACE + +#endif //PCGUI_QTQUICKCONTROLSAPPLICATION_H diff --git a/modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h b/modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h new file mode 100644 index 00000000..08b81a85 --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/include/SortFilterProxyModel.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SORTFILTERPROXYMODEL_H +#define SORTFILTERPROXYMODEL_H + +#include <QtCore/qsortfilterproxymodel.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qjsvalue.h> + +class SortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(QObject *source READ source WRITE setSource) + + Q_PROPERTY(QByteArray sortRole READ sortRole WRITE setSortRole) + Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder) + + Q_PROPERTY(QByteArray filterRole READ filterRole WRITE setFilterRole) + Q_PROPERTY(QString filterString READ filterString WRITE setFilterString) + Q_PROPERTY(FilterSyntax filterSyntax READ filterSyntax WRITE setFilterSyntax) + + Q_ENUMS(FilterSyntax) + +public: + explicit SortFilterProxyModel(QObject *parent = 0); + + QObject *source() const; + void setSource(QObject *source); + + QByteArray sortRole() const; + void setSortRole(const QByteArray &role); + + void setSortOrder(Qt::SortOrder order); + + QByteArray filterRole() const; + void setFilterRole(const QByteArray &role); + + QString filterString() const; + void setFilterString(const QString &filter); + + enum FilterSyntax { + RegExp, + Wildcard, + FixedString + }; + + FilterSyntax filterSyntax() const; + void setFilterSyntax(FilterSyntax syntax); + + int count() const; + Q_INVOKABLE QJSValue get(int index) const; + + void classBegin(); + void componentComplete(); + +signals: + void countChanged(); + +protected: + int roleKey(const QByteArray &role) const; + QHash<int, QByteArray> roleNames() const; + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + +private: + bool m_complete; + QByteArray m_sortRole; + QByteArray m_filterRole; +}; + +#endif // SORTFILTERPROXYMODEL_H diff --git a/modules/catkin_ws/src/PCGui/PCGui/qml.qrc b/modules/catkin_ws/src/PCGui/PCGui/qml.qrc index 5f6483ac..23750ca0 100644 --- a/modules/catkin_ws/src/PCGui/PCGui/qml.qrc +++ b/modules/catkin_ws/src/PCGui/PCGui/qml.qrc @@ -1,5 +1,6 @@ <RCC> <qresource prefix="/"> - <file>main.qml</file> + <file>CommandGui.qml</file> + <file>MessageGui.qml</file> </qresource> </RCC> diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/main.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp similarity index 80% rename from modules/catkin_ws/src/PCGui/PCGui/src/main.cpp rename to modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp index f3de8b09..04741d3d 100644 --- a/modules/catkin_ws/src/PCGui/PCGui/src/main.cpp +++ b/modules/catkin_ws/src/PCGui/PCGui/src/CommandGui.cpp @@ -6,7 +6,7 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + engine.load(QUrl(QStringLiteral("qrc:/CommandGui.qml"))); if (engine.rootObjects().isEmpty()) return -1; diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/Logger.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/Logger.cpp deleted file mode 100644 index 7d5588cb..00000000 --- a/modules/catkin_ws/src/PCGui/PCGui/src/Logger.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Created by philipp on 08.05.18. -// - -#include "../include/Logger.h" -#include <iostream> - -namespace pc -{ - -Logger::Logger(Logger::PrivateTag, networking::Networking & net, const std::string & host) - : net(net), host(host) -{ - client = LoggingClient::create(net, MAX_MESSAGE_SIZE); - timer = networking::time::Timer::create(net); -} - -void Logger::start() -{ - auto self = shared_from_this(); - auto state = std::make_shared<AsyncState>(self); - log(state); -} - -void Logger::stop() -{ - timer->stop(); - client->stop(); -} - -void Logger::log(AsyncState::Ptr state) -{ - using namespace std::chrono_literals; - std::string emptyRequest; - client->asyncCall( - emptyRequest, host, PORT, 10s, - [state](const auto & error, auto & responseMessage) - { - if (!responseMessage.empty()) - std::cout << responseMessage; - - state->self->timer->startTimeout(1ms, [state] - { state->self->log(state); }); - }); -} - -} - diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp new file mode 100644 index 00000000..7dcf04af --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageGui.cpp @@ -0,0 +1,54 @@ +#include "../include/QtQuickControlsApplication.h" +#include "../include/SortFilterProxyModel.h" +#include <QtQml/qqmlapplicationengine.h> +#include <QtGui/qsurfaceformat.h> +#include <QtQml/qqml.h> +#include <QtQml/QQmlContext> +#include <include/MessageModel.h> +#include "NetworkingLib/Networking.h" +#include "MessageLib/Client.h" +#include <chrono> +#include <iostream> +#include <include/MessageProducer.h> + +Q_DECLARE_METATYPE(message::Message); + +int main(int argc, char * argv[]) +{ + using namespace std::chrono_literals; + + qmlRegisterType<SortFilterProxyModel>("car.pcgui", 1, 0, "SortFilterProxyModel"); + qmlRegisterType<MessageModel>("car.pcgui", 1, 0, "MessageModel"); + qRegisterMetaType<message::Message>(); + qmlRegisterUncreatableType<MessageList>( + "car.pcgui", 1, 0, "MessageList", QStringLiteral("MessageList should not be created in QML")); + + networking::Networking net; + auto messageClient = message::Client::create(net, 10207); + MessageList messages; + MessageProducer producer; + QObject::connect(&producer, SIGNAL(messageProduced(message::Message)), + &messages, SLOT(appendMessage(const message::Message &))); + + QtQuickControlsApplication app(argc, argv); + if (QCoreApplication::arguments().contains(QLatin1String("--coreprofile"))) + { + QSurfaceFormat fmt; + fmt.setVersion(4, 4); + fmt.setProfile(QSurfaceFormat::CoreProfile); + QSurfaceFormat::setDefaultFormat(fmt); + } + + QQmlApplicationEngine engine{}; + engine.rootContext()->setContextProperty(QStringLiteral("messages"), &messages); + engine.load(QUrl("qrc:/MessageGui.qml")); + if (engine.rootObjects().isEmpty()) + return -1; + + messageClient->requestMessagesPeriodically( + "127.0.0.1", 10ms, 3s, + [&producer](const auto & message) + { producer.produceMessage(message); }); + + return app.exec(); +} diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp new file mode 100644 index 00000000..9fc693b9 --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageList.cpp @@ -0,0 +1,21 @@ +// +// Created by philipp on 13.05.18. +// + +#include "../include/MessageList.h" + +MessageList::MessageList(QObject * parent) : QObject(parent) +{ +} + +const QVector<message::Message> & MessageList::getItems() const noexcept +{ + return items; +} + +void MessageList::appendMessage(const message::Message & message) +{ + emit preMessageAppended(); + items.append(message); + emit postMessageAppended(); +} diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp new file mode 100644 index 00000000..b305119a --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/src/MessageModel.cpp @@ -0,0 +1,78 @@ +#include "../include/MessageModel.h" + +MessageModel::MessageModel(QObject * parent) + : QAbstractListModel(parent) + , messageList(nullptr) +{ +} + +int MessageModel::rowCount(const QModelIndex & parent) const +{ + // For list models only the root node (an invalid parent) should return the list's size. For all + // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. + if (parent.isValid() || !messageList) + return 0; + + return messageList->getItems().size(); +} + +QVariant MessageModel::data(const QModelIndex & index, int role) const +{ + if (!index.isValid() || !messageList) + return QVariant{}; + + auto message = messageList->getItems().at(index.row()); + switch (role) + { + case ModuleRole: + return QVariant{QString::fromStdString(message.module)}; + + case KeyRole: + return QVariant{QString::fromStdString(message.key)}; + + case ValueRole: + return QVariant{QString::fromStdString(message.value)}; + } + + return QVariant{}; +} + +QHash<int, QByteArray> MessageModel::roleNames() const +{ + QHash<int, QByteArray> names; + names[ModuleRole] = "module"; + names[KeyRole] = "key"; + names[ValueRole] = "value"; + return names; +} + +MessageList * MessageModel::getMessageList() const noexcept +{ + return messageList; +} + +void MessageModel::setMessageList(MessageList * newMessageList) +{ + beginResetModel(); + + if (messageList) + messageList->disconnect(this); + + messageList = newMessageList; + + if (messageList) + { + connect(messageList, &MessageList::preMessageAppended, this, [this] + { + int index = messageList->getItems().size(); + beginInsertRows(QModelIndex{}, index, index); + }); + + connect(messageList, &MessageList::postMessageAppended, this, [this] + { + endInsertRows(); + }); + } + + endResetModel(); +} diff --git a/modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp b/modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp new file mode 100644 index 00000000..4baa931f --- /dev/null +++ b/modules/catkin_ws/src/PCGui/PCGui/src/SortFilterProxyModel.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../include/SortFilterProxyModel.h" +#include <QtDebug> +#include <QtQml> + +SortFilterProxyModel::SortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_complete(false) +{ + connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged())); + connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged())); +} + +int SortFilterProxyModel::count() const +{ + return rowCount(); +} + +QObject *SortFilterProxyModel::source() const +{ + return sourceModel(); +} + +void SortFilterProxyModel::setSource(QObject *source) +{ + setSourceModel(qobject_cast<QAbstractItemModel *>(source)); +} + +QByteArray SortFilterProxyModel::sortRole() const +{ + return m_sortRole; +} + +void SortFilterProxyModel::setSortRole(const QByteArray &role) +{ + if (m_sortRole != role) { + m_sortRole = role; + if (m_complete) + QSortFilterProxyModel::setSortRole(roleKey(role)); + } +} + +void SortFilterProxyModel::setSortOrder(Qt::SortOrder order) +{ + QSortFilterProxyModel::sort(0, order); +} + +QByteArray SortFilterProxyModel::filterRole() const +{ + return m_filterRole; +} + +void SortFilterProxyModel::setFilterRole(const QByteArray &role) +{ + if (m_filterRole != role) { + m_filterRole = role; + if (m_complete) + QSortFilterProxyModel::setFilterRole(roleKey(role)); + } +} + +QString SortFilterProxyModel::filterString() const +{ + return filterRegExp().pattern(); +} + +void SortFilterProxyModel::setFilterString(const QString &filter) +{ + setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax()))); +} + +SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const +{ + return static_cast<FilterSyntax>(filterRegExp().patternSyntax()); +} + +void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax syntax) +{ + setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(syntax))); +} + +QJSValue SortFilterProxyModel::get(int idx) const +{ + QJSEngine *engine = qmlEngine(this); + QJSValue value = engine->newObject(); + if (idx >= 0 && idx < count()) { + QHash<int, QByteArray> roles = roleNames(); + QHashIterator<int, QByteArray> it(roles); + while (it.hasNext()) { + it.next(); + value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString()); + } + } + return value; +} + +void SortFilterProxyModel::classBegin() +{ +} + +void SortFilterProxyModel::componentComplete() +{ + m_complete = true; + if (!m_sortRole.isEmpty()) + QSortFilterProxyModel::setSortRole(roleKey(m_sortRole)); + if (!m_filterRole.isEmpty()) + QSortFilterProxyModel::setFilterRole(roleKey(m_filterRole)); +} + +int SortFilterProxyModel::roleKey(const QByteArray &role) const +{ + QHash<int, QByteArray> roles = roleNames(); + QHashIterator<int, QByteArray> it(roles); + while (it.hasNext()) { + it.next(); + if (it.value() == role) + return it.key(); + } + return -1; +} + +QHash<int, QByteArray> SortFilterProxyModel::roleNames() const +{ + if (QAbstractItemModel *source = sourceModel()) + return source->roleNames(); + return QHash<int, QByteArray>(); +} + +bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QRegExp rx = filterRegExp(); + if (rx.isEmpty()) + return true; + QAbstractItemModel *model = sourceModel(); + if (filterRole().isEmpty()) { + QHash<int, QByteArray> roles = roleNames(); + QHashIterator<int, QByteArray> it(roles); + while (it.hasNext()) { + it.next(); + QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent); + QString key = model->data(sourceIndex, it.key()).toString(); + if (key.contains(rx)) + return true; + } + return false; + } + QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent); + if (!sourceIndex.isValid()) + return true; + QString key = model->data(sourceIndex, roleKey(filterRole())).toString(); + return key.contains(rx); +} diff --git a/modules/catkin_ws/src/car/launch/noUss.launch b/modules/catkin_ws/src/car/launch/noHardware.launch similarity index 88% rename from modules/catkin_ws/src/car/launch/noUss.launch rename to modules/catkin_ws/src/car/launch/noHardware.launch index 96aa1a2c..2c09576a 100644 --- a/modules/catkin_ws/src/car/launch/noUss.launch +++ b/modules/catkin_ws/src/car/launch/noHardware.launch @@ -8,7 +8,6 @@ dsdf <node pkg="nodelet" type="nodelet" name="Master" args="manager" output="sc <node pkg="nodelet" type="nodelet" name="nodelet_environment" args="load car/environment Master"/> <node pkg="nodelet" type="nodelet" name="nodelet_camera" args="load car/camera Master"/> <node pkg="nodelet" type="nodelet" name="nodelet_lanekeeping" args="load car/lanekeeping Master"/> - <node pkg="nodelet" type="nodelet" name="nodelet_mav_link" args="load car/mav_link Master"/> </launch> <!-- diff --git a/modules/catkin_ws/src/car/src/mavLink/MavLink.cpp b/modules/catkin_ws/src/car/src/mavLink/MavLink.cpp index 06f846b0..f5ed75cd 100644 --- a/modules/catkin_ws/src/car/src/mavLink/MavLink.cpp +++ b/modules/catkin_ws/src/car/src/mavLink/MavLink.cpp @@ -58,14 +58,12 @@ void MavLink::onStmDataReceived() float MavLink::convertSpeedToStm(float speed) const { - // TODO: convert speed! - return speed; + return speed / 100; } float MavLink::convertSpeedFromStm(float speed) const { - // TODO: convert speed! - return speed; + return speed * 100; } -- GitLab