Custom Communication Protocol API

Custom communication scripting can be activated by a boolean VT entry that can be accessed in the DataMan Setup Tool.

The methods are encapsulated in a communication object. Each communication channel creates an instance of the communication object.

When the Custom Protocol Communication API is enabled through a private DMCC command, the scripting context adds the following capabilities and requirements:

  • The constructor function of the communication object, CommHandler, contains a list of functions that the script must contain:
    • onConnect
    • onDisconnect
    • onExpectedData
    • onTimer
    • onUnexpectedData
    • onError
    • onEncoder

The user must implement these functions, as the custom communications function will call them.

  • There are five member functions that the reader script engine offers, implemented by the reader:
    • send
    • close
    • setTimer
    • expectFramed
    • setEncoder

By using these functions, a user could write javascript code that allows the reader to interact with another system. In particular, the user can write code to send messages back to the other system, something that is not supported in basic scripting.

Advantage

The script engine uses the same context for function execution and object creation. This allows the sharing of data between the script-based formatting and the custom communication scripts using global accessible objects.

List of functions

The communication member functions define the following method prototypes to be implemented by the user:

CommHandler – The constructor function for the communication object. The constructor must return a new communication handler object implementing the user methods in the communication script. The reader methods are added to the communication handler object directly after construction. The implementation of the constructor is mandatory and an error will be thrown if it does not exist. Since software version 5.5 the constructor function call offers the following argument:

  • localName: The local name of the connection. The local name of a network connection is ”<READER_IP>:<PORT>”. An example for a Telnet connection is “10.82.80.156:23” with the default telnet port of 23. An example for a Network Client connection is “10.82.80.156:57350”. The local name for the serial connection is “COM1” or “COM USB”.
  • onConnect – Initialize state upon connection (a network connection established or protocol stack starts on serial connection). If the method is not implemented an error occurs. The method has one argument and a return value:
    • peerName – The peer name of the connection. The peer name for a network connection is ”<PEER_IP>:<PORT>”. An example peer name for a Telnet connection is “10.82.80.71:19772”, for a “Network Client” connection it is “10.82.80.71:1000”, where the host port is configured to 1000. The peer name for the serial connection is “COM1” or “COM USB”.
    • return – The boolean return value defines if the handler for this connection should be activated:
      • true: Enables customization of the communication protocol. Therefore, if you want to use your own protocol for communicating with the Dataman device, return true.
      • false: If you do not need the customized protocol for this peer, return false.
  • onDisconnect – Cleanup method called when closing the connection channel
  • onExpectedData – Method called if data matching the set properties has arrived. The method has one argument:
    • inputString – The received frame matched data excluding header and termination
    • return – Determines if the data should be removed from input buffer
      • true: clear the buffer.
      • false: keep the value in buffer.
  • onTimer – The timer value expired
  • onUnexpectedData – The recieved data is not matching the requirements. The boolean return value determines if the data should be removed from input. The method has one argument:
    • inputString – The received data
    • return – Determines if the data should be removed from input buffer
      • true: clear the buffer.
      • false: keep the value in buffer.
  • onError – An error occurred in the firmware and can be reported. The implementation of the method is mandatory. The method has one argument and no return value:
    • errorMsg – The error message for trigger overruns (“Trigger Overrun”), buffer overruns (“Buffer Overflow”) and general errors reported by the firmware.
  • onEncoder – Executed if a configured encoder distance is reached. The distance can be configured by the setEncoder method. The method has no arguments or return value.
  • send – Send data to channel, returns the number of send characters. The method must be called with one argument:
    • Data argument is a string
  • close – Actively terminates connection for the communication object (for example, close TCP/IP socket). On UART, this causes onConnect to be called right afterwards.
  • setTimer – Set the one-shot timer value when the onTimer will be executed. The timer can be re-initialized and aborted.
    • Timeout in seconds of type double, internal resolution is us (1e-6 sec). A zero value aborts a running timer. Active timer will be overwritten.
  • expectFramed – Tells the communication listener which data to pass on to the onExpectedData and onUnexpectedData methods. It is possible to change the match parameter at runtime. The following three arguments are required:
    • header of type string, can be empty (””)
    • terminator of type string, can be empty (””)
    • max length of type integer, specifies the maximum length of an input message to check for a match [required]
  • setEncoder – Units of the distance argument are millimetres. The encoder is configured in Setup Tool under System Settings -> Pulse Encoder. If encoder ticks should be used instead of distance set the value of the parameter “Resolution (mm)” to 1.
    • distance (double) – The encoder distance in which the onEncoder method will be called.

The methods must be implemented in the public section of the object.

Examples

API usage of custom communication protocol object

This example below demonstrates the API usage of the custom communication protocol object. The example implements custom commands read from the connection. The commands are framed by a ”#” header and terminated by ”;\r” (for example, a serial PuTTY connection). A timer periodically sends timer messages. Use the custom stop command to stop them. You can change the timer handler once by the switch command.

function CommHandler()

{

// private properties and methods:

var num_trigger = 0;
var num_send;

// public properties and methods:
function onTimeout()
{

num_send = this.send(my_name + ': timer callback\r\n');
this.setTimer(1.0);

}

function onTimeout2()
{

today = new Date();

var msg = today.getSeconds() * 1000 + today.getMilliseconds();

num_send = this.send(my_name + ': time is: ' + msg + '\r\n');

dmccCommand("TRIGGER", true);

this.setTimer(1.0);

}

function replace_crlf(input_str)

{

return input_str.replace(/\r/g, '\\r').replace(/\n/g, '\\n');

}

return {

onConnect: function (peerName)

{

my_name = peerName;

// we may ignore the connection

if(my_name == "COM1")

return false;

num_send = this.send(my_name + ": connected\r\n");

 

this.expectFramed("#", ";\r\n", 64);

return true;

},

onDisconnect: function ()

{

},

onExpectedData: function (inputString) {

var msg = 'ok';

this.expectFramed("#", ";\r\n", 64);

if (inputString == "name")

{

msg = dmccGet("DEVICE.NAME");

msg = msg.response;

}

else if(inputString == "trigger")

{

this.send(my_name + ': issue a trigger...\r\n');
dmccCommand("TRIGGER", true);

msg = 'done';

}

else if (inputString == "close")

{

this.close();

}

else if (inputString == "stop")

{

this.setTimer(0.0);

}

else if (inputString == "start")

{

this.setTimer(10.0);

}

else if (inputString == "switch")

{

this.onTimer = onTimeout2;

}

else if (inputString == "time")

{

today = new Date();

msg = today.getSeconds() * 1000 + today.getMilliseconds();

}

else

{

msg = "unknown command: " + replace_crlf(inputString);

}

num_send = this.send(my_name + ': ' + msg + "\r\n");

return inputString.length;

},

onUnexpectedData: function (inputString) {

this.expectFramed("#", ";\r\n", 128);

msg = replace_crlf(inputString);

num_send = this.send(my_name + ': ' + msg + "?\r\n");

return true;

},

onTimer: onTimeout

};

}

Generic use case: Heartbeat

Send out a periodic heartbeat message if reader is idle.

// Data Formatting:

 

var comm_handler = new Array(0);

 

// Converts read data to all upper case. Single code only.

function onResult (decodeResults, readerProperties, output) {

if (decodeResults[0].decoded) {

output.content = decodeResults[0].content+'\r\n';

for (var i = 0; i < comm_handler.length; i++)

{

comm_handler[i].resetHeartBeat();

}

}

}

 

// Communication:

 

// Heart beat example without disturbing the DMCC communication function CommHandler() {

var beat_timer = 10.0; // beat timer in sec

var peer_name;

return {

onConnect: function (peerName)

{

peer_name = peerName;

this.resetHeartBeat(); // initial timer

this.expectFramed("\0", "\0", 128); // some pattern unlikely to happen

comm_handler.push(this); // register the handler for results

// enable the handler for this connection:

return true;

},

onDisconnect: function ()

{

var index = comm_handler.indexOf(this)

comm_handler.splice(index, 1);

},

onError: function (errorMsg)

{

},

onExpectedData: function (inputString) {

return false;

},

onUnexpectedData: function (inputString) {

return false;

},

onTimer: function () {

today = new Date();

var msg = today.getSeconds() * 1000 + today.getMilliseconds();

num_send = this.send(peer_name + ': time is: ' + msg + '\r\n');

this.resetHeartBeat(); // schedule next timer event [sec]

},

resetHeartBeat: function () {

this.setTimer(beat_timer); // schedule next timer event [sec]

}

};

}

Generic use case: Real time timestamp

Implements a custom DMCC command to set the real time (send current time in seconds starting Jan 1 1970, as output by date +”%s” command). Prepend output with real time timestamp.

// communication script

var time_offset=0;

 

function CommHandler()

{

var peer_name;

 

return {

onConnect: function (peerName)

{

peer_name = peerName;

this.expectFramed("||;1>SET TIME.NOW ", "\r\n", 128); // some pattern unlikely to happen

// enable the handler for this connection:

return true;

},

onDisconnect: function ()

{

},

onError: function (errorMsg)

{

},

onExpectedData: function (inputString) {

realTime = parseInt(inputString)*1000;

localTime = (new Date()).getTime();

time_offset = realTime - localTime;

this.send("||[0]\r\n");

return true;

},

onUnexpectedData: function (inputString) {

return false;

},

onTimer: function () {

}

};

}

 

// data formatting script

function onResult (decodeResults, readerProperties, output)

{

var d = new Date();

var real = new Date(time_offset+d.getTime());

output.content = real.toString() + " " + decodeResults[0].content + "\r\n";

}

Customer Protocols implemented in various CR releases

Communication with cmf400 Profibus gateway

var CMF400_PROTOCOL_STATUS =

{

RUNNING: {value: 0, name: "Running"},

SYNCRONIZING: {value: 1, name: "Sync"},

CONFIGURING: {value: 2, name: "Config"},

STOPPED: {value: 3, name: "Stop"}

};

// make the enum non-modifyable

Object.freeze(CMF400_PROTOCOL_STATUS);

 

var cmf400_protocol_stx = '\x02'; // header

var cmf400_protocol_etx = '\x03'; // termination

 

// VT Parameter to be converted into script configuration constant values:

// "/Communication/Interfaces/COM1/Protocol")

var vt_param_comif_com1_protocol = 1;

// "/Communication/Protocols/CMF400/Profibus node number"), 3);

var vt_param_profibus_node_number = 1;

// "/Communication/Protocols/CMF400/Profibus mode"), 3);*/

var vt_param_profibus_mode = 1;

 

// TODO: how to configure parameter, where to store them with a out of stock firmware?

var cmf400_protocol_profibus_node_number = 1;

 

var cmf400_protocol_profibus_mode = 1;

 

var cmf400_protocol_test_diagnostic_enabled = 0;

 

var cmf400_protocol_test_diagnostic = 'TEST';

 

// Protocol strings

var cmf400_gateway_init = '+Gateway-Init+';

var cmf400_gateway_ident_ok = '+GW SOK TSICDPS';

var cmf400_gateway_ident_no = '+GW SNO TSICDPS';

var cmf400_gateway_run = '+GW-RUN+';

var cmf400_gateway_error = '+GW-ERR';

 

// Formatting helper function

function zero_prefix(num, size)

{

var s = "000000000" + num;

return s.substr(s.length - size);

}

 

function CommHandler()

{

// The current protocol state

var cmf400_status = CMF400_PROTOCOL_STATUS.STOPPED;

 

function _configTimedOut()

{

if (cmf400_status == CMF400_PROTOCOL_STATUS_CONFIGURING)

{

cmf400_status = CMF400_PROTOCOL_STATUS_STOPPED;

this.setTimer(30.0);

onTimer = _onSync;

}

}

function _onSync()

{

if (cmf400_status == CMF400_PROTOCOL_STATUS.SYNCRONIZING)

{

this.send(cmf400_protocol_stx + cmf400_gateway_init + cmf400_protocol_etx);

this.setTimer(1.0);

onTimer = _onSync;

}

}

function _onTimer()

{

if (cmf400_status == CMF400_PROTOCOL_STATUS.STOPPED)

{

cmf400_status = CMF400_PROTOCOL_STATUS.SYNCRONIZING;

return;

}

}

return {

onConnect: function (peerName)

{

expectFramed("", cmf400_protocol_etx, 510); // is 510 an arbitrary limit?

cmf400_status = CMF400_PROTOCOL_STATUS.SYNCRONIZING;

this.onTimer = _onSync;

this.setTimer(0.0001);

return true;

},

onDisconnect: function ()

{

},

onExpectedData: function (inputData)

{

data = inputData.slice(1,inputData.length-1);

if (cmf400_status == CMF400_PROTOCOL_STATUS.SYNCRONIZING)

{

if (data == cmf400_gateway_ident_ok || data == cmf400_gateway_ident_no)

{

cmf400_status = CMF400_PROTOCOL_STATUS.CONFIGURING;

var msg = cmf400_protocol_stx;

 

msg += "+GW S000 H000";

msg += " X" + zero_prefix(vt_param_comif_com1_protocol, 3);

msg += " N" + zero_prefix(vt_param_profibus_node_number, 3);

msg += " M" + zero_prefix(vt_param_profibus_mode, 3);

msg += cmf400_protocol_etx;

this.send(msg);

this.onTimer = _configTimedOut;

this.setTimer(10.0);

}

}

if (data == cmf400_gateway_error)

{

cmf400_status = CMF400_PROTOCOL_STATUS.STOPPED;

this.setTimer(30.0);

this.onTimer = _onTimer;

}

else if (data == cmf400_gateway_run) // missing check for status, e.g. CMF400_PROTOCOL_STATUS.CONFIGURING?

{

cmf400_status = CMF400_PROTOCOL_STATUS.RUN;

this.setTimer(0);

this.onTimer = _onTimer;

}

return true;

},

onUnexpectedData: function (inputData)

{

// ignore all unexpected data

return true;

},

onTimer: _onSync

};

}

 

function onResult (decodeResults, readerProperties, output)

{

//assuming single code

var content = cmf400_protocol_stx+decodeResults[0].content+cmf400_protocol_etx;

output.content = content;

}

Pass weight string input along with decode string

// the constructor:

 

var input_string = "";

 

function CommHandler()

{

// private properties and methods:

 

var num_trigger = 0;

var my_name;

var num_send = 99;

 

function privFunc ()

{

}

 

// public properties and methods:

 

return {

onConnect: function (peerName)

{

my_name = peerName;

num_send = this.send(my_name + ": connected\r\n");

num_send = this.expectFramed("\x02", "\x03", 128);

return true;

},

onDisconnect: function ()

{

},

onExpectedData: function (inputString) {

input_string = inputString;

return true;

},

onUnexpectedData: function (inputString) {

return true;

}

};

}

 

//Empty data formatting entry point function

function onResult (decodeResults, readerProperties, output)

{

if (decodeResults[0].decoded)

{

output.content = input_string + decodeResults[0].content + "\r\n"

input_string = "";

}

}

FMPCS protocol

// This must be in the global scope, otherwise, it is undefined

var bConnected = false;

 

dmccSet('TRIGGER.TYPE', 0);

dmccSet('SYMBOL.4STATE-IMB', 1);

dmccSet('SYMBOL.DATAMATRIX', 1);

dmccSet('SYMBOL.I2O5', 1);

dmccSet('SYMBOL.PDF417', 1);

dmccSet('SYMBOL.POSTNET', 1);

 

function CommHandler()

{

var tray = "0000";

var speed = 0;

 

var package_id_expr = new RegExp("I([0-9]{9})");

var package_idtray_expr = new RegExp('^I([0-9]{9}),T([0-9]{4})');

var config_msg_expr = new RegExp('^CS([0-9]{3}),M([ab]),L([0-9]{4})$');

 

var ErrorToId = {

'Buffer Overflow': 101,

'Trigger Overrun': 102

};

 

return {

onConnect: function (peerName)

{

if(peerName == "COM1" || bConnected)

return false;

this.expectFramed("", "\r", 128);

this.send(dmccGet('DEVICE.FIRMWARE-VER').response + ',"Cognex ' + dmccGet('DEVICE.TYPE').response + '"\r\n');

this.send('Ha,"DataMan READY"\r\n');

bConnected = true;

return true; // activate this connection

},

onError: function (msg) // TODO: this is new!

{

var errno = ErrorToId[msg];

if (!errno)

errno = 100;

this.send('E' + errno + ',"' + msg + '"\r\n');

},

// We delay sending the result until trigger off to be sure that the package id is received.

setResult: function (decodeResults) {

storedDecodeResults = decodeResults;

},

onDisconnect: function ()

{

bConnected = false;

},

onExpectedData: function (input)

{

var input = input.replace(/\n/g, '');

switch(input.charAt(0).toUpperCase())

case 'B':

dmccCommand("TRIGGER", true);

break;

case 'E':

dmccCommand("TRIGGER", false);

break;

case 'I':

var match = package_idtray_expr.exec(input);

if(!match)

match = package_id_expr.exec(input);

packageID = match[1];

if(match[2])

tray = match[2];

else

tray = "0000";

break;

case 'C':

var match = config_msg_expr.exec(input);

if (match.length == 4)

{

speed = parseInt(match[1], 10);

mode = match[2];

lengthLimit = parseInt(match[3], 10);

}

break;

case 'P':

this.send('Q\r\n');

break;

case 'Q':

// pong response, not used

break;

}

return true;

},

onUnexpectedData: function (input) {

return true;

}

};

}

The data formatting formats the result based on global variables set by the communication handler:

var packageID = "000000000"; // reset the package id

var mode = 'a';

var lengthLimit = 9999;

 

function getFixedPsocId(id_)

{

var id = id_;

switch (id.charAt(1))

{

case 'd':

id = "[D0";

break;

case 'X':

switch (id.charAt(2))

{

 

case '0':

case '1':

id = "[P0";

break;

case '2':

case '3':

id = "[L0";

break;

case '5':

case '6':

case '7':

case '8':

case '9':

case 'A':

id = "[O0";

break;

}

break;

}

return id;

}

function onResult (decodeResults, readerProperties, output)

{

var my_decode_results = new Array();

 

for(var i = 0; i < decodeResults.length; i++)

{

if(!decodeResults[i].decoded)

continue;

switch (decodeResults[i].symbology.name)

{

case 'Interleaved 2 of 5':

// b=throw away 6 digit I2of5 ending in 9

if ((mode == 'b' && decodeResults[i].content.length == 6 && decodeResults[i].content.charAt(5) == '9'))

continue;

case 'Data Matrix':

if (decodeResults[i].content.length > lengthLimit)

continue;

case 'PDF417':

if (decodeResults[i].content.length > lengthLimit)

continue;

default:

my_decode_results.push(decodeResults[i]);

}

}

var msg = 'D' + packageID + ',S,W,V';

if (my_decode_results.length == 0)

{

msg += ',?';

output.content = "no result";

}

else

{

for(var i = 0; i < my_decode_results.length; i++)

{

msg += ',' + getFixedPsocId(decodeResults[i].symbology.id);

switch (my_decode_results[i].symbology.name)

{

case 'Data Matrix':

case 'PDF417':

msg += encode_base64(my_decode_results[i].content);

break;

case 'POSTNET':

case 'PLANET':

case 'XYZ OneCode':

case 'Interleaved 2 of 5':

default:

msg += my_decode_results[i].content;

}

}

}

packageID = "000000000"; // reset the package id

output.Telnet = output.Serial = msg + '\r\n';

}

Input match string, output from script (30x)

function CommHandler()

{

return {

onConnect: function (peerName)

{

this.expectFramed('\x02', '\x03', 256);

return true;

},

onDisconnect: function ()

{

},

onExpectedData: function (inputString) {

if (inputString.length >= 11)

{

var new_match_string = inputString.substr(11, inputString.length);

for (var i = 1; i <= 3; i++) {

dmccSet("DVALID.PROG-TARG", i);

dmccSet("DVALID.MATCH-STRING", new_match_string);

}

// The following DMCC command resets all statistic values

// the CR reset only a view of them

dmccCommand("STATISTICS.RESET");

}

this.send("DEBUG: "+inputString + "\r\n");

return true;

},

onUnexpectedData: function (inputString) {

return true;

},

onTimer: function (inputString) {

}

};

}

Data formatting delegates output to communication handler objects

var comm_handler = new Array(0);

 

// Converts read data to all upper case. Single code only.

function onResult (decodeResults, readerProperties, output)

{

output.content = '';

output.SetupTool = decodeResults[0].content;

if (decodeResults[0].decoded) {

for (var i = 0; i < comm_handler.length; i++)

{

comm_handler[i].sendResultTelegram(decodeResults);

}

}

}

 

// Parameter:

var system_id = '\x43'; // the system ID

var heartbeat_time_s = 5.0; // heartbeat timer in sec [0-50] (0 is disabled)

var append_crlf = true; // wether to

 

function CommHandler()

{

function getChecksum(data)

{

var sum = 0;

for(var i = 0; i < data.length; i++)

sum += data.charCodeAt(i);

return 0x7F - (sum % 0x7f);

}

var TelegramState = {

WAIT4CONTENT: {value: 0, name: "Wait For Content"},

CHECKSUM: {value: 1, name: "Header Received"}

};

 

var errorCodes = {

undef_index: 0x31,

multi_index: 0x32,

index_in_use: 0x33,

telegram_error: 0x34,

trigger_overrun: 0x40,

buffer_overflow: 0x41,

};

 

var filler = '#';

var separator = ',';

 

var telegram_types = {

heartbeat: {type: 'F', content: system_id+'\xf7'},

init_resp: {type: 'J', content: system_id},

};

 

// initialization: J

// index: S

 

var telegram;

var status;

var index;

var all_index = new Array();

 

return {

 

sendResultTelegram: function (decodeResults)

{

var data = system_id;

var length = 0;

 

if (!index)

{

this.sendErrorTelegram(errorCodes.undef_index);

index = '9999';

}

data += index;

for (var i = 0; i < decodeResults.length; i++) {

length = decodeResults[i].content.length;

data += String.fromCharCode(length / 256, length % 256);

}

data += separator + filler;

length = 0;

for (var i = 0; i < decodeResults.length; i++) {

length += decodeResults[i].content.length;

data += decodeResults[i].content;

}

if (length & 0x1)

data += filler;

data += String.fromCharCode(getChecksum(data));

this.sendTelegram({type: system_id, content: data});

 

index = null; // invalidate the used index

},

sendErrorTelegram: function (errcode)

{

var errtel = {type: 'F', content: system_id+String.fromCharCode(errcode)}

 

this.sendTelegram(errtel);

},

sendTelegram: function (telegram)

{

var data = telegram.type + telegram.content;

data = '\x02'+data+String.fromCharCode(getChecksum(data))+'\03';

this.send(data);

if (append_crlf)

this.send('\r\n');

},

checkTelegram: function(data, checksum)

{

var exp_checksum = getChecksum(data);

if (checksum != exp_checksum) {

this.sendErrorTelegram(errorCodes.telegram_error);

} else {

switch (data[0])

{

case 'I':

this.sendTelegram(telegram_types.init_resp);

this.setTimer(0.0); // disable the heartbeat timer

all_index = new Array(0);

break;

case 'S':

if (index) {

this.sendErrorTelegram(errorCodes.multi_index);

break;

}

index = data.substr(1, 4);

if (all_index.indexOf(index) >= 0)

this.sendErrorTelegram(errorCodes.index_in_use);

else

all_index.push(index);

break;

default:

break;

}

}

},

onConnect: function (peerName)

{

status = TelegramState.WAIT4CONTENT;

this.expectFramed('\x02', '\x03', 203);

this.setTimer(heartbeat_time_s);

index = null;

comm_handler.push(this);

all_index = new Array();

return true;

},

onDisconnect: function ()

{

var index = comm_handler.indexOf(this)

comm_handler.splice(index,1);

},

onExpectedData: function (inputString) {

switch (status)

{

case TelegramState.WAIT4CONTENT:

this.expectFramed('', '', 1); // actually, disable framing

telegram = inputString;

status = TelegramState.CHECKSUM;

break;

case TelegramState.CHECKSUM:

this.expectFramed('\x02', '\x03', 203); // enable framing for the next telegram

this.checkTelegram(telegram, inputString.charCodeAt(0));

status = TelegramState.WAIT4CONTENT;

break;

default:

throw("unknown state");

}

return true;

},

onUnexpectedData: function (inputString) {

this.expectFramed('\x02', '\x03', 203); // enable framing for the next telegram

status = TelegramState.WAIT4CONTENT;

return true;

},

onTimer: function (inputString) {

this.sendTelegram(telegram_types.heartbeat);

this.setTimer(heartbeat_time_s);

}

};

}

Event Callback

The callback mechanism allows to register handler for trigger and input events. Handler for these events can be registered by the registerHandler method:

callback_handle registerHandler(eventid, callback, ...)

The registerHandler function requires the following arguments:

  • eventid – identifier for the event type to register for
  • callback – function object to execute on event

Available events identifier are defined in a constant object named “Callback”. Optional arguments can be used to configure the event, e.g. to filter the sensitivity.

A handle is returned that must be used to de-register the callback. To de-register the handler use the deregisterHandler function:

deregisterHandler(callback_handle)
  • callback_handle – handle returned by the registerHandler method.

It is possible to register the callback handler within the global scope, e.g. to be used in data formatting.

Event Types

Current available events that can be registered are “onInput” and “onTrigger” events.

onInput event: It calls the callback function on input signal and button changes. The optional third argument allows to set filter for certain inputs. The object “ConstInput” defines masks for inputs:

  • Input0:
  • Input1:
  • Input2:
  • Input3:
  • Input4:
  • Input5:
  • Input6:
  • InputAll
  • BnTrig
  • BnTune

The input mask can be combined. The input values are sampled with an accuracy of 1 ms. The callback function for the onInput event has one argument for the new state of the input.

onTrigger event: It executes the callback function on trigger start and trigger end events. The callback function for the onTrigger event has two arguments: The first argument is the trigger object, the second argument the boolean state of the trigger, true for a trigger start and false for a trigger end.

Examples

The example defines three event handler:

  • onInput0 – reacting on input0 signal and the switch button
  • onInput1 – reacting on input1 signal
  • onTrigger – reacting on trigger events

function CommHandler()

{

return {

onConnect: function (peerName)

{

this.peer = peerName;

this.input1 = registerHandler(Callback.onInput, this.onInput0.bind(this), ConstInput.Input0|ConstInput.BnTrig);

this.input2 = registerHandler(Callback.onInput, this.onInput1.bind(this), ConstInput.Input1);

this.ontrigger = registerHandler(Callback.onTrigger, this.onTrigger.bind(this));

return true;

},

onDisconnect: function ()

{

deregisterHandler(this.input1);

deregisterHandler(this.input2);

deregisterHandler(this.ontrigger);

},

onTrigger: function (trigger, state) {

if (state)

this.send("call onTrigger: started trigger with index " + trigger.index + "\r\n");

 

else

this.send("call onTrigger: end trigger with index " + trigger.index + "\r\n");

 

},

onInput0: function (inputs) {

this.send("call onInput0 for '" + this.peer + ", inputs=" + inputs + "\r\n");

},

onInput1: function (inputs) {

this.send("call onInput1 for '" + this.peer + ", inputs=" + inputs + "\r\n");

}

};

}

With the following event sequence: input1 on, input0 on, input0 off, input1 off, software trigger, switch on, switch off, we get the following output on the terminal:

call onInput1 for 'COM1, inputs=2

call onTrigger: start trigger with index 9

call onInput0 for 'COM1, inputs=1

call onTrigger: end trigger with index 9

call onInput0 for 'COM1, inputs=0

NO-READ

call onInput1 for 'COM1, inputs=0

call onTrigger: start trigger with index 10

NO-READ

call onTrigger: end trigger with index 10

call onInput0 for 'COM1, inputs=4096

call onTrigger: start trigger with index 11

call onInput0 for 'COM1, inputs=0

call onTrigger: end trigger with index 11

NO-READ

The following example registers a handler on Input1 events and stores the state in a global variable. The state of the input is output by the data formatting.

var ginputs = false;

 

registerHandler(Callback.onInput, onInput, ConstInput.Input1);

 

// Default script for data formatting

function onResult (decodeResults, readerProperties, output)

{

output.content = "Input: "+ginputs+" \r\n";

}

 

function onInput(inputs)

{

ginputs = (inputs & ConstInput.Input1) ? true : false;

}