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 GenApi 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);