Skip to Main Content
Cognex Support Hub
Logo

Script - Application - TCP/IP Communication Between Readers - Simulating Master-Slave

Simple example how to communicate two systems via TCP/IP.

16.04.2025

Details

DESCRIPTION

How does it work?

Between two (or multiple) readers, a connection is established via TCP/IP, where the “Master” reader sends triggers across the network to connected Slave readers. After receiving a trigger, the Slave reader sends data back to the Master. The Master then sends the combined results to a host system.

Purpose

This script is useful for exchanging data between readers when the “Master-Slave” feature isn’t available or if you are using unsupported devices. It can also collect data from third-party peripherals. The script can be expanded to support multiple Slave readers, but doing so increases the complexity and may require modifications. Note that data synchronization is not always perfect, especially in quick-paced applications where data might be lost.
 

REQUIREMENTS

Hardware

This script was designed to work with both fixed-mount and handheld readers. It was tested on the DataMan 470 and DataMan 260 series.

Hardware List:

  • Two DataMan Readers
  • Network Switch
  • Test Setup
  • Placeholder
    Picture 1: Test setup for exchanging data between readers.


 

HOW TO USE IT?

Setting up Network Client on Slave Reader

To set up a network client on the Slave reader, go to the Communications settings and specify the host address and port, as shown in Picture 2.

Placeholder
Picture 2: This image shows the Network Client settings on the Slave reader. You must configure the host address and port where the Master reader is located.

Uploading Scripts to Reader

Make sure scripting is enabled in the Format Data tab. Both the data formatting and communication scripts need to be uploaded.

Placeholder
Picture 3: Uploading scripts.
Placeholder
Picture 4: Uploading scripts to the respective tabs.

This image demonstrates how to upload the scripts to the Data Formatting and Communication tabs on the reader’s interface. Ensure both scripts are uploaded correctly for the system to function as intended.
 

SAMPLE SCRIPT

Data Formatting Script – Master

"use strict";

/*Constants declaration */

const TIME_OUT = 0.3;                           //Time out for slave response

const NOREAD = "No Read";                        //No read declaration

const DELIM = ";";                              //Delimiter declaration

const TRIG_MSG_ON ='||>TRIGGER ON\r\n';                   //Trigger On message sent to Slave

const TRIG_MSG_OFF ='||>TRIGGER OFF\r\n';        //Trigger Off message sent to Slave

/*Variables declaration */

let masterCode = '';                            //Master code declaration

let slaveString1 ='';                           //Slave code declaration

function onResult (decodeResults, readerProperties, output){

 masterCode = '';                              //Clearing Master Code value

//After receiving a trigger off message from the master, the system is waiting up to the TIME_OUT

//to receive data from the slave

 if (comHandler !== null) {                    //Check if serial handler is enabled

   comHandler.setTimer(TIME_OUT);               //Lunch timer with defined time value

 }      

 if (decodeResults[0].decoded){

   masterCode = decodeResults[0].content;       //Add decoded code to variable

 }

 output.content = "";                          //Sending empty message on standard outputs

}

 

Communication Script – Master

"use strict";

// Constants declaration

const SLAVE1_IP = '192.168.1.203';     // IP address of Slave 1

const SLAVE_PORT = '23';                        // Slaves port

const STX = '\x02';

const ETX = '\x03';

const HEADER = STX;                     //Input String Header

const FOOTER = ETX;                    //Input String Header

 

const HOST_IP = '192.168.1.130';       //Declaration of Host IP

const HOST_PORT = '23';

const LOG = true;                      // Logging enabled

//Handlers declaration

let slaveHandler1 = null;              //Slave 1 handler

let comHandler = null;                 //Com handler - used for timer

let hostHandler = null;                //Declaring Host handler (PC)

 

let temp = '';                         //Used for controlling received data by Master from Host

function CommHandler(localName){

 return {

 

//In onConnect part we are declaring 3 handlers:host(ETH), Slave (ETH) and timer(COM)

 onConnect: function (peerName){

   let peerIP = peerName.split(':')[0];         //Declaring connected peer IP (Slave IP)

   let peerPort = peerName.split(':')[1];       //Declaring connected peer port (Slave port)

   let localPort = localName.split(':')[1];     //Declaring connected local port (Host port)

   const sourceIP = peerName.substr(0, peerName.lastIndexOf(':'))  //Declaring connected system (Host IP)

         if (sourceIP === HOST_IP && localPort ===HOST_PORT) {     //Opening Host handler, If IP is the defined host IP address and specified port

     hostHandler = this;

     hostHandler.expectFramed(HEADER, FOOTER, 64); //Declaration of expected frame <STX MSG ETX>

     logMsg('Ethernet Handler Connected!');

     return true;

   } else if (peerIP === SLAVE1_IP && peerPort === SLAVE_PORT) { //Opening Slave handler

       slaveHandler1 = this;

       slaveHandler1.expectFramed(HEADER, FOOTER, 64);//Declaration of expected frame <STX MSG ETX>

       logMsg('SLAVE1 Connected');

       return true;

   }                      

   if (peerIP.substr(0, 3) === 'COM') { //Opening COM handler

     comHandler = this;

     logMsg('COM Connected');

     return true;

   }

 return false;

 },

                 

 onDisconnect: function (){},

 onError: function (errorMsg){},

 onExpectedData: function (inputString) {       //Note: unused handler should be commented.

   if (this === slaveHandler1) {               //Receiving data from Slave 1

     logMsg('Slave Handler 1:' + inputString);

     slaveString1=inputString;

     slaveString1='';

   }

   if (this === hostHandler) {                 //Receiving data from Host

     temp = inputString;

     logMsg('Host Handler:' + inputString);

     if(temp == "START"){                      //When START message is received Master is sending trigger command to Slave

       slaveString1='';                        //and starting to trigger itself

       dmccCommand('TRIGGER', 'ON');

       slaveHandler1.send(TRIG_MSG_ON);

             temp='';

     }

     if(temp == "STOP"){                       //When STOP message is received Master is sending stop command to Slave

       dmccCommand('TRIGGER', 'OFF'); //and turning off itself

       slaveHandler1.send(TRIG_MSG_OFF);

       temp='';

     }

   }

 return true;

 },

 

 onUnexpectedData: function (inputString) {

   if (this === comHandler) {

     logMsg("WRONG MSG: "+inputString);         //Logging data when it's not correct according to the declared frame

   }

   return true;

 },

 onTimer: function () {                      

   if(comHandler === this){

     logMsg ("COMHandler on");

     slaveHandler1.send(TRIG_MSG_OFF);                             //Turning triggering off on Slave 1

     hostHandler.send(masterCode+DELIM+slaveString1);    //Sending combined results to Host

     slaveString1='';                                    //Clearing Slave 1 data

     masterCode='';                                      //Clearing Master decode codes    

   }

 },

 onEncoder: function () {}

 };

}

 

function logMsg(msg) {

 if (LOG) {

   console.log(msg);

 }

}

 

Data Formatting Script – Slave

"use strict";

const STX = '\x02';

const ETX = '\x03';

 

let outputCode = '';

let outputString = '';

dmccSet("LIGHT.DIRECT", "OFF OFF OFF OFF");

function onResult(decodeResults, readerProperties, output) {

 outputCode = '';

 outputString = '';

 

 if (decodeResults[0].decoded) {

   outputCode = decodeResults[0].content;

 }

 if (outputCode!='') {

   outputString = STX + outputCode + ETX;

 }

 else{

   outputString = STX + '' + ETX;

 }

 if (primaryHandler !== null) {

   primaryHandler.send(outputString);

 }

 output.content = '';

 output.SetupTool = 'Output String: ' + outputString;

}

 

Communication Script – Slave

"use strict";

const LOG = true;

 

const PRIMARY_IP = dmccGet('NETWORK-CLIENT.HOST-ADDRESS').response;

const PRIMARY_PORT = dmccGet('NETWORK-CLIENT.HOST-PORT').response;

let primaryHandler = null;

 

function CommHandler (localName) {

 return {

   onConnect: function (peerName) {

     logMsg('New Connection: ' + localName + ' ' + peerName);

     const sourceIP = peerName.substr(0, peerName.lastIndexOf(':'));

     const peerPort = peerName.substr(peerName.lastIndexOf(':') + 1);

     if (sourceIP === PRIMARY_IP && peerPort === PRIMARY_PORT) {

       logMsg('Primary handler connected');

       primaryHandler = this;

       return true;

     }

     return false;

   },

   onDisconnect: function () {

     if (this === primaryHandler) {

       primaryHandler = null;

       console.log('Primary handler disconnected');

     }

   },

   onError: function (errorMsg) {

   },

   onExpectedData: function () {

   },

   onUnexpectedData: function (inputString) {

   },

   onTimer: function () {

   },

   onEncoder: function () {

   }

 };

}

 

function logMsg (msg) {

 if (LOG) {

   console.log(msg);

 }

}

 

CONSIDERATIONS FOR DATA SYNCHRONIZATION

While using this system, data synchronization is essential but may not always be perfect. Consider these points:

  1. Time Delays:
    The Master reader sends triggers to the Slave, which may introduce a delay due to network latency. This could result in delayed data responses. The TIME_OUT parameter is used to avoid indefinite waiting, but it may need adjustment based on network speed.
  2. Data Loss:
    In fast-paced operations, data loss can occur if the Slave doesn’t respond in time. Adjusting the TIME_OUT value or optimizing data handling can help reduce the risk of losing important data.
  3. Multiple Slaves:
    When connecting multiple Slave readers, synchronization becomes more complex. The Master may not always receive data in the correct order, especially if Slaves respond at different times. Consider increasing the time buffer between triggers to allow each Slave sufficient time to respond.
  4. Data Handling:
    The Master must handle data from multiple Slaves and format it correctly before sending it to the host. Proper data validation and error handling are necessary to avoid sending incomplete or corrupted data.
  5. Buffer Overflows:
    If too many triggers are sent rapidly, buffer overflows could occur, preventing the Master or Slave from processing data correctly. Increasing time intervals or using an intermediate buffer to manage data can help mitigate this issue.

 

Conclusion

By following these steps and addressing synchronization concerns, you can ensure smooth communication between the Master and Slave readers. Proper configuration, timing adjustments, and data handling will lead to reliable results and seamless data transfer to the host system.