Page 1 of 1

Call External C Library

Posted: Tue Apr 30, 2013 4:38 pm
by zak
Is it possible to call an external c library from within the EMCA script environment? Or are scripts executed in a "sandbox" that not allow that, and would I instead have to modify C++ source (getting the applicable license of course) accomplish that kind of functionality?

Thanks, Zak

Re: Call External C Library

Posted: Wed May 01, 2013 8:03 am
by andrew
C/C++ code can only be called from ECMAScript if script wrappers exist (which is the case for most of the Qt and QCAD API).

You may provide script wrappers for any third-party library through a QCAD C++ plugin. A plugin implements a plugin interface which provides two functions:

Code: Select all

void init()
void initScriptExtensions(QScriptEngine& engine)
init() is called when the plugin is loaded. initScriptExtensions(QScriptEngine& engine) is called whenever a new script engine is created (one for the application, one for each new document).

Inside initScriptExtensions(QScriptEngine& engine), you can initialize any script wrappers. Script wrappers can make almost anything scriptable (C++ classes, C methods, enums, ...).

See also http://qt-project.org/doc/qt-4.8/scripting.html

Re: Call External C Library

Posted: Wed May 01, 2013 5:48 pm
by zak
Excellent! Your're using QT Script Engine, that makes sense. Thanks for the quick response.

Re: Call External C Library

Posted: Wed May 15, 2013 7:12 pm
by matthiaswm
Hmm. That is not entirely clear to me.

So I need to create a dynamic library with the "C" functions mentioned above, containing a Q... class interface. That much is clear.

But where do I put the library so that QCAD will find it in the initialization phase?
Or do I need to call something in the .js file to register my extension?
Or will I need another license?

I would use this to write a driver for my Laser Cutter. I want QCAD to communicate via USB with the cutter and upload and cut files right out of the software.

Thanks,

Matthias

Re: Call External C Library

Posted: Wed May 15, 2013 8:05 pm
by andrew
Typically, you would implement your C / C++ functions and classes in the plugin and expose a part of that functionality to ECMAScript.

The C++ classes are compiled into a library, together with a C++ class that implements the plugin interface (RPluginInterface). The compiled library is placed into the 'plugins' folder of the QCAD installation. Plugins are found and loaded automatically. A list of all loaded plugins can be found in the about dialog, plugins tab.

A 'Hello World' type example plugin implementation is available in support/exampleplugin:
https://github.com/qcad/qcad/tree/maste ... mpleplugin

For your use case, you might have a C++ class UsbUploader with a function uploadFile(const QString& fileName).
After making that class and function scriptable, you can create an ECMAScript that calls the C++ member function as follows:

Code: Select all

var uploader = new UsbUploader([some parameters...]);
uploader.uploadFile("/path/to/file.cnc");
Please keep in mind that all this information relates to the latest code available in the Git repository. Nothing is cast in stone, but the classes directly involved in custom plugins (RPluginInterface and RPluginInfo) are unlikely to change significantly at this point. A QCAD 3.1 Beta release is scheduled to be released in the coming days.

Re: Call External C Library

Posted: Thu May 16, 2013 9:49 pm
by matthiaswm
Thanks, that was already a great help.

EDIT3: OK, I get the plugin to work when I use the source tree. So obviously the issues are with configuring for deployment (OS X typical) and/or differences to 3.0.9. I will continue to develop in the GIT tree in the hopes that the plugin will eventually wrk in the public version.

Thanks,

Matthias

Re: Call External C Library

Posted: Fri May 17, 2013 11:30 pm
by andrew
I've just uploaded QCAD 3.1 Beta which has support for these types of C++ plugins.

A new version of the CAM add-on for QCAD is now also available as a first beta version. Although it does not compute tool radius compensation, it might still be interesting to try it out. Please refer to this thread for details:
viewtopic.php?f=17&t=2078&p=7850#p7850

Re: Call External C Library

Posted: Sat May 18, 2013 11:20 pm
by matthiaswm
OK, that works. Great! I bought the CAM addition and I can run a binary plugin and methods in it. Getting closer to running the Laser ;-)

Re: Call External C Library

Posted: Sun May 19, 2013 3:57 pm
by andrew
Excellent! That is quite impressive without any further instructions :) Let me know if you hit any brick walls.

Re: Call External C Library

Posted: Mon May 20, 2013 10:16 pm
by matthiaswm
Thanks. With all the code available, I had a fair chance of digging up things that work.

I currently have a binary plugin that talks USB (libusb is very nice!) and makes a QObject available named RLaser. I can then call RLaser.move Home(), etc. from any script file. I also added a dockable box for basic Laser Cutter control (see snapshot, to be expanded).

With the CAM output dialog, there is room for improvement.

I think that the layers should not be in a pulldown menu, but instead all layers should be visible in a scrollable multi-column view. It should be possible to sort the layers, so text marking comes before cutting, for example.

There should be one check box per layer (second column) to switch CAM export off for that layer alone. The following columns can then be managed by the CAM plugin (for the laser, that would be a pulldown (cut/engrave), power and speed (or even better, a pulldown with presets)). The settings would be saved with the layer in the .dxf file.

Also, from within the plugin, I would like to be able to send the data directly to the laser instead of saving them in a file.

Code: Select all

Sample Column View:

| 0 Draft | [ ] |
| 1 Text  | [X] |   Cut   [V] | Pwr:  20% | Spd: 100% |
| 2 CutMe | [X] |   Cut   [V] | Pwr: 100% | Spd:   6% |
| 3 Cut2  | [X] |   Cut   [V] | Birch [V] |       3mm |
| 4 Img   | [X] | Engrave [V] | Pwr:  15% | Spd: 500% | Dithered [V] |

[X] = Checkbox, [V] = Pulldown Menu

Re: Call External C Library

Posted: Mon May 20, 2013 10:55 pm
by andrew
Thanks for the input.

The two panels at the right side of the CAM export dialog ("Global options" and "Layer options") are very flexible and configurable.

For example, the configuration "GCode" is based on the file "scripts/Cam/CamConfigurations/GCode.js".
In the constructor, this exporter defines the files "GCode.ui" and "GCodeLayer.ui" to be the global and layer specific option panels to be shown for that configuration. Your own configuration can for example inherit GCode but use different global options and layer specific options. You can use "Qt Designer" to design such individual option panels (.ui files). Object names that are used for the widgets in the .ui file are directly mapped to document variables and layer properties.

Example:
We want to create a new configuration called "MyLaser", based on "GCode". But instead of GCode.ui and GCodeLayer.ui, we want to use our own .ui files:

File "MyLaser.js"

Code: Select all

include("GCode.js");

function MyLaser(documentInterface, newDocumentInterface) {
    GCode.call(this, documentInterface, newDocumentInterface);

    this.globalOptions = "MyLaser";
    this.layerOptions = "MyLaserLayer";
}

MyLaser.prototype = new GCode();
MyLaser.ui contains one combo box with its object name set to "Power".
MyLaserLayer.ui contains one combo box with its object name also set to "Power".

The power chosen as global option is then accessible in MyLaser.js as document variable:

Code: Select all

var powerGlobal = this.document.getVariable("Cam/Power");
The power chosen for the layer which is currently being processed is accessible as layer property:

Code: Select all

var layer = this.document.queryLayer(this.getEntity().getLayerId());
var powerLayer = layer.getCustomProperty("Cam/Power", powerGlobal);      // default to globally set power
Document variables and layer properties can be saved to the DXF file if XData is enabled. Since XData support is considered experimental, you will have to enable it on the command line when starting QCAD:

Code: Select all

./qcad -enable-xdata
That's probably a lot of information to digest. The reason for this relatively complex design is flexibility. The information that has to be collected from the user greatly depends on the configuration and the target machine. Configurations might use lists, tables, combo boxes, check boxes, line edits or even multiline text fields. This is somewhat unpredictable at this point, but I didn't want to impose any unnecessary limits for the user interface. Users are usually more creative than expected at first ;) If someone only engraves text for example, an exporter might only ask for a line of text and a font and not even require any CAD input.