Euresys GenApi scripts
The Euresys GenApi Script language is documented in a few GenApi scripts. For convenience, they are also included here.
doc/basics.js
// Euresys GenApi Script uses a syntax inspired by JavaScript, but is not
// exactly JavaScript. Using the extension .js for scripts is just a way to get
// proper syntax highlighting in text editors.
//
// This file describes the basics of Euresys GenApi Script. It can be executed
// by running 'gentl script <path-to-coaxlink-scripts-dir>/doc/basics.js', or
// more simply 'gentl script coaxlink://doc/basics.js'.
// Euresys GenApi Script is case-sensitive.
// Statements are always separated by semicolons (JavaScript is more
// permissive).
// Single-line comment
/* Multi-line comment
(cannot be nested)
*/
// Function declaration
function multiply(a, b) {
return a * b;
}
// Functions can be nested
function sumOfSquares(a, b) {
function square(x) {
return x * x;
}
return square(a) + square(b);
}
// Variable declaration
function Variables() {
var x = 1; // 1
var y = 2 * x; // 2
var z; // undefined
}
// Data types
function DataTypes() {
// Primitive types: Boolean, Number, String, undefined
function Booleans() {
var x = true;
var y = false;
}
function Numbers() {
var x = 3.14159;
var y = -1;
var z = 6.022e23;
}
function Strings() {
var empty = "";
var x = "euresys";
var y = 'coaxlink';
}
function Undefined() {
// undefined is the type of variables without a value
// undefined is also a special value
var x; // undefined
x = 1; // x has a value
x = undefined; // x is now again undefined
}
// Objects: Object (unordered set of key/value pairs), Array (ordered list
// of values), RegExp (regular expression)
function Objects() {
// Construction
var empty = {};
var x = { a: 1, b: 2, c: 3 };
var y = { other: x };
// Access to object properties
var sum1 = x.a + x.b + x.c; // dot notation
var sum2 = x['a'] + x['b'] + x['c']; // bracket notation
// Adding properties
x.d = 4; // x: { a: 1, b: 2, c: 3, d: 4 }
x["e"] = 5; // x: { a: 1, b: 2, c: 3, d: 4, e: 5 }
}
function Arrays() {
// Construction
var empty = [];
var x = [3.14159, 2.71828];
var mix = [1, false, "abc", {}];
// Access to array elements
var sum = x[0] + x[1]; // bracket notation
// Adding elements
x[2] = 1.61803; // x: [3.14159, 2.71828, 1.61803]
x[4] = 1.41421; // x: [3.14159, 2.71828, 1.61803, undefined, 1.41421];
}
function RegularExpressions() {
var x = /CXP[36]_X[124]/;
}
}
// Like JavaScript, Euresys GenApi Script is a dynamically typed language. The
// type of a variable is defined by the value it holds, which can change.
function DynamicVariables() {
var x = 1; // Number
x = "x is now a string";
}
// Object types are accessed by reference.
function References() {
var x = [3.14159, 2.71828]; // x is a reference to an array
var y = x; // y is a reference to the same array
assertEqual(x.length, y.length);
assertEqual(x[0], y[0]);
assertEqual(x[1], y[1]);
y[2] = 1.61803; // the array can be modified via any reference
assertEqual(x[2], y[2]);
function update(obj) {
// objects (including arrays) are passed by reference
obj.updated = true;
obj.added = true;
}
var z = { initialized: true, updated: false };
assertEqual(true, z.initialized);
assertEqual(false, z.updated);
assertEqual(undefined, z.added);
update(z);
assertEqual(true, z.initialized);
assertEqual(true, z.updated);
assertEqual(true, z.added);
}
// Supported operators
function Operators() {
// From lowest to highest precedence:
// Assignment operators: = += -= *= /=
var x = 3;
x += 2;
x -= 1;
x *= 3;
x /= 5;
assertEqual(2.4, x);
// Logical OR: ||
assertEqual(true, false || true);
assertEqual('ok', false || 'ok');
assertEqual('ok', 'ok' || 'ignored');
// Logical AND: &&
assertEqual(false, true && false);
assertEqual(true, true && true);
assertEqual('ok', true && 'ok');
// Identity (strict equality) and non-identity (strict inequality): === !==
assertEqual(true, 1 === 2 / 2);
assertEqual(true, 1 !== 2);
// Equality (==) and inequality (!=) JavaScript operators lead to confusing
// and inconsistent conversions of their operands. They are not implemented
// in Euresys GenApi Script.
// Relational operators: < <= > >=
assert(1 < 2);
assert(1 <= 1);
assert(2 > 1);
assert(2 >= 2);
// Addition and subtraction: + -
assertEqual(1, 3 - 2);
assertEqual(5, 2 + 3);
assertEqual("abcdef", "abc" + "def"); // if one of the operands is of type
assertEqual("abc123", "abc" + 123); // string, all operands are converted
assertEqual("123456", 123 + "456"); // to string, and concatenated
// Multiplication and division: * /
assertEqual(4.5, 3 * 3 / 2);
// Prefix operators: ++ -- ! typeof
var x = 0;
assertEqual(1, ++x);
assertEqual(1, x);
assertEqual(0, --x);
assertEqual(0, x);
assertEqual(true, !false);
assertEqual('boolean', typeof false);
assertEqual('number', typeof 0);
assertEqual('string', typeof '');
assertEqual('undefined', typeof undefined);
assertEqual('function', typeof function () {});
assertEqual('object', typeof {});
assertEqual('object', typeof []);
assertEqual('object', typeof /re/);
assertEqual('object', typeof null);
// Postfix operators: ++ --
var x = 0;
assertEqual(0, x++);
assertEqual(1, x);
assertEqual(1, x--);
assertEqual(0, x);
// Function call: ()
assertEqual(6, multiply(3, 2));
// Member access: . []
var obj = { a: 1 };
assertEqual(1, obj.a);
obj['4'] = 'four';
assertEqual('four', obj[2*2]);
}
// Scope of variables
function OuterFunction() {
var x = 'outer x';
function Shadowing() {
assertEqual(undefined, x);
var x = 'inner x';
assertEqual('inner x', x);
}
function Nested() {
assertEqual('outer x', x);
var y = 'not accessible outside Nested';
x += ' changed in Nested';
}
function NoBlockScope() {
var x = 1;
assertEqual(1, x);
if (true) {
// The scope of variables is the function.
// This variable x is the same as the one outside the if block.
var x = 2;
}
assertEqual(2, x);
}
assertEqual('outer x', x);
Shadowing();
assertEqual('outer x', x);
Nested();
assertEqual('outer x changed in Nested', x);
NoBlockScope();
}
// Loops
function Loops() {
// for loops
function ForLoops() {
var i;
var sum = 0;
for (i = 0; i < 6; ++i) {
sum += i;
}
assertEqual(15, sum);
}
// for..in loops: iterating over indices
function ForInLoops() {
var xs = [1, 10, 100, 1000];
var sum = 0;
for (var i in xs) {
sum += xs[i];
}
assertEqual(1111, sum);
var obj = { one: 1, two: 2 };
var sum = 0;
for (var p in obj) {
sum += obj[p];
}
assertEqual(3, sum);
var str = "Coaxlink";
var sum = "";
for (var i in str) {
sum += str[i];
}
assertEqual("Coaxlink", sum);
}
// for..of loops: iterating over values
function ForOfLoops() {
var xs = [1, 10, 100, 1000];
var sum = 0;
for (var x of xs) {
sum += x;
}
assertEqual(1111, sum);
var obj = { one: 1, two: 2 };
var sum = 0;
for (var x of obj) {
sum += x;
}
assertEqual(3, sum);
var str = "Coaxlink";
var sum = "";
for (var c of str) {
sum += c;
}
assertEqual("Coaxlink", sum);
}
function ContinueAndBreak() {
var i;
var sum = 0;
for (i = 0; i < 100; ++i) {
if (i === 3) {
continue;
} else if (i === 6) {
break;
} else {
sum += i;
}
}
assertEqual(0 + 1 + 2 + 4 + 5, sum);
}
ForLoops();
ForInLoops();
ForOfLoops();
ContinueAndBreak();
}
function Exceptions() {
var x;
var caught;
var finallyDone;
function f(action) {
x = 0;
caught = undefined;
finallyDone = false;
try {
x = 1;
if (action === 'fail') {
throw action;
} else if (action === 'return') {
return;
}
x = 2;
} catch (e) {
// Executed if a throw statement is executed.
assertEqual(1, x);
caught = e;
} finally {
// Executed regardless of whether or not a throw statement is
// executed. Also executed if a return statement causes the
// function to exit before the end of the try block.
finallyDone = true;
}
}
f('fail');
assertEqual(1, x);
assertEqual('fail', caught);
assert(finallyDone);
f('return');
assertEqual(1, x);
assert(!caught);
assert(finallyDone);
f();
assertEqual(2, x);
assert(!caught);
assert(finallyDone);
}
// Run tests
References();
Operators();
OuterFunction();
Loops();
Exceptions();
function assertEqual(expected, actual) {
if (expected !== actual) {
throw 'expected: ' + expected + ', actual: ' + actual;
}
}
function assert(condition) {
if (!condition) {
throw 'failed assertion';
}
}
doc/builtins.js
// This file describes the builtins (functions or objects) of Euresys GenApi
// Script. It can be executed by running 'gentl script
// coaxlink://doc/builtins.js'.
// The builtin object 'console' contains a function 'log' which can be
// used to output text to the standard output (if available) as well as to
// Memento with the notice verbosity level.
console.log('Hello from ' + module.filename);
console.log('If several arguments are passed,', 'they are joined with spaces');
console.log('All text is sent to both standard output and Memento');
// The builtin object 'memento' contains the following functions: error,
// warning, notice, info, debug, verbose (each corresponding to a different
// verbosity level in Memento). They are similar to console.log, except that
// the text is only sent to Memento.
memento.error('error description');
memento.warning('warning description');
memento.notice('important notification');
memento.info('message');
memento.debug('debug information');
memento.verbose('more debug information');
// For convenience, the object 'console' also contains the same methods as the
// object 'memento'; the functions are similar to their 'memento' counterparts,
// except that they also send text to the standard output if available
console.error('error description');
console.warning('warning description');
console.notice('important notification');
console.info('message');
console.debug('debug information');
console.verbose('more debug information');
// Explicit type conversion/information functions:
console.log('Boolean(0) = ' + Boolean(0)); // false
console.log('Boolean(3) = ' + Boolean(3)); // true
console.log('Number(false) = ' + Number(false)); // 0
console.log('Number(true) = ' + Number(true)); // 1
console.log('Number("3.14") = ' + Number("3.14")); // 3.14
console.log('Number("0x16") = ' + Number("0x16")); // 22
console.log('Number("1e-9") = ' + Number("1e-9")); // 1e-9
console.log('String(false) = ' + String(false)); // "false"
console.log('String(true) = ' + String(true)); // "true"
console.log('String(3.14) = ' + String(3.14)); // "3.14"
console.log('String([1, 2]) = ' + String([1, 2])); // "1,2"
console.log('isNaN(0/0) = ' + isNaN(0/0)); // true
console.log('isNaN(Infinity) = ' + isNaN(Infinity)); // false
console.log('isRegExp(/re/) = ' + isRegExp(/re/)); // true
console.log('isRegExp("/re/") = ' + isRegExp("/re/")); // false
console.log('Array.isArray({}) = ' + Array.isArray({})); // false
console.log('Array.isArray([]) = ' + Array.isArray([])); // true
// The builtin object 'Math' contains a few functions:
console.log('Math.floor(3.14) = ' + Math.floor(3.14));
console.log('Math.ceil(3.14) = ' + Math.ceil(3.14));
console.log('Math.abs(-1.5) = ' + Math.abs(1.5));
console.log('Math.pow(2, 5) = ' + Math.pow(2, 5));
console.log('Math.log2(2048) = ' + Math.log2(2048));
// String manipulation
console.log('"Duo & Duo".replace(/Duo/, "Quad") = "' +
"Duo & Duo".replace(/Duo/, "Quad") + '"'); // "Quad & Duo"
console.log('"Duo & Duo".replace(/Duo/g, "Quad") = "' +
"Duo & Duo".replace(/Duo/g, "Quad") + '"'); // "Quad & Quad"
console.log('"Hello, Coaxlink".toLowerCase() = "' +
"Hello, Coaxlink".toLowerCase() + '"'); // "hello, coaxlink"
console.log('"Coaxlink Quad G3".includes("Quad") = ' +
"Coaxlink Quad G3".includes("Quad")); // true
console.log('"Coaxlink Quad".includes("G3") = ' +
"Coaxlink Quad".includes("G3")); // false
console.log('"Coaxlink Quad G3".split(" ") = [' +
"Coaxlink Quad G3".split(" ") + ']'); // [Coaxlink,Quad,G3]
console.log('"Coaxlink Quad G3".split("Quad") = [' +
"Coaxlink Quad G3".split("Quad") + ']'); // [Coaxlink , G3]
console.log('["Mono", "Duo", "Quad"].join() = "' +
["Mono", "Duo", "Quad"].join() + '"'); // "Mono,Duo,Quad"
console.log('["Mono", "Duo", "Quad"].join(" & ") = "' +
["Mono", "Duo", "Quad"].join(" & ") + '"'); // "Mono & Duo & Quad"
// Utility functions
console.log('random(0,1): ' + random(0,1)); // random number between 0 and 1
sleep(0.5); // pause execution of script for 0.5 second
// The builtin function 'require' loads a script, executes it, and returns
// the value of the special 'module.exports' from that module.
var mod1 = require('./module1.js');
console.log('mod1.description: ' + mod1.description);
console.log('mod1.plus2(3): ' + mod1.plus2(3));
console.log('calling mod1.hello()...');
mod1.hello();
// 'require' can deal with:
// - absolute paths
// var mod = require('C:\\absolute\\path\\some-module.js');
// - relative paths (paths relative to the current script)
// var mod = require('./utils/helper.js');
// - coaxlink:// paths (paths relative to the directory where coaxlink scripts
// are installed)
// var mod = require(coaxlink://doc/builtins.js);
doc/grabbers.js
// This file describes the 'grabbers' object of Euresys GenApi Script. It can
// be executed by running 'gentl script coaxlink://doc/grabbers.js'.
// The builtin object 'grabbers' is a list of objects giving access to the
// available GenTL modules/ports.
// In most cases, 'grabbers' contains exactly one element. However, when using
// the 'gentl script' command, 'grabbers' contains the list of all devices.
// This makes it possible to configure several cameras and/or cards.
console.log("grabbers.length:", grabbers.length);
// Each item in 'grabbers' encapsulates all the ports related to one data
// stream:
// TLPort | GenTL producer
// InterfacePort | Coaxlink card
// DevicePort | local device
// StreamPort | data stream
// RemotePort | camera (if available)
var PortNames = ['TLPort', 'InterfacePort', 'DevicePort', 'StreamPort',
'RemotePort'];
// Ports are objects which provide the following textual information:
// name | one of PortNames
// tag | port handle type and value (as shown in memento traces)
for (var i in grabbers) {
var g = grabbers[i];
console.log('- grabbers[' + i + ']');
for (var pn of PortNames) {
var port = g[pn];
console.log(' - ' + port.name + ' (' + port.tag + ')');
}
}
// Ports also have the following functions to work on GenICam features:
// get(f) | get value of f
// set(f,v) | set value v to f
// execute(f) | execute f
// done(f) | test if command f is done (execution completed)
// features([re]) | get list of features [matching~ re]
// $features([re]) | strict* variant of features([re])
// featuresOf(c, [re]) | get list of features of category c [matching~ re]
// $featuresOf(c, [re]) | strict* variant of featuresOf(c, [re])
// categories([re]) | get list of categories [matching~ re]
// $categories([re]) | strict* variant of categories([re])
// categoriesOf(c, [re]) | get list of categories of category c [matching~ re]
// $categoriesOf(c, [re]) | strict* variant of categoriesOf(c, [re])
// ee(f,[re]) | get list of enum entries [matching~ re]
// | of enumeration f
// $ee(f,[re]) | strict* variant of ee(f,[re])
// has(f) | test if f exists
// has(f,v) | test if f has an enum entry v
// available(f) | test if f is available
// available(f,v) | test if f has an enum entry v which is available
// readable(f) | test if f is readable
// writeable(f) | test if f is writeable
// implemented(f) | test if f is implemented
// command(f) | test if f is a command
// selectors(f) | get list of features that act as selectors of f
// attributes(...) | extract information from the XML file describing
// | the port
// interfaces(f) | get list of interfaces of f (e.g. ["IInteger"])
// source(f) | get the XML source of f
// info(f,what) | get XML information what of f
// declare(t,f) | declare a virtual user feature f of type t,
// | t can be one of "integer", "float", "string"
// undeclare(f) | undeclare (delete) a virtual user feature f
// declared() | get list of virtual user features
//
// * by strict we mean that the returned list contains only nodes/values
// that are available (as dictated by 'pIsAvailable' GenICam node elements)
// ~ the returned list is filtered by regular expression matching
if (grabbers.length) {
var port = grabbers[0].InterfacePort;
console.log('Playing with', port.tag);
// get(f)
console.log('- InterfaceID: ' + port.get('InterfaceID'));
// set(f,v)
port.set('LineSelector', 'TTLIO11');
// execute(f)
port.execute('DeviceUpdateList');
// features(re)
console.log('- Features matching \'PCIe\':');
for (var f of port.features('PCIe')) {
console.log(' - ' + f);
}
// $ee(f)
console.log('- Available enum entries for LineSource:');
for (var ee of port.$ee('LineSource')) {
console.log(' - ' + ee);
}
for (var ix of [0, 1, 2, 3, 9]) {
var ee = 'Device' + ix + 'Strobe';
// has(f, v)
if (port.has('LineSource', ee)) {
console.log('- ' + ee + ' exists');
} else {
console.log('- ' + ee + ' does not exist');
}
// available(f, v)
if (port.available('LineSource', ee)) {
console.log('- ' + ee + ' is available');
} else {
console.log('- ' + ee + ' is not available');
}
}
// selectors(f)
console.log('- LineSource feature is selected by',
port.selectors('LineSource'));
// attributes()
console.log('- attributes()');
var attrs = port.attributes();
for (var n in attrs) {
console.log(' - ' + n + ': ' + attrs[n]);
}
// attributes(f)
console.log('- attributes(\'LineFormat\')');
var attrs = port.attributes('LineFormat');
for (var n in attrs) {
console.log(' - ' + n + ': ' + attrs[n]);
}
// attributes(f)
var fmt = port.get('LineFormat');
console.log('- attributes(\'LineFormat\', \'' + fmt + '\')');
var attrs = port.attributes('LineFormat', fmt);
for (var n in attrs) {
console.log(' - ' + n + ': ' + attrs[n]);
}
// optional suffixes to integer or float feature names
if (port.available('DividerToolSelector') &&
port.available('DividerToolSelector', 'DIV1')) {
var feature = 'DividerToolDivisionFactor[DIV1]';
var suffixes = ['.Min', '.Max', '.Inc', '.Value'];
console.log('- Accessing ' + suffixes + ' of ' + feature);
for (var suffix of suffixes) {
console.log( ' - ' + suffix + ': ' + port.get(feature + suffix));
}
}
}
// Camera ports (RemotePort) also have the following functions:
// brRead(addr) | read bootstrap register (32-bit big endian)
// brWrite(addr,v) | write value to bootstrap register (32-bit big endian)
if (grabbers.length) {
var port = grabbers[0].RemotePort;
if (port) {
console.log('Playing with', port.tag);
var brStandard = 0x00000000;
var brRevision = 0x00000004;
var standard = port.brRead(brStandard);
var revision = port.brRead(brRevision);
if (0xc0a79ae5 === standard) {
console.log('Bootstrap register "Standard" is OK (0xc0a79ae5)');
} else {
console.log('Bootstrap register "Standard" is ' + standard);
}
console.log('Bootstrap register "Revision" is ' + revision);
}
}
doc/module1.js
// This file describes the special 'module' variable of Euresys GenApi Script.
// It can be executed by running 'gentl script coaxlink://doc/module1.js'. It
// is also dynamically loaded by the coaxlink://doc/builtins.js script.
// 'module' is a special per-module variable. It cannot be declared with var.
// It always exists, and contains a few items:
console.log('Started execution of "' + module.filename + '"');
console.log('This script is located in directory "' + module.curdir + '"');
// Modules can export values via module.exports (which is initialized as an
// empty object):
module.exports = { description: 'Example of Euresys GenApi Script module'
, plus2: function(x) {
return x + 2;
}
, hello: function() {
console.log('Hello from ' + module.filename);
}
};
console.log('module.exports contains: ');
for (var e in module.exports) {
console.log('- ' + e + ' (' + typeof module.exports[e] + ')');
}
console.log('Completed execution of ' + module.filename);