Skip to content

Commit

Permalink
simulator: new command to run script and play a scenario
Browse files Browse the repository at this point in the history
- New commands: PLAY script, BREAK, and PLAY

EXIT, and the commands to resume (RUN, PLAY) are invalid in script mode.
All others are usable in script, even LOAD gpx and RUN trkid.
  • Loading branch information
janbar committed Sep 30, 2024
1 parent cdaeb17 commit e6442af
Show file tree
Hide file tree
Showing 9 changed files with 409 additions and 61 deletions.
6 changes: 4 additions & 2 deletions simulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ if(SIMULATOR_WITH_READLINE)
endif()

set(simulator_SOURCES main.cpp
commandline.cpp
globalazimuth.cpp
globalposition.cpp
gpxrunner.cpp
scriptrunner.cpp
simulatedcompass.cpp
simulatedpositionsource.cpp
simulatedsensorplugin.cpp
commandline.cpp
simulator.cpp
gpxrunner.cpp
${OSMIN_SRC_DIR}/converter.cpp
${OSMIN_SRC_DIR}/csvparser.cpp
${OSMIN_SRC_DIR}/gpxfilemodel.cpp
Expand All @@ -45,6 +46,7 @@ set(simulator_HEADERS
globalazimuth.h
globalposition.h
gpxrunner.h
scriptrunner.h
simulatedcompass.h
simulatedpositionsource.h
simulatedsensorplugin.h
Expand Down
36 changes: 11 additions & 25 deletions simulator/commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
#include <readline/history.h>
#endif

#include <string>

#define PROMPT_STRING ">>> "
#define LINE_MAXSIZE 1024

Expand All @@ -46,42 +44,29 @@ CommandLine::~CommandLine()
#endif
}

void CommandLine::forceInterruption() {
this->terminate();
#ifdef HAVE_READLINE
// cleanup the state of the terminal
rl_cleanup_after_signal();
#endif
}

void CommandLine::run()
{
int r = readstdin(_buffer, LINE_MAXSIZE);
if (r > 0)
{
// a line must be terminated by nl
_buffer[r - 1] = '\0';
emit newCommand(tokenize(" ", true));
emit newCommand(QString(_buffer));
}
else
{
emit eof();
}
}

QStringList CommandLine::tokenize(const char *delimiters, bool trimnull)
{
QStringList tokens;
std::string tmp(_buffer);
std::string::size_type pa = 0, pb = 0;
unsigned n = 0;
// Counter n will break infinite loop. Max count is 255 tokens
while ((pb = tmp.find_first_of(delimiters, pb)) != std::string::npos && ++n < 255)
{
tokens.push_back(QString::fromStdString(tmp.substr(pa, pb - pa)));
do
{
pa = ++pb;
}
while (trimnull && tmp.find_first_of(delimiters, pb) == pb);
}

if (!trimnull || pa < tmp.size())
tokens.push_back(QString::fromStdString(tmp.substr(pa)));
return tokens;
}

#ifdef HAVE_READLINE
int CommandLine::readstdin(char *buf, size_t maxlen)
{
Expand Down Expand Up @@ -114,6 +99,7 @@ int CommandLine::readstdin(char *buf, size_t maxlen)
}

/* get a new line */
rl_catch_signals = 0;
rl_line = readline(PROMPT_STRING);
/* if the line has any text in it */
if (rl_line)
Expand Down
9 changes: 7 additions & 2 deletions simulator/commandline.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,23 @@ class CommandLine : public QThread
Q_OBJECT

signals:
void newCommand(QStringList tokens);
void newCommand(QString line);
void eof();

public:
CommandLine();
~CommandLine();

/** Terminate the running thread, and reset state of the terminal.
* Prefer this instead terminate(), which won't cleanup the state
* of the terminal.
*/
void forceInterruption();

private:
char * _buffer;

void run();
QStringList tokenize(const char *delimiters, bool trimnull = false);

int readstdin(char *buf, size_t maxlen);
#ifdef HAVE_READLINE
Expand Down
3 changes: 2 additions & 1 deletion simulator/gpxrunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ void GPXRunner::run()
{
while (wait > 0)
{
if (isInterruptionRequested())
// check for thread interrupted, not this
if (QThread::currentThread()->isInterruptionRequested())
{
_running->aborted = true;
break;
Expand Down
3 changes: 2 additions & 1 deletion simulator/gpxrunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class GPXRunner : public QThread
bool configureRun(int trackid, int tick, double speed, int startpts);
bool isRunAborted() { return (_running ? _running->aborted : false); }

void run() override;

signals:
void pointChanged(int pts);

Expand Down Expand Up @@ -73,7 +75,6 @@ class GPXRunner : public QThread
GPXFile * _gpxfile = nullptr;
Running * _running = nullptr;

void run() override;
bool processNextPoint(int * waitfor);

/* file loader progress callback
Expand Down
99 changes: 99 additions & 0 deletions simulator/scriptrunner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2024
* Jean-Luc Barriere <jlbarriere68@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "scriptrunner.h"
#include "simulator.h"

#include <QByteArray>
#include <QEventLoop>
#include <cassert>

#define LINE_MAXSIZE 1024

ScriptRunner::~ScriptRunner()
{
if (isRunning())
{
this->requestInterruption();
this->wait();
}
if (_file)
delete _file;
}

bool ScriptRunner::configureScript(const QString &filepath)
{
QFile file(filepath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
file.close();
if (_file)
delete _file;
_file = new QFile(filepath);
return true;
}
return false;
}

QString ScriptRunner::filepath() const
{
if (_file)
return _file->fileName();
return QString();
}

void ScriptRunner::run()
{
if (_file == nullptr)
return;
if (!_file->isOpen() && !_file->open(QIODevice::ReadOnly | QIODevice::Text))
return;
_aborted = false;
while (processCommand())
{
// check for thread interrupted, not this
if (QThread::currentThread()->isInterruptionRequested())
{
_aborted = true;
break;
}
// now the command is completed, therefore clear recover
_redo = false;
}
if (!_aborted)
_file->close();
}

void ScriptRunner::recover()
{
qDebug("rollback %s : %s", filepath().toStdString().c_str(), _command.constData());
_redo = true;
}

bool ScriptRunner::processCommand()
{
assert(_file->isOpen() == true);
// redo last aborted command or process next
if (!_redo)
_command = _file->readLine(LINE_MAXSIZE);

if (_command.isEmpty() || _command.back() != '\n')
return false;
fprintf(stdout, "PLAY: %s", _command.constData());
_simulator.onCommand(QString(_command.mid(0, _command.size()-1)));
return true;
}
55 changes: 55 additions & 0 deletions simulator/scriptrunner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2024
* Jean-Luc Barriere <jlbarriere68@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCRIPTRUNNER_H
#define SCRIPTRUNNER_H

#include <QObject>
#include <QString>
#include <QThread>
#include <QFile>
#include <QByteArray>

class Simulator;

class ScriptRunner : public QThread
{
Q_OBJECT
public:
explicit ScriptRunner(Simulator& s)
: _simulator(s) { }
~ScriptRunner();

bool configureScript(const QString& filepath);
bool isRunAborted() { return (_file ? _aborted : false); }
QString filepath() const;

void run();
void recover();
bool isRecovery() const { return _redo; }

private:
bool processCommand();

bool _aborted = false;
bool _redo = false;
bool _finished = false;
Simulator& _simulator;
QFile * _file = nullptr;
QByteArray _command;
};

#endif // SCRIPTRUNNER_H
Loading

0 comments on commit e6442af

Please sign in to comment.