diff --git a/src/LogTask.cpp b/src/LogTask.cpp index 7a82fe4..bcd1499 100644 --- a/src/LogTask.cpp +++ b/src/LogTask.cpp @@ -64,6 +64,8 @@ bool LogTask::addStream(pocolog_cpp::InputDataStream& stream) task->ports()->addPort(portHandle->port->getName(), *portHandle->port); streamIdx2Port.emplace(stream.getIndex(), std::move(portHandle)); return true; + } else { + unreplayablePorts.emplace(portName, stream.getCXXType()); } } @@ -203,7 +205,11 @@ LogTask::PortCollection LogTask::getPortCollection() for(const auto& portHandlePair : streamIdx2Port) { const auto& portHandle = portHandlePair.second; - collection.emplace_back(portHandle->name, portHandle->inputDataStream.getCXXType()); + collection.replayable.emplace_back(PortInfo{portHandle->name, portHandle->inputDataStream.getCXXType()}); + } + for(const auto& p : unreplayablePorts) + { + collection.unreplayable.emplace_back(PortInfo{p.first, p.second}); } return collection; @@ -217,4 +223,4 @@ std::string LogTask::getName() bool LogTask::isValid() { return task.get(); -} \ No newline at end of file +} diff --git a/src/LogTask.hpp b/src/LogTask.hpp index da9b689..68cda2c 100644 --- a/src/LogTask.hpp +++ b/src/LogTask.hpp @@ -96,13 +96,19 @@ class LogTask * @brief Alias for pair of port name and port type. * */ - using PortInfo = std::pair; + struct PortInfo { + std::string name; + std::string type; + }; /** - * @brief Alias for list of PortInfo. + * @brief Structure holding two lists: replayable ports and unreplayable ports * */ - using PortCollection = std::vector; + struct PortCollection { + std::vector replayable; + std::vector unreplayable; + }; /** * @brief Constructor. @@ -236,4 +242,11 @@ class LogTask * */ std::map> streamIdx2Port; + + /** + * @brief Map of stream names to types + * + * Used for showing which ports are present but cannot be replayed + */ + std::map unreplayablePorts; }; diff --git a/src/LogTaskManager.cpp b/src/LogTaskManager.cpp index 80e097b..0436782 100644 --- a/src/LogTaskManager.cpp +++ b/src/LogTaskManager.cpp @@ -4,11 +4,13 @@ #include #include +#include LogTaskManager::LogTaskManager() { orocos_cpp::OrocosCppConfig config; orocos.initialize(config); + haveLoadedAllTypeKits = false; } void LogTaskManager::init( @@ -126,21 +128,52 @@ bool LogTaskManager::loadTypekitsAndAddStreamToLogTask(pocolog_cpp::InputDataStr { modelName = inputStream.getTaskModel(); } + catch(std::exception &e) + { + LOG_WARN_S << "stream " << inputStream.getName() + << " does not contain necessary metadata for its task model. Trying to load typekit via stream name" + << "("<< typeid(e).name() << ": " << e.what() << ")"; + } catch(...) { LOG_WARN_S << "stream " << inputStream.getName() << " does not contain necessary metadata for its task model. Trying to load typekit via stream name"; } + bool typekit_loaded = false; try { orocos.loadAllTypekitsForModel(modelName); + typekit_loaded = true; + } + catch(std::exception &e) + { + LOG_WARN_S << "cannot load typekits using modelName " << modelName << " for stream " << inputStream.getName() << "("<< typeid(e).name() << ": " << e.what() << ")"; + } + catch(...) + { + LOG_WARN_S << "cannot load typekits using modelName " << modelName << " for stream " << inputStream.getName(); + } + if(!typekit_loaded && !haveLoadedAllTypeKits) { + haveLoadedAllTypeKits = true; + LOG_WARN_S << "Trying to load all typekits for stream " << inputStream.getName(); + orocos_cpp::PluginHelper::loadAllTypekitAndTransports(); + } + //even though the registry is available in inputStream.getStreamRegistry, + //we cannot do anything without the typekits, so best we can do is + //configure orocos_cpp with load_all_packages and hope the datatype + //can be found. + try { LogTask& logTask = findOrCreateLogTask(inputStream.getName()); return logTask.addStream(inputStream); } + catch(std::exception &e) + { + LOG_WARN_S << "cannot add stream to task for stream " << inputStream.getName() << "("<< typeid(e).name() << ": " << e.what() << ")"; + } catch(...) { - LOG_WARN_S << "cannot load typekits for stream " << inputStream.getName(); + LOG_WARN_S << "cannot add stream to task for stream " << inputStream.getName(); } return false; diff --git a/src/LogTaskManager.hpp b/src/LogTaskManager.hpp index d3a1d5a..7a0add6 100644 --- a/src/LogTaskManager.hpp +++ b/src/LogTaskManager.hpp @@ -40,16 +40,6 @@ class LogTaskManager bool valid; }; - /** - * @brief Pair of port name and corresponding c++ data type. - */ - using PortInfo = std::pair; - - /** - * @brief List of PortInfos. - */ - using PortCollection = std::vector; - /** * @brief Map of task name to corresponding list of PortInfos. */ @@ -175,4 +165,9 @@ class LogTaskManager * */ std::map renamings; + + /** + * @brief Set to remember if we have already tried loading all typekits + */ + bool haveLoadedAllTypeKits; }; diff --git a/src/Main.cpp b/src/Main.cpp index 310499a..0e71dd1 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -3,16 +3,20 @@ #include -ReplayHandler replayHandler; - void startHeadless(const ArgParser& argParser) { - static bool no_exit = argParser.no_exit; - std::signal(SIGINT, [](int sig) { replayHandler.stop(); no_exit = false; }); + //There can only be one replayHandler(due to orocos_cpp), and since + //startGui does use a one on its stack, it would be unusable if this + //one were static. + ReplayHandler replayHandler; + + static volatile bool do_quit = false; + //This must be a function, so it cannot capture anything. + std::signal(SIGINT, [](int sig) { do_quit = true; }); replayHandler.init(argParser.fileNames, argParser.prefix, argParser.whiteListTokens, argParser.renamings); replayHandler.play(); - while(replayHandler.isPlaying()) + while(replayHandler.isPlaying() && !do_quit) { if(!argParser.quiet){ std::cout << "replaying [" << replayHandler.getCurIndex() << "/" << replayHandler.getMaxIndex() @@ -26,7 +30,7 @@ void startHeadless(const ArgParser& argParser) replayHandler.stop(); std::cout << "replay handler stopped" << std::endl; - while(no_exit) sleep(1); + while(argParser.no_exit && !do_quit) sleep(1); } int startGui(int argc, char* argv[], const ArgParser& argParser) diff --git a/src/ReplayGui.cpp b/src/ReplayGui.cpp index 922fda5..22b41c5 100644 --- a/src/ReplayGui.cpp +++ b/src/ReplayGui.cpp @@ -75,7 +75,7 @@ void ReplayGui::initReplayHandler( title = "Rock-Replay"; break; case 1: - title = QString(fileNames[0].c_str()); + title = QString::fromStdString(fileNames[0]); break; default: title = QString("Multi Logfile Replay"); @@ -188,8 +188,8 @@ void ReplayGui::statusUpdate() { QString interval = " [" + QString::number(replayHandler.getMinSpan()) + "/" + QString::number(replayHandler.getMaxSpan()) + "]"; ui.curSampleNum->setText(QString::number(replayHandler.getCurIndex()) + "/" + QString::number(replayHandler.getMaxIndex()) + interval); - ui.curTimestamp->setText(replayHandler.getCurTimeStamp().c_str()); - ui.curPortName->setText(replayHandler.getCurSamplePortName().c_str()); + ui.curTimestamp->setText(QString::fromStdString(replayHandler.getCurTimeStamp())); + ui.curPortName->setText(QString::fromStdString(replayHandler.getCurSamplePortName())); ui.curPortName->setAutoFillBackground(!replayHandler.canSampleBeReplayed()); ui.progressSlider->setSliderPosition(replayHandler.getCurIndex()); ui.speedBar->setValue(replayHandler.getCurrentSpeed() * 100); @@ -269,20 +269,25 @@ void ReplayGui::updateTaskView() for(const auto& taskName2Ports : replayHandler.getTaskNamesWithPorts()) { - auto* task = new QStandardItem(taskName2Ports.first.c_str()); + auto* task = new QStandardItem(QString::fromStdString(taskName2Ports.first)); task->setCheckable(false); - QList portTypes; - for(const auto& portName : taskName2Ports.second) + for(const auto& portName : taskName2Ports.second.replayable) { - QStandardItem* port = new QStandardItem(portName.first.c_str()); + QStandardItem* port = new QStandardItem(QString::fromStdString(portName.name)); port->setCheckable(true); port->setData(Qt::Checked, Qt::CheckStateRole); - task->appendRow(port); - portTypes.push_back(new QStandardItem(portName.second.c_str())); + task->appendRow(QList { + port, new QStandardItem(QString::fromStdString(portName.type))}); + } + for(const auto& portName : taskName2Ports.second.unreplayable) + { + QStandardItem* port = new QStandardItem(QString::fromStdString(portName.name)); + port->setCheckable(false); + port->setEnabled(false); + task->appendRow(QList { + port, new QStandardItem(QString::fromStdString(portName.type)+" [missing typekit]")}); } - - task->appendColumn(portTypes); tasksModel->appendRow(task); } diff --git a/src/ReplayHandler.cpp b/src/ReplayHandler.cpp index 3d6de4e..c09b025 100644 --- a/src/ReplayHandler.cpp +++ b/src/ReplayHandler.cpp @@ -49,7 +49,7 @@ void ReplayHandler::deinit() } } -std::map>> ReplayHandler::getTaskNamesWithPorts() +ReplayHandler::TaskCollection ReplayHandler::getTaskNamesWithPorts() { return manager.getTaskCollection(); } diff --git a/src/ReplayHandler.hpp b/src/ReplayHandler.hpp index 0e1422d..60d1890 100644 --- a/src/ReplayHandler.hpp +++ b/src/ReplayHandler.hpp @@ -15,6 +15,9 @@ class ReplayHandler { public: + + using TaskCollection = LogTaskManager::TaskCollection; + /** * @brief Constructor. * @@ -118,7 +121,7 @@ class ReplayHandler * @brief Returns a map of task names with a list of their ports. * @return std::map> Map of task names with list of ports. */ - std::map>> getTaskNamesWithPorts(); + TaskCollection getTaskNamesWithPorts(); /** * @brief Returns the current sample timestamp.