Passa al contenuto principale

ModbusGateway, Modbus protocol gateway

Questo blocco funzione da eseguire in task Back, opera come gateway tra due connessioni Modbus. Allo stream IFile può collegarsi un sistema master che esegue richieste Modbus con il protocollo definito in IType. Le richieste ricevute saranno riportate in uscita sullo stream OFile da collegarsi ai sistemi slaves, convertite con il tipo di protocollo definito in OType.

In Timeout occorre definire il tempo massimo di attesa delle risposte alle richieste Modbus ricevute in ingresso sullo stream IFile ed inviate in uscita sullo stream OFile. L'uscita Packets ritorna il conteggio dei pacchetti Modbus correttamente gestiti. In Exceptions è ritornato il conteggio delle eventuali risposte di eccezione ricevute dal sistema slave. In caso di errore viene attivata per un loop l'uscita Fault.

Modifica pacchetti da programma​

Per abilitare la modifica dei pacchetti Modbus da programma occorre definire le variabili ITrigger ed OTrigger. Per abilitare questa funzione occorre richiedere il codice di protezione, vedi protezione funzioni e blocchi funzione. E’ comunque possibile testarne il funzionamento in modo test per 30 Min.

Per modificare i pacchetti Modbus ricevuti come comando dal server in ITrigger è possibile definire l'indirizzo di una variabile trigger (BOOL) che sarà attivata alla ricezione del pacchetto. Il programma potrà modificare il pacchetto in DFrame, resettando la variabile trigger il pacchetto sarà inviato in uscita su OFile.

Per modificare i pacchetti Modbus ricevuti come risposta dallo slave in OTrigger è possibile definire l'indirizzo di una variabile trigger (BOOL) che sarà attivata alla ricezione del pacchetto. Il programma potrà modificare il pacchetto in DFrame, resettando la variabile trigger il pacchetto sarà inviato in uscita su IFile.

Upgrade list

ModbusGateway_v1​

Modificato parametri IType ed OType ora sono di tipo MODBUS_PROTOCOL. Il parametro Timeout ora è di tipo TIME.

ModbusGateway_v2​

Aggiunto parametri ILock ed OLock per la gestione di connessioni multiple in ingresso. Il parametro PMTime ora è di tipo TIME.

Approfondimenti

In questo topic un esempio di utilizzo del FB per sostituire un gateway commerciale.

Modbus gateway programmabile

Per connettersi a dispositivi seriali Modbus RTU via ethernet occorre utilizzare un Gateway Modbus TCP/RTU, esistono sul mercato prodotti stand-alone, come quelli da noi distribuiti nella gamma dei convertitori Ethernet-Seriale. Vediamo le possibilità offerte da questo FB modificando da programma i pacchetti Modbus.

  • Modificare l'indirizzo dei registri in richiesta dal sistema master verso il sistema slave.

  • Modificare l'indirizzo di nodo in richiesta dal sistema master verso il sistema slave.

  • Indirizzare la richiesta del sistema master su diversi streams di comunicazione e diversi tipi di protocollo in base all'indirizzo di nodo.

Descrizione​

Immagine FB ModbusGateway_v2

ParametroTipoDescrizione
EnableBOOLComando di abilitazione blocco funzione.
ILockBOOLComando di blocco conversione dati ricevuti da IFile. Si utilizza in caso di gestione connessioni multiple in ingresso.
SpyOnBOOLSe attivo permette di spiare il funzionamento della FB (Vedi articolo).
ITrigger@BOOLDefinire indirizzo della variabile trigger che verrà attivata da FB su ricezione in DFrame pacchetto da IFile (Solo se si desidera modificare il pacchetto Modbus ricevuto dal master). Definire eNULL se non utilizzata.
OTrigger@BOOLDefinire indirizzo della variabile trigger che verrà attivata da FB su ricezione in DFrame pacchetto da OFile (Solo se si desidera modificare il pacchetto Modbus ricevuto dallo slave). Definire eNULL se non utilizzata.
ADLgtUINTDefinizione lunghezza frame di risposta da inviare al master su stream IFile. (Utilizzare solo se si modificano i pacchetti Modbus ricevuti dal master).
ITypeMODBUS_PROTOCOLTipo di protocollo modbus gestito da stream IFile (Definizione).
IFileeFILEPStream di comunicazione con sistema master.
OTypeMODBUS_PROTOCOLTipo di protocollo modbus gestito da stream OFile (Definizione).
OFileeFILEPStream di comunicazione con sistema slave.
TimeoutTIMETempo massimo gestione pacchetto.
FaultBOOLAttivo per un loop se errore esecuzione comando.
OLockBOOLComando di attivazione blocco conversione dati ricevuti da IFile su altre istanze FB. Si utilizza in caso di gestione connessioni multiple in ingresso.
CDLgtUINTRitorna la lunghezza del pacchetto Modbus ricevuto dallo stream IFile.
DFramePVOIDIndirizzo buffer con pacchetto Modbus.
PacketsUDINTContatore pacchetti Modbus correttamente gestiti.
PMTimeTIMETempo di gestione pacchetto da ricezione comando da server e trasmissione risposta.
ExceptionsUDINTContatore pacchetti Modbus con eccezione ricevuti dal sistema slave.
ErrorsUDINTContatore errori di esecuzione.

Trigger di spy​

Se SpyOn attivo è possibile utilizzare la console di spionaggio per verificare il funzionamento della FB. Sono previsti vari livelli di triggers.

Livelli di trigger

TriggerDescrizione
16#00000001IRx: Ricezione frame comando modbus (Input)
16#00000002ITx: Trasmissione frame risposta modbus (Input)
16#00000004ORx: Ricezione frame risposta modbus (Output)
16#00000008OTx: Trasmissione frame comando modbus (Output)
16#40000000Er: Errore di esecuzione.

Esempi​

Come utilizzare gli esempi.
ST_ModbusGateway: Viene gestito un semplice gateway tra Modbus TCP e Modbus RTU.

ST_ModbusGatewayMC: Viene gestito un gateway tra Modbus TCP e Modbus RTU sono gestite fino a 3 connessioni TCP contemporanee.

ST_ModbusGatewayPkModify: Viene gestito un gateway tra Modbus TCP e Modbus RTU se nodo Modbus diverso da 2. Nel caso il nodo Modbus sia 2 il gateway reindirizza il pacchetto al nodo 255 su Modbus TCP connesso in localhost. Viene anche eseguita la modifica dell'indirizzo Modbus richiesto su comando Read Holding register.

ST_ModbusRTUNetwork: Il sistema master comunica con uno o più sistemi slave utilizzando i FBs ModbusMaster ed ACModbus. Su connessione TCP sulla porta 5200 viene disabilitata la comunicazione con i sistemi slaves ed abilitato il FB ModbusGateway che converte la comunicazione Modbus TCP in Modbus RTU verso i dispositivi slaves. Per programmare i vari slaves basterà in LogicLab definire una comunicazione Modbus TCP indicando indirizzo IP del dispositivo master e porta 5200. Ogni slave sarà identificabile con il proprio indirizzo di nodo.

LogicLab (Ptp205, ST_ModbusGateway)
PROGRAM ST_ModbusGateway
VAR
Sp : SysSerialPort; (* Serial port *)
MdbGw : ModbusGateway_v2; (* Modbus gateway *)
TCPServer : SysTCPServer; (* TCPServer management *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_ModbusGateway"
// *****************************************************************************
// Simple Modbus TCP to Modbus RTU gateway.
// -----------------------------------------------------------------------------

// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Program initializations.

IF (SysFirstLoop) THEN

// TCP server settings.

TCPServer.FilesArr:=ADR(MdbGw.IFile); //Files array
TCPServer.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPServer.LocalPort:=2000; //Local port
TCPServer.MaxConn:=1; //Accepted connections
TCPServer.FlushTm:=50; //Flush time (mS)
TCPServer.LifeTm:=60; //Life time (S)
TCPServer.RxSize:=256; //Rx buffer size
TCPServer.TxSize:=256; //Tx buffer size

// Serial port settings.

Sp.COM:=ADR('COM2'); //COM port definition
Sp.Baudrate:=115200; //Baudrate
Sp.Parity:='E'; //Parity
Sp.DataBits:=8; //Data bits
Sp.StopBits:=1; //Stop bits
Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
Sp.DTRComplement:=FALSE; //DTR complement
Sp.EchoFlush:=FALSE; //Received echo flush
Sp.DTROnTime:=0; //DTR On time delay (mS)
Sp.DTROffTime:=0; //DTR Off time delay (mS)
Sp.FlushTm:=0; //Flush time (mS)
Sp.RxSize:=0; //Rx buffer size
Sp.TxSize:=0; //Tx buffer size

// Modbus gateway settings.

MdbGw.SpyOn:=FALSE; //Spy On
MdbGw.IType:=MODBUS_PROTOCOL#MDB_TCP; //Modbus type (Input)
MdbGw.OType:=MODBUS_PROTOCOL#MDB_RTU; //Modbus type (Output)
MdbGw.ITrigger:=eNULL; //Trigger command (Input)
MdbGw.OTrigger:=eNULL; //Trigger answer (Output)
MdbGw.Timeout:=T#1s; //Timeout time
END_IF;

// -------------------------------------------------------------------------
// GATEWAY MANAGEMENT
// -------------------------------------------------------------------------
// Gateway management.

TCPServer(Enable:=TRUE); //TCPServer management
Sp(Open:=TRUE); //Serial port management
MdbGw(OFile:=Sp.File, Enable:=SysFIsOpen(MdbGw.IFile)); //Modbus gateway enable

// [End of file]
LogicLab (Ptp205, ST_ModbusGatewayMC)
PROGRAM ST_ModbusGatewayMC
VAR
i : UDINT; (* Auxiliary counter *)
Fp : ARRAY[0..2] OF eFILEP; (* File pointer *)
Sp : SysSerialPort; (* Serial port *)
TCPServer : SysTCPServer; (* TCPServer management *)
MdbGw : ARRAY[0..2] OF ModbusGateway_v2; (* Modbus gateway *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_ModbusGatewayMC"
// *****************************************************************************
// A Modbus TCP to RTU gateway that accepts up to 3 simultaneous connections.
// -----------------------------------------------------------------------------

// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Program initializations.

IF (SysFirstLoop) THEN

// TCP server settings.

TCPServer.FilesArr:=ADR(Fp); //Files array
TCPServer.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPServer.LocalPort:=2000; //Local port
TCPServer.MaxConn:=3; //Accepted connections
TCPServer.FlushTm:=50; //Flush time (mS)
TCPServer.LifeTm:=60; //Life time (S)
TCPServer.RxSize:=256; //Rx buffer size
TCPServer.TxSize:=256; //Tx buffer size

// Serial port settings.

Sp.COM:=ADR('COM0'); //COM port definition
Sp.Baudrate:=115200; //Baudrate
Sp.Parity:='E'; //Parity
Sp.DataBits:=8; //Data bits
Sp.StopBits:=1; //Stop bits
Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
Sp.DTRComplement:=FALSE; //DTR complement
Sp.EchoFlush:=FALSE; //Received echo flush
Sp.DTROnTime:=0; //DTR On time delay (mS)
Sp.DTROffTime:=0; //DTR Off time delay (mS)
Sp.FlushTm:=0; //Flush time (mS)
Sp.RxSize:=0; //Rx buffer size
Sp.TxSize:=0; //Tx buffer size

// Modbus gateway settings.

FOR i:=0 TO 2 DO
MdbGw[i].SpyOn:=TRUE; //Spy On
MdbGw[i].IType:=MODBUS_PROTOCOL#MDB_TCP; //Modbus type (Input)
MdbGw[i].OType:=MODBUS_PROTOCOL#MDB_RTU; //Modbus type (Output)
MdbGw[i].ITrigger:=eNULL; //Trigger command (Input)
MdbGw[i].OTrigger:=eNULL; //Trigger answer (Output)
MdbGw[i].Timeout:=T#1s; //Timeout time
END_FOR;
END_IF;

// -------------------------------------------------------------------------
// GATEWAY MANAGEMENT
// -------------------------------------------------------------------------
// Gateway management.

TCPServer(Enable:=TRUE); //TCPServer management
Sp(Open:=TRUE); //Serial port management

MdbGw[0].ILock:=(MdbGw[1].OLock OR MdbGw[2].OLock);
MdbGw[0](IFile:=Fp[0], OFile:=Sp.File, Enable:=SysFIsOpen(Fp[0])); //Modbus gateway enable

MdbGw[1].ILock:=(MdbGw[0].OLock OR MdbGw[2].OLock);
MdbGw[1](IFile:=Fp[1], OFile:=Sp.File, Enable:=SysFIsOpen(Fp[1])); //Modbus gateway enable

MdbGw[2].ILock:=(MdbGw[0].OLock OR MdbGw[1].OLock);
MdbGw[2](IFile:=Fp[2], OFile:=Sp.File, Enable:=SysFIsOpen(Fp[2])); //Modbus gateway enable

// [End of file]
LogicLab (Ptp205, ST_ModbusGatewayPkModify)
PROGRAM ST_ModbusGatewayPkModify
VAR
AwB : WORD; (* Auxiliary word buffer *)
ITrigger : BOOL; (* Trigger command (Input) *)
OTrigger : BOOL; (* Trigger answer (Output) *)
MCommand : BYTE; (* Modbus command *)
MCPoints : UINT; (* Modbus command points *)
MRAddress : WORD; (* Modbus request address *)
MCAddress : WORD; (* Modbus command address *)
IRegs : ARRAY[0..7] OF WORD; (* Internal registers *)
Sp : SysSerialPort; (* Serial port *)
TCPClient : SysTCPClient; (* TCP client management *)
TCPServer : SysTCPServer; (* TCPServer management *)
MdbGw : ModbusGateway_v2; (* Modbus gateway *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_ModbusGatewayPkModify"
// *****************************************************************************
// Modbus TCP to Modbus RTU and Modbus TCP gateway
// -----------------------------------------------------------------------------

// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Program initializations.

IF (SysFirstLoop) THEN

// TCP server settings.

TCPServer.FilesArr:=ADR(MdbGw.IFile); //Files array
TCPServer.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPServer.LocalPort:=2000; //Local port
TCPServer.MaxConn:=1; //Accepted connections
TCPServer.FlushTm:=50; //Flush time (mS)
TCPServer.LifeTm:=60; //Life time (S)
TCPServer.RxSize:=256; //Rx buffer size
TCPServer.TxSize:=256; //Tx buffer size

// Serial port settings.

Sp.COM:=ADR('COM2'); //COM port definition
Sp.Baudrate:=115200; //Baudrate
Sp.Parity:='E'; //Parity
Sp.DataBits:=8; //Data bits
Sp.StopBits:=1; //Stop bits
Sp.DTRManagement:=DTR_AUTO_WO_TIMES; //DTR management
Sp.DTRComplement:=FALSE; //DTR complement
Sp.EchoFlush:=FALSE; //Received echo flush
Sp.DTROnTime:=0; //DTR On time delay (mS)
Sp.DTROffTime:=0; //DTR Off time delay (mS)
Sp.FlushTm:=0; //Flush time (mS)
Sp.RxSize:=0; //Rx buffer size
Sp.TxSize:=0; //Tx buffer size

// TCP client settings.

TCPClient.PeerAdd:=ADR('127.0.0.1'); //Peer address
TCPClient.PeerPort:=502; //Peer port
TCPClient.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPClient.LocalPort:=0; //Local port
TCPClient.FlushTm:=50; //Flush time (mS)
TCPClient.LifeTm:=20; //Life time (S)
TCPClient.RxSize:=128; //Rx buffer size
TCPClient.TxSize:=128; //Tx buffer size

// Modbus gateway settings.

MdbGw.SpyOn:=TRUE; //Spy On
MdbGw.IType:=MODBUS_PROTOCOL#MDB_TCP; //Modbus type (Input)
MdbGw.ITrigger:=ADR(ITrigger); //Trigger command (Input)
MdbGw.OTrigger:=eNULL; //Trigger answer (Output)
MdbGw.Timeout:=T#1s; //Timeout time
END_IF;

// -------------------------------------------------------------------------
// GATEWAY MANAGEMENT
// -------------------------------------------------------------------------
// Gateway management.

TCPServer(Enable:=TRUE); //TCPServer management
Sp(Open:=TRUE); //Serial port management
TCPClient(Connect:=TRUE); //TCPClient management
MdbGw(Enable:=SysFIsOpen(MdbGw.IFile)); //Modbus gateway enable

// =========================================================================
// MODBUS PACKET MODIFY
// =========================================================================
// Below a program that shows the FB powerful features.

// -------------------------------------------------------------------------
// "IFILE" MODBUS RX PACKETS ANALYSING
// -------------------------------------------------------------------------
// At every modbus packet received from the "IFile" communication stream,
// the packets is analized and modified by the program before to be sent to
// slave system connected to "OFile" communication stream.
// -------------------------------------------------------------------------
// Just a remind on the Modbus commands,
// 16#01 Read coil status
// 16#02 Read input status
// 16#03 Read holding registers
// 16#04 Read input registers
// 16#05 Force single coil
// 16#06 Preset single register
// 16#10 Preset multiple registers
//
// +----+---+---+---+---...---
// Command frame |Node|Cmd|Address| Data
// +----+---+---+---+---...---
// -------------------------------------------------------------------------
// The needs are to manage connection to three types of devices according
// the received command address.

IF (ITrigger) THEN
ITrigger:=FALSE; //Trigger command (Input)

// Acquire the command and address from the received packet and manage it.

MCommand:=eGetBYTE(MdbGw.DFrame+1); //Modbus command
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, ADR(MCAddress), MdbGw.DFrame+2)); //Modbus command address

CASE (MCAddress) OF

// -----------------------------------------------------------------
// Addresses from 0 to 7 are managed by the program and act on 8
// registers (Only 16#03 and 16#10 command are managed).

0..7:
MdbGw.OFile:=eNULL; //So command packet is not redirect to any slave
CASE (MCommand) OF

// -------------------------------------------------------------
// Read holding registers, return the request value.
// +----+--+---+---+---+---+ +----+--+-----+--...--+
// Rx |Node|03|Address|Points | Tx |Node|03|Bytes| Data |
// +----+--+---+---+---+---+ +----+--+-----+--...--+

16#03:
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, ADR(MCPoints), MdbGw.DFrame+4)); //Modbus command points
eTO_JUNK(eSetBYTE(MdbGw.DFrame+2, TO_BYTE(MCPoints*2))); //Set bytes

FOR AwB:=0 TO MCPoints-1 DO
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, MdbGw.DFrame+3+(AwB*2), eTO_POINTER(ADR(IRegs))+(AwB*2)));
END_FOR;

MdbGw.ADLgt:=3+(MCPoints*2); //Answer data length

// -------------------------------------------------------------
// Preset multiple registers, return the proper answer.
// +----+--+---+---+---+---+-----+--...--+ +----+--+---+---+---+---+
// Rx |Node|10|Address|Points |Bytes| Data | Tx |Node|10|Address|Points |
// +----+--+---+---+---+---+-----+--...--+ +----+--+---+---+---+---+

16#10:
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, ADR(MCPoints), MdbGw.DFrame+4)); //Modbus command points

FOR AwB:=0 TO MCPoints-1 DO
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, eTO_POINTER(ADR(IRegs))+(AwB*2), MdbGw.DFrame+7+(AwB*2)));
END_FOR;

MdbGw.ADLgt:=6; //Answer data length

// -------------------------------------------------------------
// If command is not managed an exception is sent.
// +--+---+---------+
// |Nd|Cmd|Exception|
// +--+---+---------+

ELSE
eTO_JUNK(eSetBYTE(MdbGw.DFrame+1, eGetBYTE(MdbGw.DFrame+1) OR 16#80));
eTO_JUNK(eSetBYTE(MdbGw.DFrame+2, 16#02)); //Illegal data address
MdbGw.ADLgt:=3; //Answer data length
END_CASE;

// -----------------------------------------------------------------
// Address 100 is sent on a Modbus RTU slave, address is offsetted.

100:
MdbGw.OFile:=Sp.File; //Output stream
MdbGw.OType:=MODBUS_PROTOCOL#MDB_RTU; //Modbus type
MRAddress:=(MCAddress-100)+40000; //Modbus request address
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, MdbGw.DFrame+2, ADR(MRAddress)));

// -----------------------------------------------------------------
// Address 200 is sent on a Modbus TCP slave, address is offsetted.

200:
MdbGw.OFile:=TCPClient.File; //Output stream
MdbGw.OType:=MODBUS_PROTOCOL#MDB_TCP; //Modbus type
MRAddress:=(MCAddress-200)+40000; //Modbus request address
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, MdbGw.DFrame+2, ADR(MRAddress)));

// -----------------------------------------------------------------
// All other address are exceptions.
// +--+---+---------+
// |Nd|Cmd|Exception|
// +--+---+---------+

ELSE
MdbGw.OFile:=eNULL; //So command packet is not redirect to any slave
eTO_JUNK(eSetBYTE(MdbGw.DFrame+1, eGetBYTE(MdbGw.DFrame+1) OR 16#80));
eTO_JUNK(eSetBYTE(MdbGw.DFrame+2, 16#02)); //Illegal data address
MdbGw.ADLgt:=3; //Answer data length
END_CASE;
END_IF;

// -------------------------------------------------------------------------
// "OFILE" MODBUS RX PACKETS ANALYSING
// -------------------------------------------------------------------------
// Just a remind on the Modbus answers,
// 16#01 Read coil status
// 16#02 Read input status
// 16#03 Read holding registers
// 16#04 Read input registers
//
// +----+---+---
// Answer frame |Node|Cmd|...
// +----+---+---
//
// 16#05 Force single coil
// 16#06 Preset single register
// 16#10 Preset multiple registers
//
// +----+---+---+---+---
// Answer frame |Node|Cmd|Address|...
// +----+---+---+---+---
// -------------------------------------------------------------------------
// Nelle risposte l'indirizzo di nodo da ritornare è sempre 16#01.

IF (OTrigger) THEN
OTrigger:=FALSE; //Trigger command (Output)

// Acquire the command and address from the received packet and manage it.

MCommand:=eGetBYTE(MdbGw.DFrame+1); //Modbus command
CASE (MCommand) OF

// -----------------------------------------------------------------
// On these commands no modification is required.

16#01, 16#02,16#03, 16#04:

// -----------------------------------------------------------------
// On these commands the address must be replaced.

16#05, 16#06,16#10:
eTO_JUNK(ArrayVarTxfer(TRUE, WORD_TYPE, MdbGw.DFrame+2, ADR(MCAddress)));
END_CASE;
END_IF;

// [End of file]
LogicLab (Ptp205, ST_ModbusRTUNetwork)
PROGRAM ST_ModbusRTUNetwork
VAR
MdbRead : ARRAY[0..1] OF WORD; (* Modbus read buffer *)
MdbWrite : ARRAY[0..1] OF WORD; (* Modbus write buffer *)
ACData : ARRAY[0..1] OF ACMODBUS_DATA_V3; (* Array command data *)
Sp : SysSerialPort; (* Porta seriale *)
Sk : SysTCPServer; (* TCP server *)
ACMdb : ACModbus_v3; (* Array command modbus *)
MMdb : ModbusMaster_v3; (* Modbus master communication *)
MdbGw : ModbusGateway_v2; (* Modbus ascii to RTU gateway *)
END_VAR

// *****************************************************************************
// PROGRAM "ST_ModbusRTUNetwork"
// *****************************************************************************
// A modbus RTU master network with LogicLab access to nodes.
// -----------------------------------------------------------------------------

// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Program initializations.

IF (SysFirstLoop) THEN

// Serial port settings.

Sp.COM:=ADR('COM0'); // COM port definition
Sp.Baudrate:=115200; // Baudrate
Sp.Parity:='E'; // Parity
Sp.DataBits:=8; // Data bits
Sp.StopBits:=1; // Stop bits
Sp.DTRManagement:=DTR_AUTO_WO_TIMES; // DTR management
Sp.DTRComplement:=FALSE; // DTR complement
Sp.EchoFlush:=FALSE; // Received echo flush
Sp.DTROnTime:=0; // DTR On time delay (mS)
Sp.DTROffTime:=0; // DTR Off time delay (mS)
Sp.FlushTm:=0; // Flush time (mS)
Sp.RxSize:=0; // Rx buffer size
Sp.TxSize:=0; // Tx buffer size

// TCP server settings.

Sk.FilesArr:=ADR(MdbGw.IFile); // Files array
Sk.LocalAdd:=ADR('0.0.0.0'); // Local address
Sk.LocalPort:=5200; // Local port
Sk.MaxConn:=1; // Accepted connections
Sk.FlushTm:=50; // Flush time (mS)
Sk.LifeTm:=30; // Life time (S)
Sk.RxSize:=256; // Rx buffer size
Sk.TxSize:=256; // Tx buffer size

// Modbus master settings.

MMdb.Type:=MODBUS_PROTOCOL#MDB_RTU; //Modbus protocol type
MMdb.Absolute:=FALSE; //Absolute addressing
MMdb.Timeout:=T#100ms; //Timeout time
MMdb.Delay:=T#30ms; //Delay time

// Modbus gateway settings.

MdbGw.SpyOn:=TRUE; //Spy On
MdbGw.IType:=MODBUS_PROTOCOL#MDB_TCP; //Modbus type (Input)
MdbGw.OType:=MODBUS_PROTOCOL#MDB_RTU; //Modbus type (Output)
MdbGw.ITrigger:=eNULL; //Trigger command (Input)
MdbGw.OTrigger:=eNULL; //Trigger answer (Output)
MdbGw.Timeout:=T#1s; //Timeout time

// Array command modbus settings.

ACMdb.ACAdd:=ADR(ACData); //Array command address
ACMdb.ACNr:=SIZEOF(ACData)/SIZEOF(ACData[0]); //Array command number
ACMdb.RTime:=T#10s; //Retry time

// Node 1 registers read..

ACData[0].Command.0:=FALSE; //Spy On
ACData[0].Command.1:=FALSE; //Absolute addressing
ACData[0].Node:=1; //Modbus node
ACData[0].FCode:=16#03; //Modbus function code
ACData[0].Address:=40000; //Modbus register address
ACData[0].Buffer:=ADR(MdbRead); //Memory buffer address
ACData[0].Points:=TO_UINT(SIZEOF(MdbRead)/2); //Modbus register points

// Node 1 registers write..

ACData[1].Command.0:=FALSE; //Spy On
ACData[1].Command.1:=FALSE; //Absolute addressing
ACData[1].Node:=1; //Modbus node
ACData[1].FCode:=16#10; //Modbus function code
ACData[1].Address:=40000; //Modbus register address
ACData[1].Buffer:=ADR(MdbWrite); //Memory buffer address
ACData[1].Points:=TO_UINT(SIZEOF(MdbWrite)/2); //Modbus register points
END_IF;

// -------------------------------------------------------------------------
// COMMUNICATION STREAMS
// -------------------------------------------------------------------------
// Manage the communication streams.

Sp(Open:=TRUE); //Serial port management
Sk(Enable:=TRUE); //TCP server management

// Manage Modbus communication.

MMdb(File:=Sp.File); //Modbus master
ACMdb(MMdb:=ADR(MMdb)); //Array command modbus

// If a client connect to TCP server the Modbus gateway is enabled.
// This gains access to slave nodes.

MdbGw(OFile:=Sp.File, Enable:=SysFIsOpen(MdbGw.IFile)); //Modbus gateway enable
ACMdb.Enable:=NOT(MdbGw.Enable) AND NOT(ACMdb.Done); //FB enable

// [End of file]