Embedded scripting recommendation



  • Hi All,

    I've spent most of the day looking through a ton of embedded scripting options. Some seem easy, some claim to work but seem to have some issues running even the simplest examples. So I'm looking for some recommendations.

    I'm write an instrument control app that has to be Win32 (hardware limitation). I don't need a ton of scripting horsepower. Basically I need the following:

    1. Some basic math
    2. Mostly simple variables (int, float, string)
    3. Timing (IE delays, timers would be nice)
    4. Loops
    5. Ability to export or create functions to call some internal routines I will have to control the instrument.

    I'm not too particular on the syntax since it will be used really for test purposes. IE the operator will want to repeatedly test a particular operation so they would write a short script that loops the desired number of times and calls some function I give them to control the device.

    Thats really about the extent of what I need. It seems like most of the embedded scriptors I've been looking at aim much higher than I need and seem rather difficult to implement and some when I've downloaded and attempted to include/compile their simple example have bombed pretty bad either causing AVs or not compiling at all.

    I saw that there was a QtPython and I thought "alright!" but it too seems not to like Qt 5.4. It seems to have last been updated in 2012.

    I do see QtScript and I'm reading about it but wonder if it can do what I want/need.

    Any recommendations?

    Thanks in advance.


  • Moderators

    Hi,

    Qt Script supports JavaScript, and I know JavaScript supports #1 to #4 of your list. Could you explain what you mean by #5?

    An alternative is to use QJSEngine, which also supports JavaScript (see "Making Applications Scriptable":http://doc.qt.io/qt-5.4/qtjavascript.html). It is newer than Qt Script but simpler.



  • Hi JKSH

    Thanks so much for the reply.

    What I mean by #5 is in my app I will have a small API of sorts to control the instrument I must talk to. For example there will be a X/Y robot so I'll probably have a class/methods to move the robot around. I want to be able to expose these in some fashion to the script.

    For example in a much older application written in Delphi years and years ago we had a pascal based scripting language and for each low-level function we had, one of them was in fact MoveRobot() I had a scriptable version. So in a script we could write something like:

    @procedure MoveToPark();
    begin
    MoveRobot( parkX, parkY );
    end;@

    All of the above code was evaluated by the script engine and "MoveRobot()" was evaluated and a call to my internal API MoveRobot() was made.

    That is my goal. The purpose of this app right now is to provide a test bed for some new hardware being developed. The mechanical and fluidics engineers are looking for something where they can say exercise the robot between some positions repeatedly.

    While I could do this in code quickly for them the eventual goal will be to have them writing a sequence that takes the instrument through its paces.

    As I mentioned my scripting needs are pretty simple. I don't need true objects just mainly the stuff in the list. In our prior scripting language (years and years ago again) we could have functions, variables etc. it was pretty advanced for a script language of 15 years ago.

    I'll check out JSEngine. Thanks for the reference!



  • At an initial glance JSEngine looks ok. Since you can "pass in" an object I think I can use that method to make instrument control routines available to the script.

    I'll check this out further. Thanks again!



  • Hello, I'd also advice use of QtScript, it basicaly does all you required. It also has fine debugger window with it, and can export separate functions (both of these are different for QJSEngine as far as I know). I'll give you some snippets to start with:
    Qt project.pro integration:
    @QT += core gui widgets script scripttools@

    If you dont need the debugger window, you can omit gui, widgets and scripttools (latter is debuger module, and debugger is a widget, that requires gui app)
    The next step, you can have this class
    @#include <QObject>
    #include <QScriptEngine>
    #include <QScriptEngineDebugger>

    class Engine : public QObject
    {
    Q_OBJECT

    public:
    Engine();
    ~Engine();

    public slots:
    void start();

    private:
    QScriptEngine *js;
    QScriptEngineDebugger *dbg;
    };
    Engine::Engine()
    : js(new QScriptEngine)
    , dbg(new QScriptEngineDebugger)
    {
    js->globalObject().setProperty("script", js->newFunction(script));
    js->globalObject().setProperty("warning", js->newFunction(warning));
    js->globalObject().setProperty("quit", js->newFunction(quit));

    dbg->attachTo(js);
    dbg->setAutoShowStandardWindow(true);
    }

    Engine::~Engine()
    {
    delete dbg; dbg = nullptr;
    delete js; js = nullptr;
    }

    void Engine::start()
    {
    fileEval(js, "myStartScript");
    }
    QScriptValue fileEval(QScriptEngine* js, const QString &name)
    {
    QString path = QString("./../scripts/%0.js").arg(name);
    QFile scriptFile(path);
    if (!scriptFile.open(QIODevice::ReadOnly))
    qDebug() << "Script file does not exist:" << name;
    QString code = scriptFile.readAll();
    scriptFile.close();

    QElapsedTimer tmr;
    tmr.start();
    QScriptValue result = js->evaluate(code, name);

    if (result.isError())
    qDebug() << "Uncaught exception:" << result.toString();
    qDebug() << "script" << name << "executed in" << tmr.elapsed() << "msec";
    return result;
    }
    QScriptValue script(QScriptContext* ctx, QScriptEngine* eng)
    {
    return fileEval(eng, ctx->argument(0).toString());
    }

    QScriptValue warning(QScriptContext* ctx, QScriptEngine* eng)
    {
    Q_UNUSED(eng);
    qDebug() << "Warning:" << ctx->argument(0).toString();
    return 0;
    }

    QScriptValue quit(QScriptContext* ctx, QScriptEngine* eng)
    {
    Q_UNUSED(ctx); Q_UNUSED(eng);
    QApplication::quit();
    return 0;
    }@

    Now you can write js scripts or extend the engine itself. Script example:
    @var check = script("someScript"); // do not include '.js' as it is already accounted for
    warning('additional scripts loaded!');
    quit(); // app exit@


  • Moderators

    You're most welcome :)

    I'm pretty sure QJSEngine lets you do #1 to #5 too. I haven't used Qt Script or QJSEngine myself though, so please do check them out further before committing.

    All the best!



  • @RaubTieR - Thanks very much! I get the idea from your code however I couldn't seem to get it to link. So I pulled the basics out and it helped to get me some ideas. Thanks so much for taking the time to post the example!

    @JKSH - You guys are the best. Thanks again for all the help.

    Hope all enjoy the new year!



  • The reason behind link failure is probably that you've forgot to run qmake on your project after adding this line
    @QT += core gui widgets script scripttools@

    The right way is to always run qmake explicitly (right mouse button in project panel) when you change your project somehow. The other option is to delete the whole build-folder (in which compiled files are). Simply "Rebuild" isn't usually sufficient in case of project modification. You run qmake for qt to prepare build-system-dependent description (could be "make", "vc project", etc.) of the project, after that it never changes automatically.



  • I've been using boost.Python and QJSEngine in my current app. I've spent most of the effort on exposing stuff to Python, since that's the "important" language for my market segment. But, a few things are useful to interop with web stuff where JS is the only language, so I have both. Boost Python is awesome, but very complicated to expose the guts of a complete large app to Python. QJSEngine would probably also drive me crazy if I wanted to do everything I am doing with my Python bindings, but for the little stuff it is currently doing, I was almost shocked how easy it is to get up and running:

    @ engine->globalObject().setProperty("nominalWeight", nominalWeight);
    QJSValue result = engine->evaluate(QString::fromStdString(logic));
    if (result.isError())
    return nominalWeight;
    return engine->globalObject().property("nominalWeight").toNumber();

    @



  • [quote author="RaubTieR" date="1419789716"]The reason behind link failure is probably that you've forgot to run qmake on your project after adding this line
    @QT += core gui widgets script scripttools@

    The right way is to always run qmake explicitly (right mouse button in project panel) when you change your project somehow. The other option is to delete the whole build-folder (in which compiled files are). Simply "Rebuild" isn't usually sufficient in case of project modification. You run qmake for qt to prepare build-system-dependent description (could be "make", "vc project", etc.) of the project, after that it never changes automatically.[/quote]

    I have learned that. I do qmakes quite often to be sure.

    I was going to wait few days to avoid flooding the forum with dumb questions I need to ask about how to do a command line build of my project.

    One of the requirements is automated weekly builds. Eventually nightly.

    I've tried copying the command lines from the compile output, making sure my paths to compiler and linker are in place but still can't seem to get a command line build to run.

    Using VS2013 compiler and once my build starts it complains it can't find stdfx.h.

    Anyway I'll work up a formal question with examples on that. Thanks for the input!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.