From 4f8c1e4a146cd7260c3b1911f45a558478ea06ed Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 2 May 2015 22:24:03 +0200 Subject: [PATCH] Added methods to Hongkang parser that publish the results More changes to the TImeline GUI --- gui/timelineview/common.h | 35 +++++ gui/timelineview/mainwindow.cpp | 115 ++++++++++++++- gui/timelineview/mainwindow.h | 3 + gui/timelineview/timelinewidget.cpp | 155 ++++++++++++++++++++- gui/timelineview/timelinewidget.h | 24 ++++ include/openspace/engine/openspaceengine.h | 1 + include/openspace/network/networkengine.h | 37 ++++- include/openspace/util/hongkangparser.h | 1 + src/engine/openspaceengine.cpp | 7 +- src/main.cpp | 1 - src/network/networkengine.cpp | 128 +++++++++++++++-- src/util/hongkangparser.cpp | 121 ++++++++++++++++ 12 files changed, 602 insertions(+), 26 deletions(-) create mode 100644 gui/timelineview/common.h diff --git a/gui/timelineview/common.h b/gui/timelineview/common.h new file mode 100644 index 0000000000..2588afda3a --- /dev/null +++ b/gui/timelineview/common.h @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2015 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +struct Image { + double beginning; + double ending; + std::string target; + std::vector instruments; +}; + +#endif // __COMMON_H__ diff --git a/gui/timelineview/mainwindow.cpp b/gui/timelineview/mainwindow.cpp index a6b2bb9b24..845a719e89 100644 --- a/gui/timelineview/mainwindow.cpp +++ b/gui/timelineview/mainwindow.cpp @@ -36,6 +36,28 @@ #include #include +template +T readFromBuffer(char* buffer, size_t& currentReadLocation) { + union { + T value; + std::array data; + } b; + std::memmove(b.data.data(), buffer + currentReadLocation, sizeof(T)); + currentReadLocation += sizeof(T); + return b.value; +} + +template <> +std::string readFromBuffer(char* buffer, size_t& currentReadLocation) { + uint8_t size = readFromBuffer(buffer, currentReadLocation); + + std::string result(buffer + currentReadLocation, buffer + currentReadLocation + size); + currentReadLocation += size; + return result; +} + + + MainWindow::MainWindow() : QWidget(nullptr) , _configurationWidget(nullptr) @@ -82,24 +104,52 @@ void MainWindow::onConnect(QString host, QString port) { _socket = new QTcpSocket(this); connect(_socket, SIGNAL(readyRead()), SLOT(readTcpData())); _socket->connectToHost(host, port.toUInt()); + + _socket->write(QString("1\r\n").toLatin1()); } void MainWindow::readTcpData() { - static const uint8_t MessageTypeStatus = 0; + static const uint16_t MessageTypeStatus = 0; + static const uint16_t MessageTypePlayBook = 2; QByteArray data = _socket->readAll(); + //QString debug(data); + //qDebug() << debug; + if (QString(data) == "Connected to SGCT!\r\n") return; if (QString(data) == "OK\r\n") return; - uint8_t messageType = data[0]; + QByteArray messageTypeData = data.left(2); + union { + uint16_t value; + std::array data; + } messageType; + std::memcpy(messageType.data.data(), messageTypeData.data(), sizeof(uint16_t)); - if (messageType == MessageTypeStatus) - handleStatusMessage(data.mid(1)); - handleStatusMessage(data.right(data.length() - 1)); + switch (messageType.value) { + case MessageTypeStatus: + handleStatusMessage(data.mid(2)); + break; + case MessageTypePlayBook: + { + const char* payloadDebug = data.mid(2).data(); + + size_t beginning = 0; + uint32_t size = readFromBuffer(data.mid(2).data(), beginning); + + while (_socket->waitForReadyRead() && data.size() < size) { + data = data.append(_socket->readAll()); + } + handlePlaybook(data.mid(2)); + break; + } + default: + qDebug() << "Unknown message of type '" << messageType.value << "'"; + } } void MainWindow::handleStatusMessage(QByteArray data) { @@ -124,8 +174,63 @@ void MainWindow::handleStatusMessage(QByteArray data) { QString::fromStdString(std::string(timeString.begin(), timeString.end())), QString::number(delta.value) ); + _timelineWidget->setCurrentTime(std::string(timeString.begin(), timeString.end())); } +std::vector instrumentsFromId(uint16_t instrumentId, std::map instrumentMap) { + std::vector results; + for (int i = 0; i < 16; ++i) { + uint16_t testValue = 1 << i; + if ((testValue & instrumentId) == 1) + results.push_back(instrumentMap[testValue]); + } + return results; +} + +void MainWindow::handlePlaybook(QByteArray data) { + char* buffer = data.data(); + size_t currentReadLocation = 0; + + uint32_t totalData = readFromBuffer(buffer, currentReadLocation); + + uint8_t nTargets = readFromBuffer(buffer, currentReadLocation); + std::map targetMap; + for (uint8_t i = 0; i < nTargets; ++i) { + uint8_t id = readFromBuffer(buffer, currentReadLocation); + std::string value = readFromBuffer(buffer, currentReadLocation); + targetMap[id] = value; + } + + uint8_t nInstruments = readFromBuffer(buffer, currentReadLocation); + std::map instrumentMap; + for (uint8_t i = 0; i < nInstruments; ++i) { + uint8_t id = readFromBuffer(buffer, currentReadLocation); + std::string value = readFromBuffer(buffer, currentReadLocation); + instrumentMap[id] = value; + } + + uint32_t nImages = readFromBuffer(buffer, currentReadLocation); + std::vector images; + for (uint32_t i = 0; i < nImages; ++i) { + Image image; + image.beginning = readFromBuffer(buffer, currentReadLocation); + image.ending = readFromBuffer(buffer, currentReadLocation); + + image.beginningString = readFromBuffer(buffer, currentReadLocation); + image.endingString = readFromBuffer(buffer, currentReadLocation); + + uint8_t targetId = readFromBuffer(buffer, currentReadLocation); + uint16_t instrumentId = readFromBuffer(buffer, currentReadLocation); + image.target = targetMap[targetId]; + image.instruments = instrumentsFromId(instrumentId, instrumentMap); + images.push_back(image); + } + + _timelineWidget->setData(std::move(images), std::move(targetMap), std::move(instrumentMap)); +} + + void MainWindow::sendScript(QString script) { _socket->write(("0" + script + "\r\n").toLatin1()); } + diff --git a/gui/timelineview/mainwindow.h b/gui/timelineview/mainwindow.h index 9fdd10b1d3..cb9ada8a8b 100644 --- a/gui/timelineview/mainwindow.h +++ b/gui/timelineview/mainwindow.h @@ -28,6 +28,8 @@ #include #include +#include "common.h" + class ConfigurationWidget; class TimeControlWidget; class InformationWidget; @@ -49,6 +51,7 @@ private slots: //void sendCommandButton(); void readTcpData(); void handleStatusMessage(QByteArray data); + void handlePlaybook(QByteArray data); private: ConfigurationWidget* _configurationWidget; diff --git a/gui/timelineview/timelinewidget.cpp b/gui/timelineview/timelinewidget.cpp index 7028482f30..5f064a0619 100644 --- a/gui/timelineview/timelinewidget.cpp +++ b/gui/timelineview/timelinewidget.cpp @@ -24,19 +24,166 @@ #include "timelinewidget.h" +#include #include #include +#include + +namespace { + static const int LegendHeight = 105; + static const int TimeWidth = 150; + + const QColor targetColors[] = { + QColor(251, 180, 174), + QColor(179, 205, 227), + QColor(204, 235, 197), + QColor(222, 203, 228), + QColor(254, 217, 166), + QColor(255, 255, 204) + }; + + const QColor instrumentColors[] = { + QColor(228, 26, 28), + QColor(55, 126, 184), + QColor(77, 175, 74), + QColor(152, 78, 163), + QColor(255, 127, 0), + QColor(255, 255, 51), + QColor(166, 86, 40), + QColor(247, 129, 191), + QColor(153, 153, 153), + }; + + const double etSpread = 100.0; +} + TimelineWidget::TimelineWidget(QWidget* parent) : QWidget(parent) { - setMinimumWidth(300); - setMinimumHeight(500); + setMinimumWidth(600); + setMinimumHeight(600); } void TimelineWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); - painter.setBrush(QBrush(Qt::white)); - painter.drawRect(contentsRect()); + QRectF fullRect = contentsRect(); + QRectF contentRect(0, 0, fullRect.width() - 1, fullRect.height() - LegendHeight); + QRectF legendRect(0, fullRect.bottom() - LegendHeight, fullRect.right(), fullRect.bottom()); + + painter.save(); + drawContent(painter, contentRect); + painter.restore(); + + painter.save(); + painter.translate(0, fullRect.height() - LegendHeight); + drawLegend(painter, QRectF(legendRect)); + painter.restore(); } + +void TimelineWidget::setData(std::vector images, std::map targetMap, std::map instrumentMap) { + _images = std::move(images); + + std::sort(_images.begin(), _images.end(), [](const Image& a, const Image& b) { return a.beginning < b.beginning; }); + + _targetMap = std::move(targetMap); + _instrumentMap = std::move(instrumentMap); + + _instruments.clear(); + std::set instruments; + for (auto p : _instrumentMap) + instruments.insert(p.second); + std::copy(instruments.begin(), instruments.end(), std::back_inserter(_instruments)); + + _targets.clear(); + std::set targets; + for (auto p : _targetMap) + targets.insert(p.second); + std::copy(targets.begin(), targets.end(), std::back_inserter(_targets)); + + repaint(); +} + +void TimelineWidget::drawContent(QPainter& painter, QRectF rect) { + QRectF timelineRect(0, 0, rect.width() - TimeWidth, rect.height()); + QRectF dateRect(rect.width() - TimeWidth, 0, TimeWidth, rect.height()); + + // Draw background + painter.setBrush(QBrush(Qt::white)); painter.drawRect(timelineRect); + painter.setBrush(QBrush(Qt::gray)); painter.drawRect(dateRect); + + // Draw current time + painter.setBrush(QBrush(Qt::black)); + painter.drawLine(QPointF(0, timelineRect.height() / 2), QPointF(timelineRect.width(), timelineRect.height() / 2)); + painter.drawText(timelineRect.width(), timelineRect.height() / 2, QString::fromStdString(_currentTime.time)); + + + const double lowerTime = _currentTime.et - etSpread; + const double upperTime = _currentTime.et + etSpread; + + std::vector::const_iterator start = _images.end(); + std::vector::const_iterator end = _images.end(); + for (std::vector::const_iterator it = _images.begin(); it != _image.end(); ++it) { + if (it->beginning > lowerTime + } + + //std::vector::const_iterator lower = std::lower_bound(_images.begin(), _images.end(), lowerTime, [lowerTime](const Image& i) { return i.beginning < lowerTime; }); + ////std::vector::const_iterator upper = std::lower_bound(_images.begin(), _iamges.end(), upperTime) + + + +} + +void TimelineWidget::drawLegend(QPainter& painter, QRectF rect) { + static const int HalfHeight = LegendHeight / 2; + static const int Padding = 5; + static const int BoxSize = 20; + + // Draw Targets + int currentHorizontalPosition = Padding; + int currentVerticalPosition = Padding; + for (int i = 0; i < _targets.size(); ++i) { + + const std::string& target = _targets[i]; + + painter.setBrush(QBrush(targetColors[i])); + painter.drawRect(currentHorizontalPosition, currentVerticalPosition, BoxSize, BoxSize); + currentHorizontalPosition += BoxSize + Padding; + + painter.drawText(currentHorizontalPosition, currentVerticalPosition + BoxSize / 2, QString::fromStdString(target)); + int textWidth = painter.boundingRect(QRect(), QString::fromStdString(target)).width(); + currentHorizontalPosition += std::max(textWidth, 25) + Padding; + } + + // Draw Instruments + currentHorizontalPosition = Padding; + currentVerticalPosition = Padding + BoxSize + Padding; + for (int i = 0; i < _instruments.size(); ++i) { + if (i == _instruments.size() / 3 || i == _instruments.size() * 2 / 3) { + currentVerticalPosition += BoxSize + Padding; + currentHorizontalPosition = Padding; + } + + const std::string& instrument = _instruments[i]; + + //painter.setBrush(QBrush(instrumentColors[i])); + painter.setBrush(Qt::NoBrush); + painter.setPen(QPen(instrumentColors[i])); + painter.drawRect(currentHorizontalPosition, currentVerticalPosition, BoxSize, BoxSize); + currentHorizontalPosition += BoxSize + Padding; + + painter.setPen(QPen(Qt::black)); + painter.drawText(currentHorizontalPosition, currentVerticalPosition + BoxSize / 2, QString::fromStdString(instrument)); + int textWidth = painter.boundingRect(QRect(), QString::fromStdString(instrument)).width(); + currentHorizontalPosition += std::max(textWidth, 25) + Padding; + } +} + +void TimelineWidget::setCurrentTime(std::string currentTime, double et) { + _currentTime.time = std::move(currentTime); + _currentTime.et = std::move(et); + repaint(); + +} + diff --git a/gui/timelineview/timelinewidget.h b/gui/timelineview/timelinewidget.h index def40ffe6c..33c455b3eb 100644 --- a/gui/timelineview/timelinewidget.h +++ b/gui/timelineview/timelinewidget.h @@ -27,6 +27,12 @@ #include +#include "common.h" + +#include +#include +#include + class QPaintEvent; class TimelineWidget : public QWidget { @@ -34,9 +40,27 @@ Q_OBJECT public: TimelineWidget(QWidget* parent); + void setData(std::vector images, std::map targetMap, std::map instrumentMap); + void setCurrentTime(std::string currentTime, double et); + protected: void paintEvent(QPaintEvent* event); + void drawContent(QPainter& painter, QRectF rect); + void drawLegend(QPainter& painter, QRectF rect); + +private: + std::vector _images; + std::map _targetMap; + std::map _instrumentMap; + + std::vector _targets; + std::vector _instruments; + + struct { + std::string time; + double et; + } _currentTime; }; #endif // __TIMELINEWIDGET_H__ diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 2beeafa486..155a9f9e33 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -69,6 +69,7 @@ public: interaction::InteractionHandler* interactionHandler(); RenderEngine* renderEngine(); scripting::ScriptEngine* scriptEngine(); + NetworkEngine* networkEngine(); LuaConsole* console(); gui::GUI* gui(); diff --git a/include/openspace/network/networkengine.h b/include/openspace/network/networkengine.h index 1d0c03481a..90558f9717 100644 --- a/include/openspace/network/networkengine.h +++ b/include/openspace/network/networkengine.h @@ -25,17 +25,50 @@ #ifndef __NETWORKENGINE_H__ #define __NETWORKENGINE_H__ +#include +#include #include +#include namespace openspace { class NetworkEngine { public: - NetworkEngine() = default; + typedef uint16_t MessageIdentifier; + NetworkEngine(); + + // Receiving messages bool handleMessage(const std::string& message); - void sendStatusMessage(); + // Sending messages + void publishStatusMessage(); + void publishIdentifierMappingMessage(); + void publishMessage(MessageIdentifier identifier, std::vector message); + void sendMessages(); + + // Initial Connection Messages + void setInitialConnectionMessage(MessageIdentifier identifier, std::vector message); + void sendInitialInformation(); + + // Background + MessageIdentifier identifier(std::string name); +private: + std::map _identifiers; + MessageIdentifier _lastAssignedIdentifier; + + struct Message { + MessageIdentifier identifer; + std::vector body; + }; + std::vector _messagesToSend; + + std::vector _initialConnectionMessages; + + + + MessageIdentifier _statusMessageIdentifier; + MessageIdentifier _identifierMappingIdentifier; }; } // namespace openspace diff --git a/include/openspace/util/hongkangparser.h b/include/openspace/util/hongkangparser.h index f6e08c6160..ca1eccf68d 100644 --- a/include/openspace/util/hongkangparser.h +++ b/include/openspace/util/hongkangparser.h @@ -65,6 +65,7 @@ namespace openspace { std::string spacecraft, std::vector payload, std::vector potentialTargets); + void sendPlaybookInformation(); std::string _defaultCaptureImage; double _metRef = 299180517; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 4e169dc328..7499cab4ec 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -703,7 +703,8 @@ void OpenSpaceEngine::encode() { _syncBuffer->write(); } - _networkEngine->sendStatusMessage(); + _networkEngine->publishStatusMessage(); + _networkEngine->sendMessages(); } void OpenSpaceEngine::decode() { @@ -733,4 +734,8 @@ void OpenSpaceEngine::disableBarrier() { sgct::SGCTWindow::setBarrier(false); } +NetworkEngine* OpenSpaceEngine::networkEngine() { + return _networkEngine; +} + } // namespace openspace diff --git a/src/main.cpp b/src/main.cpp index 86a3dfdf2a..d7a851db0f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,7 +79,6 @@ int main(int argc, char** argv) { sgct::MessageHandler::instance()->setLogToCallback(true); sgct::MessageHandler::instance()->setLogCallback(mainLogCallback); - LDEBUG("Creating SGCT Engine"); _sgctEngine = new sgct::Engine(newArgc, newArgv); diff --git a/src/network/networkengine.cpp b/src/network/networkengine.cpp index 1b0c0a2599..c89ce924b3 100644 --- a/src/network/networkengine.cpp +++ b/src/network/networkengine.cpp @@ -27,27 +27,49 @@ #include #include +#include + #include "sgct.h" namespace { const std::string _loggerCat = "NetworkEngine"; - const uint8_t MessageTypeStatus = 0; + const std::string StatusMessageIdentifierName = "StatusMessage"; + const std::string MappingIdentifierIdentifierName = "IdentifierMapping"; + + const char MessageTypeLuaScript = '0'; + const char MessageTypeExternalControlConnected = '1'; } namespace openspace { +NetworkEngine::NetworkEngine() + : _lastAssignedIdentifier(-1) // -1 is okay as we assign one identifier in this ctor +{ + static_assert( + sizeof(MessageIdentifier) == 2, + "MessageIdentifier has to be 2 bytes or dependent applications will break" + ); + _statusMessageIdentifier = identifier(StatusMessageIdentifierName); + _identifierMappingIdentifier = identifier(MappingIdentifierIdentifierName); +} + bool NetworkEngine::handleMessage(const std::string& message) { // The first byte determines the type of message const char type = message[0]; switch (type) { - case '0': // LuaScript + case MessageTypeLuaScript: // LuaScript { std::string script = message.substr(1); //LINFO("Received Lua Script: '" << script << "'"); OsEng.scriptEngine()->queueScript(script); return true; } + case MessageTypeExternalControlConnected: + { + sendInitialInformation(); + return true; + } default: LERROR("Unknown type '" << type << "'"); return false; @@ -55,15 +77,14 @@ bool NetworkEngine::handleMessage(const std::string& message) { } -void NetworkEngine::sendStatusMessage() { +void NetworkEngine::publishStatusMessage() { if (!sgct::Engine::instance()->isExternalControlConnected()) return; - // Protocols: - // 1 byte: type of message + // Protocol: // 8 bytes: time as a ET double // 24 bytes: time as a UTC string // 8 bytes: delta time as double - // Total: 41 + // Total: 40 uint16_t messageSize = 0; @@ -71,27 +92,108 @@ void NetworkEngine::sendStatusMessage() { std::string timeString = Time::ref().currentTimeUTC(); double delta = Time::ref().deltaTime(); - messageSize += sizeof(uint8_t); messageSize += sizeof(time); messageSize += timeString.length(); messageSize += sizeof(delta); - //LINFO(delta); - - ghoul_assert(messageSize == 41, "Message size is not correct"); + ghoul_assert(messageSize == 40, "Message size is not correct"); unsigned int currentLocation = 0; std::vector buffer(messageSize); - std::memcpy(buffer.data(), &MessageTypeStatus, sizeof(MessageTypeStatus)); - currentLocation += sizeof(MessageTypeStatus); std::memmove(buffer.data() + currentLocation, &time, sizeof(time)); currentLocation += sizeof(time); std::memmove(buffer.data() + currentLocation, timeString.c_str(), timeString.length()); currentLocation += timeString.length(); std::memmove(buffer.data() + currentLocation, &delta, sizeof(delta)); - sgct::Engine::instance()->sendMessageToExternalControl(buffer.data(), messageSize); + publishMessage(_statusMessageIdentifier, std::move(buffer)); +} + +void NetworkEngine::publishIdentifierMappingMessage() { + size_t bufferSize = 0; + for (const std::pair& i : _identifiers) { + bufferSize += sizeof(MessageIdentifier); + bufferSize += i.second.size() + 1; // +1 for \0 terminating character + } + + std::vector buffer(bufferSize); + size_t currentWritingPosition = 0; + for (const std::pair& i : _identifiers) { + std::memcpy(buffer.data() + currentWritingPosition, &(i.first), sizeof(MessageIdentifier)); + currentWritingPosition += sizeof(MessageIdentifier); + std::memcpy(buffer.data() + currentWritingPosition, i.second.data(), i.second.size()); + currentWritingPosition += i.second.size(); + buffer[currentWritingPosition] = '\0'; + currentWritingPosition += 1; + } + + publishMessage(_identifierMappingIdentifier, std::move(buffer)); +} + + +NetworkEngine::MessageIdentifier NetworkEngine::identifier(std::string name) { +#ifdef DEBUG + // Check if name has been assigned already + for (const std::pair& p : _identifiers) { + if (p.second == name) { + LERROR("Name '" << name << "' for identifier has been registered before"); + return -1; + } + } +#endif + _lastAssignedIdentifier++; + + MessageIdentifier result = _lastAssignedIdentifier; + + _identifiers[result] = std::move(name); + return result; +} + +void NetworkEngine::publishMessage(MessageIdentifier identifier, std::vector message) { + _messagesToSend.push_back({ std::move(identifier), std::move(message) }); +} + +void NetworkEngine::sendMessages() { + if (!sgct::Engine::instance()->isExternalControlConnected()) + return; + + for (Message& m : _messagesToSend) { + // Protocol: + // 2 bytes: type of message as uint16_t + // Rest of payload depending on the message type + + union { + MessageIdentifier value; + std::array data; + } identifier; + identifier.value = m.identifer; + + // Prepending the message identifier to the front + m.body.insert(m.body.begin(), identifier.data.begin(), identifier.data.end()); + sgct::Engine::instance()->sendMessageToExternalControl(m.body.data(), m.body.size()); + } + + _messagesToSend.clear(); +} + +void NetworkEngine::sendInitialInformation() { + for (const Message& m : _initialConnectionMessages) { + union { + MessageIdentifier value; + std::array data; + } identifier; + identifier.value = m.identifer; + + std::vector payload = m.body; + payload.insert(payload.begin(), identifier.data.begin(), identifier.data.end()); + sgct::Engine::instance()->sendMessageToExternalControl(payload.data(), payload.size()); + } +} + +void NetworkEngine::setInitialConnectionMessage(MessageIdentifier identifier, std::vector message) { + // Add check if a MessageIdentifier already exists ---abock + _initialConnectionMessages.push_back({std::move(identifier), std::move(message)}); } } // namespace openspace diff --git a/src/util/hongkangparser.cpp b/src/util/hongkangparser.cpp index 0628de37c3..55802a7249 100644 --- a/src/util/hongkangparser.cpp +++ b/src/util/hongkangparser.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,6 +40,8 @@ namespace { const std::string _loggerCat = "HongKangParser"; const std::string keyTranslation = "DataInputTranslation"; + + const std::string PlaybookIdentifierName = "Playbook"; } namespace openspace { @@ -207,6 +211,8 @@ void HongKangParser::create(){ } } } + + sendPlaybookInformation(); std::ofstream myfile; myfile.open("HongKangOutput.txt"); @@ -333,4 +339,119 @@ std::vector HongKangParser::getCaptureProgression(){ return _captureProgression; }; + +template +void writeToBuffer(std::vector& buffer, size_t& currentWriteLocation, T value) { + if ((currentWriteLocation + sizeof(T)) > buffer.size()) + buffer.resize(2 * buffer.size()); + + std::memmove(buffer.data() + currentWriteLocation, reinterpret_cast(&value), sizeof(T)); + currentWriteLocation += sizeof(T); +} + +template <> + +void writeToBuffer(std::vector& buffer, size_t& currentWriteLocation, std::string value) { + if ((currentWriteLocation + sizeof(uint8_t) + value.size()) > buffer.size()) + buffer.resize(2 * buffer.size()); + + uint8_t length = value.size(); + std::memcpy(buffer.data() + currentWriteLocation, &length, sizeof(uint8_t)); + currentWriteLocation += sizeof(uint8_t); + + std::memmove(buffer.data() + currentWriteLocation, value.data(), length); + currentWriteLocation += length; +} + + +void HongKangParser::sendPlaybookInformation() { + static const NetworkEngine::MessageIdentifier PlaybookIdentifier = OsEng.networkEngine()->identifier(PlaybookIdentifierName); + + std::vector buffer(1024); + size_t currentWriteLocation = 0; + + // Protocol: + // 4 bytes: Total number of bytes sent + // 1 byte : Number of Targets (i) + // i times: 1 byte (id), 1 byte (length j of name), j bytes (name) + // 1 byte : Number of Instruments (i) + // i times: 1 byte (id), 1 byte (length j of name), j bytes (name) + // 4 byte: Number (n) of images + // n times: 8 byte (beginning time), 8 byte (ending time), 1 byte (target id), 2 byte (instrument id) + + std::map targetMap; + uint8_t currentTargetId = 0; + for (auto target : _subsetMap) { + if (targetMap.find(target.first) == targetMap.end()) + targetMap[target.first] = currentTargetId++; + } + + std::map instrumentMap; + uint16_t currentInstrumentId = 1; + for (auto target : _subsetMap) { + for (auto image : target.second._subset) { + for (auto instrument : image.activeInstruments) { + if (instrumentMap.find(instrument) == instrumentMap.end()) { + instrumentMap[instrument] = currentInstrumentId; + currentInstrumentId = currentInstrumentId << 1; + } + } + } + } + + writeToBuffer(buffer, currentWriteLocation, uint8_t(targetMap.size())); + for (const std::pair& p : targetMap) { + writeToBuffer(buffer, currentWriteLocation, p.second); + writeToBuffer(buffer, currentWriteLocation, p.first); + } + + writeToBuffer(buffer, currentWriteLocation, uint8_t(instrumentMap.size())); + for (const std::pair& p : instrumentMap) { + writeToBuffer(buffer, currentWriteLocation, p.second); + writeToBuffer(buffer, currentWriteLocation, p.first); + } + + uint32_t allImages = 0; + for (auto target : _subsetMap) + allImages += target.second._subset.size(); + writeToBuffer(buffer, currentWriteLocation, allImages); + + for (auto target : _subsetMap){ + for (auto image : target.second._subset){ + writeToBuffer(buffer, currentWriteLocation, image.startTime); + writeToBuffer(buffer, currentWriteLocation, image.stopTime); + + std::string timeBegin; + std::string timeEnd; + SpiceManager::ref().getDateFromET(image.startTime, timeBegin); + SpiceManager::ref().getDateFromET(image.stopTime, timeEnd); + + writeToBuffer(buffer, currentWriteLocation, timeBegin); + writeToBuffer(buffer, currentWriteLocation, timeEnd); + + uint8_t targetId = targetMap[target.first]; + writeToBuffer(buffer, currentWriteLocation, targetId); + uint16_t totalInstrumentId = 0; + for (auto instrument : image.activeInstruments) { + uint16_t thisInstrumentId = instrumentMap[instrument]; + totalInstrumentId |= thisInstrumentId; + } + writeToBuffer(buffer, currentWriteLocation, totalInstrumentId); + } + } + + union { + uint32_t value; + std::array data; + } sizeBuffer; + sizeBuffer.value = currentWriteLocation; + buffer.insert(buffer.begin(), sizeBuffer.data.begin(), sizeBuffer.data.end()); + currentWriteLocation += sizeof(uint32_t); + + buffer.resize(currentWriteLocation); + + //OsEng.networkEngine()->publishMessage(PlaybookIdentifier, buffer); + OsEng.networkEngine()->setInitialConnectionMessage(PlaybookIdentifier, buffer); +} + } \ No newline at end of file