Skip to content
Snippets Groups Projects
Commit 2458f5e3 authored by al.schwinn's avatar al.schwinn
Browse files

[SIL-170] Upgrade Modbus library to official 3.0.6 version and link

with 3rd party delivery.
parent 2733f7e3
No related branches found
No related tags found
No related merge requests found
Showing
with 129 additions and 2894 deletions
......@@ -33,5 +33,8 @@ COMPILER_FLAGS = -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH)
# Comment IN/Out to enable NI-Support
#COMPILER_FLAGS += -DNI_SUPPORT_ENABLED=TRUE
# Comment IN/Out to enable Modbus-Support
#COMPILER_FLAGS += -DMODBUS_SUPPORT_ENABLED=TRUE
# Include the generic make file
include $(COMMON_MAKE_PATH)/Make.generic
\ No newline at end of file
......@@ -4,6 +4,17 @@ LIBXML_PATH ?= /usr/include/libxml2/
SNAP7_BASE ?= ../snap7/snap7-full
BOOST_HOME ?= /opt/gsi/3rdparty/boost/$(BOOST_VERSION)
ifdef MODBUS_SUPPORT_ENABLED
MODBUS_VERSION = 3.0.6
MODBUS_ROOT=$(RELEASE_LOCATION)/$(CPU)/3rdparty/libmodbus-$(MODBUS_VERSION)
MODBUS_SRC=$(MODBUS_ROOT)/src
MODBUS_LIB=$(MODBUS_SRC)/.libs
MODBUS_RPATH=$(RELEASE_LOCATION)/$(CPU)/3rdparty/libmodbus-$(MODBUS_VERSION)/src/.libs
endif
ifdef MODBUS_SUPPORT_ENABLED
DEPENDENT_COMPILER_OPTIONS += -I$(MODBUS_SRC)
endif
DEPENDENT_COMPILER_OPTIONS += -I$(LIBXML_PATH)
DEPENDENT_COMPILER_OPTIONS += -I$(SNAP7_BASE)/release/Wrappers/c-cpp
DEPENDENT_COMPILER_OPTIONS += -I$(BOOST_HOME)/include
\ No newline at end of file
......@@ -12,7 +12,7 @@
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef MODBUS_SUPPORT_ENABLED
#include <silecs-communication/interface/utility/SilecsLog.h>
#include <silecs-communication/interface/utility/StringUtilities.h>
#include <silecs-communication/interface/communication/SilecsConnection.h>
......@@ -26,6 +26,7 @@ namespace Silecs
MBConnection::MBConnection(PLC* thePLC) : Connection(thePLC)
{
LOG(ALLOC) << "MBConnection (create): " << thePLC->getName();
readCtx_ = writeCtx_ = NULL;
}
......@@ -39,18 +40,19 @@ namespace Silecs
bool MBConnection::open(PLC* thePLC)
{
//Open read and write Modbus channels (using IP address to limit the naming-server accesses)
readCh_ = IeMdbOpen(0, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress());
writeCh_ = IeMdbOpen(0, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress());
return ((readCh_ >= 0) && (writeCh_ >= 0));
int readErr = IeMdbOpen(&readCtx_, NULL, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress());
int writeErr = IeMdbOpen(&writeCtx_, NULL, (char *) thePLC->getIPAddress().c_str(), (int)thePLC->getBaseAddress());
return ((readErr == 0) && (writeErr == 0));
}
bool MBConnection::close(PLC* thePLC)
{
int err = 0;
err |= IeMdbClose(readCh_);
err |= IeMdbClose(writeCh_);
return (err == 0);
int err = 0;
err |= IeMdbClose(readCtx_);
err |= IeMdbClose(writeCtx_);
readCtx_ = writeCtx_ = NULL;
return (err == 0);
}
......@@ -78,7 +80,7 @@ namespace Silecs
//DATA topic makes sense with RECV one
if (RECV & Log::topics_) LOG(DATA) << "Read data, address: %MW" << addr << ", byte-size: " << size;
int error = IeMBreadData(readCh_, addr, (unsigned short)size, pBuffer);
int err = IeMBreadData(readCtx_, addr, (unsigned short)size, pBuffer);
if(error)
throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error)));
}
......@@ -111,7 +113,7 @@ namespace Silecs
//DATA topic makes sense with SEND one
if (SEND & Log::topics_) LOG(DATA) << "Write data, address: %MW" << addr << ", byte-size: " << size;
int error = IeMBwriteData(writeCh_, (unsigned short)addr, (unsigned short)size, pBuffer);
int error = IeMBwriteData(writeCtx_, (unsigned short)addr, (unsigned short)size, pBuffer);
if(error)
throw SilecsException(__FILE__, __LINE__, UNEXPECTED_ERROR," ModBus Error: " + string(IeGetErrorMessage(error)));
}
......@@ -119,3 +121,4 @@ namespace Silecs
}
} // namespace
#endif //MODBUS_SUPPORT_ENABLED
......@@ -12,7 +12,7 @@
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef MODBUS_SUPPORT_ENABLED
#ifndef _MB_CONNECTION_H_
#define _MB_CONNECTION_H_
......@@ -22,7 +22,6 @@
namespace Silecs
{
class PLC;
class Connection;
/*!
* \class MBConnection
......@@ -39,6 +38,8 @@ namespace Silecs
int writeData(PLC* thePLC, unsigned long address, unsigned long offset, unsigned long size, unsigned char* pBuffer);
private:
modbus_t* readCtx_;
modbus_t* writeCtx_;
bool open(PLC* thePLC);
bool close(PLC* thePLC);
......@@ -48,3 +49,4 @@ namespace Silecs
#endif // _MB_CONNECTION_H_
#endif //MODBUS_SUPPORT_ENABLED
......@@ -17,12 +17,12 @@
#define _SNAP7_CONNECTION_H_
#include <silecs-communication/protocol/core/silecs.h>
#include <silecs-communication/interface/communication/SilecsConnection.h>
#include <snap7.h>
namespace Silecs
{
class PLC;
class Connection;
/*!
* \class SNAP7Connection
......
......@@ -22,7 +22,6 @@ namespace Silecs
{
// static definition
bool Connection::isInit_ = false;
bool Connection::isAlive_ = false;
const unsigned int Connection::numberConn_ = 3;
......@@ -42,12 +41,6 @@ namespace Silecs
timeConn_ = NULL;
delayConn_ = UrgentConnection; //initial reconnection delay
remainConn_ = numberConn_; //initial number of attempt
// Silecs initialization has to be invoked only once per process
if (isInit_== false)
{ IeInit();
isInit_ = true;
}
}
......@@ -191,7 +184,6 @@ namespace Silecs
{
if (close(thePLC))
{
readCh_ = writeCh_ = 0;
isConnected_ = false;
//Connection status has changed: update the diagnostic variables
......
......@@ -147,10 +147,6 @@ namespace Silecs
// flag used to enable/disable the transactions independently from the scheduling
bool isEnabled_;
// Silecs descriptor for send/recv channels
ChannelID readCh_;
ChannelID writeCh_;
/* . read-channel and write channel are independent and can be accessed in parallel.
* . Each channel must be protected against respective concurrent access.
* . The global action (open,close,etc.) must be protected from any concurrent access.
......@@ -169,9 +165,6 @@ namespace Silecs
static bool isAlive_; // PLC has repliyed to the ping: true/false
bool isConnected_; // State of this particular connection: FEC/PLC/Class
// Silecs initialization has to be invoked only once per process
static bool isInit_;
// not copyable object
Connection(const Connection&);
Connection& operator=(const Connection&);
......
......@@ -294,7 +294,9 @@ namespace Silecs
break;
case Schneider:
case Digi:
#ifdef MODBUS_SUPPORT_ENABLED
((double *)pRecvValue_)[i*dimension2_+j] = IeMdbGetTime(pData);
#endif //MODBUS_SUPPORT_ENABLED
break;
case Ni:
//TODO
......@@ -372,7 +374,9 @@ namespace Silecs
break;
case Schneider:
case Digi:
#ifdef MODBUS_SUPPORT_ENABLED
IeMdbSetTime(pData, epoch);
#endif //MODBUS_SUPPORT_ENABLED
break;
case Ni:
//TODO
......
......@@ -450,7 +450,9 @@ namespace Silecs
case S7Protocol:
theConn = new SNAP7Connection(this); break;
case MBProtocol:
#ifdef MODBUS_SUPPORT_ENABLED
theConn = new MBConnection(this); break;
#endif
case CNVProtocol:
#ifdef NI_SUPPORT_ENABLED
theConn = new CNVConnection(this);break;
......
......@@ -39,10 +39,6 @@
#include <silecs-communication/protocol/core/silecs.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------*/
/* MACRO DEFINITION */
/* ---------------------------------------------------------*/
......@@ -321,40 +317,3 @@ char *IeGetErrorMessage(int err)
return ("Unknown IE error");
}
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at first.
*/
int IeInit (void)
{
int err=0;
err |= IeMdbInit();
return (err);
}
/*----------------------------------------------------------*/
/* This function de-initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at end.
*/
int IeExit (void)
{
int err=0;
err |= IeMdbExit();
return (err);
}
#ifdef __cplusplus
}
#endif
......@@ -33,10 +33,6 @@
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------*/
/* INCLUDE FILES */
/* ---------------------------------------------------------*/
......@@ -45,7 +41,7 @@ extern "C" {
/* ---------------------------------------------------------*/
/* PROTOTYPE DEFINITIONS */
/* ---------------------------------------------------------*/
#include <silecs-communication/protocol/modbus/iemdb.h> /* modbus interface */
#include <silecs-communication/protocol/modbus/iemdb.h>
/*----------------------------------------------------------*/
/* Time funtion
......@@ -89,26 +85,4 @@ int IeRfcPing (char *hostName, char *plcIP);
*/
char *IeGetErrorMessage(int err);
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at first.
*/
int IeInit (void);
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at end.
*/
int IeExit (void);
#ifdef __cplusplus
}
#endif
#endif /* _SILECS_H_ */
// Copyright 2016 CERN and GSI
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
* Revision : v1.0
* Date : 08/2003 - F.Locci
* Objet : original version for PS7-SCHNEIDER PLC
* Action :
*
* Revision : v1.1
* Date : 05/2004 - F.Locci
* Objet : .remove when data size = 0
* .set err on read/write error
* Look at v1.1 comments
*
* Revision : v1.2
* Date : 11/2004 - F.Locci
* Objet : .move mb_master_init() call to IeMdbInit() function
* to make modbus code reentrant.
* Look at v1.2 comments
*
* Revision : v1.3
* Date : 10/2004 - F.Locci
* Objet : .Allow absolute offset for read/write action
* .Allow variable size for read/write action
* => use offset sign convention for absolute/relative
* => use application size instead of config.table one
* Look at v1.3 comments
*
* Revision : v1.4
* Date : 03/2006 - F.Locci
* Objet : .Extend the number of possible connection (7 --> 32)
* in order to allow more than 7 connections with
* DIFFERENT PLC (SPS/EA project in particular).
* We keep 7 connection for SIEMENS (F/W) protocole
* to respect material constraint (14 ISO-ON-TCP max.)
*
* Revision : v1.5
* Date : 01/2007 - F.Locci
* Objet : implement BLOCK mode
* Action : .Add IeMdbGetBlock() and IeMdbSetBlock() function
* .Upgrade mdbFindEqp() function
* Look at v1.5 comments
*
* Revision : v1.6
* Date : 03/2007 - F.Locci
* Objet : Protect Get data buffer overflow
* Look at v1.5 comments
*
* Revision : v1.7
* Date : 04/2007 - F.Locci
* Objet : Direct byte swapping into MdbSetTime function
* Look at v1.5 comments
*/
/*
* This library was developped to provide communication between
* Linux/LynxOS active host (client) and a PLC passive server.
* Based on MODBUS std. protocole, it defines generic
* set and get functions to read and write data into/from PLC
* memory.
*/
/* ---------------------------------------------------------*/
/* INCLUDE FILES */
/* ---------------------------------------------------------*/
#include <silecs-communication/protocol/core/ietype.h>
#include "mb_addr.h"
#include "mb_master.h"
#ifdef MODBUS_SUPPORT_ENABLED
#include "iemdb.h"
#ifdef __cplusplus
extern "C" {
#endif
//Modbus max data size definition (byte counting)
#define MAX_WRITE_DATA_SIZE MODBUS_MAX_WRITE_REGISTERS*2
#define MAX_READ_DATA_SIZE MODBUS_MAX_READ_REGISTERS*2
/* ---------------------------------------------------------*/
/* LOCAL CONSTANT DEFINITIONS */
/* ---------------------------------------------------------*/
/* For Modbus protocol */
#define MODBUS_MAX_CONNECTION 64 /*v1.4*/
#define MODBUS_SENDRETRIES_DEF 1
#define MODBUS_TIMEOUT_DEF 2 /* in seconds */
/*Config.Table entries offset - SCHNEIDER memory implementation - word alignment*/
#define FEC_CMD_OFS 0 /* Command from FEC: first entry of cfg.table*/
#define PARAMS_CMD_OFS 2/2 /* Params of FEC command */
#define CURRENT_DATE_OFS 10/2 /* PLC current dat&time */
#define SYS_INFO_OFS 18/2 /* HW/SW info variables */
#define DIAG_INFO_OFS 78/2 /* PLC SW/HW diagnostic */
#define NB_EQP_OFS 132/2 /*nb table row */
#define ADDR_TBL_OFS 134/2 /*table data (addr/size)*/
#define swap16(w) ((((unsigned short)w & 0x00ff)<<8)+(((unsigned short)w & 0xff00)>>8))
/* ---------------------------------------------------------*/
/* TYPE DEFINITIONS */
/* ---------------------------------------------------------*/
/* an entry in the network array */
typedef struct
{
const char *name;
node_addr_t addr;
int nd; /* the node descriptor... */
struct timespec timeout;
u32 send_retries;
} network_t;
/* ---------------------------------------------------------*/
/* GLOBAL DECLARATIONS */
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* FUNCTIONS CODE */
/* FUNCTIONS CODE */
/* ---------------------------------------------------------*/
/*----------------------------------------------------------*/
......@@ -225,41 +109,6 @@ double IeMdbGetTime(unsigned char *dt) // from PLC
return((double)plctm + ms);
}
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at first.
*/
int IeMdbInit (void)
{
/*v1.2*/
if (mb_master_init(MODBUS_MAX_CONNECTION) < 0)
{
#ifdef DEBUG
/* could not init network! */
printf("\n#Error: mb_master_init() failed");
#endif
return (IE_SYS_ERROR);
}
return 0;
}
/*----------------------------------------------------------*/
/* This function de-initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at end.
*/
int IeMdbExit (void)
{
mb_master_done();
return 0;
}
/*----------------------------------------------------------*/
/* This function creates a synchronous OSI-ON-TCP socket
* channel used for sending/receiving communication with PLC.
......@@ -272,150 +121,20 @@ int IeMdbExit (void)
* Only one synchronous channel per PLC at the same time
* supported in that version.
*/
int IeMdbOpen (char *hostName, char *plcIP, int baseAddress)
int IeMdbOpen (modbus_t** ctx, char *hostName, char *plcIP, int baseAddress)
{
network_t net;
char *ipstr = plcIP;
_WORD dummy;
// use hostName reference in priority else plcIP
if (hostName) ipstr = hostName;
*ctx = modbus_new_tcp(plcIP, MODBUS_TCP_DEFAULT_PORT /*=502*/);
//modbus_set_debug(*ctx, TRUE);
if (ipstr == NULL)
if (modbus_connect(*ctx) == -1)
{
printf("#Error: ipstr NULL\n");
return(IE_PARAM_ERROR);
modbus_free(*ctx);
return IE_CONNECT_ERROR;
}
/* init network .........................................*/
/*net.name = not used here*/
net.addr.naf = naf_tcp;
net.addr.addr.tcp.host = ipstr;
net.addr.addr.tcp.service = "502"; //specific modbus
net.addr.addr.tcp.close_on_silence = 1; // TRUE
net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF);
net.send_retries = MODBUS_SENDRETRIES_DEF;
/* connection ......................................*/
if ( (net.nd = mb_master_connect(net.addr)) >= 0)
{
/*Try to access PLC memory, just to confirm modbus connection (for example,
read config. table address.
*/
if (read_bdata(
1, /*int slave,*/
baseAddress/2, /*int start_addr (/2 is used to convert the byte alignment to 16bit alignment) */
sizeof(dummy), /*int byte count,*/
(_BYTE *)&dummy, /*uchar *dest,*/
net.nd, /*int ttyfd,*/
net.send_retries, /*int send_retries,*/
&net.timeout /*const struct timespec *response_timeout*/
) >= 0)
{
/* node opened successfully! */
#ifdef DEBUG
printf("Connecting to network %s: OK\n", net.addr.addr.tcp.host);
#endif
return (net.nd);
}
#ifdef DEBUG
else
{
/* could not read registers from slave! */
printf("#Error: could not establish connection to %s\n", net.addr.addr.tcp.host);
}
#endif
mb_master_close(net.nd);
}
#ifdef DEBUG
else
{
/* could not connect to slave! */
printf("#Error: could not establish connection to %s\n", net.addr.addr.tcp.host);
}
#endif
return(IE_CONNECT_ERROR);
return 0;
}
/*----------------------------------------------------------*/
int IeMBwriteData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer)
{
int err;
network_t net;
/* init network .........................................*/
net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF);
net.send_retries = MODBUS_SENDRETRIES_DEF;
/*then SET&DATE cmd into command word*/
if (write_bdata(1, /*int slave,*/
dataOfs, /*int start_addr (!16 bits alignment)*/
dataSize, /*int byte count */
dataBuffer, /*uchar *src */
cid, /*int connection id */
net.send_retries, /*int send_retries,*/
&net.timeout /*const struct timespec *response_timeout*/
) >= 0)
{
#ifdef DEBUG
printf("IeMBwriteData has been done successfully\n");
#endif
err = 0; /*no problem*/
}
else
{
#ifdef DEBUG
printf("#Error on IeMBwriteData\n");
#endif
err = IE_EPIPE_ERROR;
}
return err;
}
/*----------------------------------------------------------*/
int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer)
{
int err;
network_t net;
/* init network .........................................*/
net.timeout = d_to_timespec(MODBUS_TIMEOUT_DEF);
net.send_retries = MODBUS_SENDRETRIES_DEF;
/*unusefull to read empty data buffer*/
if (dataSize > 0)
{
err = read_bdata(1, /*int slave,*/
dataOfs, /*int start_addr (!16 bits alignment)*/
dataSize, /*int byte count */
dataBuffer, /*uchar *src */
cid, /*int connection id */
net.send_retries, /*int send_retries,*/
&net.timeout /*const struct timespec *response_timeout*/
);
}
if ((dataSize == 0) || (err >= 0))
{
#ifdef DEBUG
printf("IeMBreadData has been done successfully\n");
#endif
err = 0; /*no problem*/
}
else
{
#ifdef DEBUG
printf("#Error on IeMBreadData\n");
#endif
err = IE_EPIPE_ERROR;
}
return err;
}
/*----------------------------------------------------------*/
/* This function closes the synchronous OSI-ON-TCP socket
......@@ -425,17 +144,72 @@ int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer)
*
* Details:
*/
int IeMdbClose(int cid)
int IeMdbClose(modbus_t* ctx)
{
int err = 0;
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
err |= mb_master_close(cid);
if (err != 0) err = IE_DISCONNECT_ERROR;
return(err);
return 0;
}
#ifdef __cplusplus
/*----------------------------------------------------------*/
int IeMBwriteData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data)
{
uint16_t *srcp = (uint16_t*)data;
int word_count, byte_count;
while(count)
{
word_count = (count > MAX_WRITE_DATA_SIZE) ? MAX_WRITE_DATA_SIZE/2 : (count/2)+(count%2);
byte_count = (word_count * 2);
if (modbus_write_registers(ctx, start_addr, word_count, srcp) != word_count)
{
return IE_EPIPE_ERROR;
}
//srcp += byte_count-(count%2);
srcp += word_count;
start_addr += word_count;
count -= (byte_count - (count%2));
}
return 0;
}
#endif
/*----------------------------------------------------------*/
int IeMBreadData(modbus_t* ctx, uint16_t start_addr, uint16_t count, uint8_t* data)
{
uint16_t *destp = (uint16_t*)data;
int word_count, byte_count;
while(count) {
if (count > MAX_READ_DATA_SIZE)
{
/*'word_count' is a word counter*/
word_count = MAX_READ_DATA_SIZE/2;
}
else
{
/*'word_count' is a word counter*/
word_count = (count/2) + (count%2);
}
byte_count = (word_count * 2);
if (modbus_read_registers(ctx, start_addr, word_count, destp) != word_count)
{
return IE_EPIPE_ERROR;
}
//destp += (byte_count-(count%2));
destp += word_count;
start_addr += word_count;
count -= (byte_count - (count%2));
}
return 0;
}
#endif //MODBUS_SUPPORT_ENABLED
// Copyright 2016 CERN and GSI
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
* Revision : v1.0
* Date : 08/2003 - F.Locci
* Objet : original version for PS7-SCHNEIDER PLC
* Action :
*
* Revision : v1.5
* Date : 01/2007 - F.Locci
* Objet : implement BLOCK mode
* Action : Add IeMdbGetBlock() and IeMdbSetBlock() function
* Look at v1.5 comments
*
*/
#ifdef MODBUS_SUPPORT_ENABLED
#ifndef _IEMDB_H_
#define _IEMDB_H_
/*
* This library was developped to provide communication between
* Linux/LynxOS active host (client) and a PLC passive server.
* Based on MODBUS std. protocole, it defines generic
* set and get functions to read and write data into/from PLC
* memory.
*/
/* ---------------------------------------------------------*/
/* LOCAL CONSTANT DEFINITIONS */
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* TYPE DEFINITIONS */
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* PROTOTYPE DEFINITIONS */
/* ---------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
#include <silecs-communication/protocol/core/ietype.h>
#include <modbus.h>
/*----------------------------------------------------------*/
/* Time funtion
......@@ -64,7 +15,7 @@ extern "C" {
* format:
*
* 0 1 2 3 4 5 6 7
* SC -- HH MN MM DD YY YY
* SC -- HH MN MM DD YY YY
*
* byte 1 is used by gateway to synchronize time setting.
*/
......@@ -80,29 +31,11 @@ void IeMdbSetTime(unsigned char *dt, time_t epoch); // to PLC
* format:
*
* 0 1 2 3 4 5 6 7
* SC SC/100 HH MN MM DD YY YY
* SC SC/100 HH MN MM DD YY YY
*
*/
double IeMdbGetTime(unsigned char *dt); // from PLC
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at first.
*/
int IeMdbInit (void);
/*----------------------------------------------------------*/
/* This function initializes the DSC-PLC communication.
* return 0 or <0 on error (see constant error)
*
* Details:
* Must be executed at end.
*/
int IeMdbExit (void);
/*----------------------------------------------------------*/
/* This function creates a synchronous OSI-ON-TCP socket
* channel used for sending/receiving communication with PLC.
......@@ -115,29 +48,29 @@ int IeMdbExit (void);
* Only one synchronous channel per PLC at the same time
* supported in that version.
*/
int IeMdbOpen (char *hostName, char *plcIP, int baseAddress);
int IeMdbOpen (modbus_t** ctx, char *hostName, char *plcIP, int baseAddress);
/*----------------------------------------------------------*/
/* This function send a data segment to the PLC using the
* MODBUS protocole.
* 'cid': write channel id of the MB connection
* 'dataOfs': target adress of the data segment within the PLC memory
* 'ctx': write channel id of the MB connection
* 'dataAddr': target address of the data segment within the PLC memory
* 'dataSize': byte size of the data segment to be sent
* 'dataBuffer': buffer of the data to be sent
* return 0 or <0 on error (see constant error)
*/
int IeMBwriteData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer);
int IeMBwriteData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer);
/*----------------------------------------------------------*/
/* This function read a data segment from the PLC using the
* MODBUS protocole.
* 'cid': read channel id of the MB connection
* 'dataOfs': adress of the data segment within the PLC memory
* 'ctx': read channel id of the MB connection
* 'dataAddr': address of the data segment within the PLC memory
* 'dataSize': byte size of the data segment to be read
* 'dataBuffer': buffer to store the data
* return 0 or <0 on error (see constant error)
*/
int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer);
int IeMBreadData(modbus_t* ctx, uint16_t dataAddr, uint16_t dataSize, uint8_t* dataBuffer);
/*----------------------------------------------------------*/
/* This function closes the synchronous OSI-ON-TCP socket
......@@ -147,10 +80,7 @@ int IeMBreadData(int cid, _WORD dataOfs, _WORD dataSize, _BYTE* dataBuffer);
*
* Details:
*/
int IeMdbClose(int cid);
#ifdef __cplusplus
}
#endif
int IeMdbClose(modbus_t* ctx);
#endif /* _IEMDB_H_ */
#endif //MODBUS_SUPPORT_ENABLED
/*
* (c) 2002 Mario de Sousa
*
* Offered to the public under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
#ifndef MODBUS_LAYER2_H
#define MODBUS_LAYER2_H
/*F.Locci #include <plc.h>*/ /* get the plc data types */
#include <time.h> /* struct timespec data type */
/*F.Locci - 28/10/2003*/
/*types only defined with linux version: <asm/types.h>*/
#ifndef __Lynx__
#include <asm/types.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#else
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#ifndef __ppc4__ /*new <socket.h> with ppc4 environment*/
/*F.Locci - 03/11/2004, add x86 platform support*/
#ifndef __x86__
typedef unsigned short int sa_family_t;
/* The following constants should be used for the second parameter of
`shutdown'. */
enum
{
SHUT_RD = 0, /* No more receptions. */
#define SHUT_RD SHUT_RD
SHUT_WR, /* No more transmissions. */
#define SHUT_WR SHUT_WR
SHUT_RDWR /* No more receptions or transmissions. */
#define SHUT_RDWR SHUT_RDWR
};
#endif
#endif
/*constant conversion for LynxOS*/
#define AF_ROSE 11
#define AF_X25 9
#define AF_AX25 3
#define SOL_TCP 6
#define SOL_IP 0
#endif
typedef enum {optimize_speed, optimize_size} optimization_t;
typedef enum {
naf_ascii,
naf_rtu,
naf_tcp,
} node_addr_family_t;
typedef struct {
const char *host;
const char *service;
int close_on_silence;
} node_addr_tcp_t;
typedef struct {
const char *device;
int baud; /* plain baud rate, eg 2400; zero for the default 9600 */
int parity; /* 0 for none, 1 for odd, 2 for even */
int data_bits;
int stop_bits;
int ignore_echo; /* 1 => ignore echo; 0 => do not ignore echo */
} node_addr_rtu_t;
typedef node_addr_rtu_t node_addr_ascii_t;
typedef union {
node_addr_ascii_t ascii;
node_addr_rtu_t rtu;
node_addr_tcp_t tcp;
} node_addr_common_t;
typedef struct {
node_addr_family_t naf;
node_addr_common_t addr;
} node_addr_t;
#endif /* MODBUS_LAYER2_H */
/*
* (c) 2001 Mario de Sousa
*
* Offered to the public under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*
* Revision : v1.0
* Date : 11/2004 - F.Locci
* Objet : move global recv_buf_ to local one into read/write_bdata()
* to make module reentrant.
* Look at v1.0 comment
*/
#ifndef MODBUS_LAYER1_H
#define MODBUS_LAYER1_H
#ifdef __cplusplus
extern "C" {
#endif
/*F.Locci #include <plc.h>*/ /* get the plc data types */
#include <time.h> /* struct timespec data type */
#include "mb_addr.h" /* get definitions of common variable types */
/* write a modbus frame */
/* WARNING: when calling this functio, the *frame_data buffer
* must be allocated with an extra *extra_bytes
* beyond those required for the frame_length.
* This is because the extra bytes will be used
* to store the crc before sending the frame.
*
* The *extra_bytes value will be returned by the
* modbus_init() function call.
*/
/* NOTE: calling this function will flush the input stream,
* which means any frames that may have arrived
* but have not yet been read using modbus_read()
* will be permanently lost...
*/
int modbus_write(int nd,
u8 *frame_data,
size_t frame_length,
u16 transaction_id);
/* read a modbus frame */
/* NOTE: calling modbus_write() will flush the input stream,
* which means any frames that may have arrived
* but have not yet been read using modbus_read()
* will be permanently lost...
*
* NOTE: Ususal select semantics for (a: recv_timeout == NULL) and
* (b: *recv_timeout == 0) also apply.
*
* (a) Indefinite timeout
* (b) Try once, and and quit if no data available.
*/
int modbus_read(int *nd, /* node descriptor */
u8 *recv_data_ptr/*v1.0*/,
u16 *transaction_id,
u8 *send_data, /* ignored ! */
int send_length, /* ignored ! */
const struct timespec *recv_timeout);
/* init the library */
int modbus_init(int nd_count, /* maximum number of nodes... */
optimization_t opt,
int *extra_bytes);
/* shutdown the library...*/
int modbus_done(void);
/* Open a node for master / slave operation.
* Returns the node descriptor, or -1 on error.
*/
int modbus_connect(node_addr_t node_addr);
int modbus_listen(node_addr_t node_addr);
/* Close a node, needs a node descriptor as argument... */
int modbus_close(int nd);
/* Tell the library that the user will probably not be communicating
* for some time...
* This will allow the library to release any resources it will not
* be needing during the silence.
* NOTE: This is onlyused by the TCP version to close down tcp connections
* when the silence will going to be longer than second.
*/
int modbus_silence_init(void);
/* determine the minmum acceptable timeout... */
/* NOTE: timeout values passed to modbus_read() lower than the value returned
* by this function may result in frames being aborted midway, since they
* take at least modbus_get_min_timeout() seconds to transmit.
*/
double modbus_get_min_timeout(int baud,
int parity,
int data_bits,
int stop_bits);
#ifdef __cplusplus
}
#endif
#endif /* MODBUS_LAYER1_H */
/* mb_master.c
By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au
These library of functions are designed to enable a program send and
receive data from a device that communicates using the Modbus protocol.
Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The functions included here have been derived from the
Modicon Modbus Protocol Reference Guide
which can be obtained from Schneider at www.schneiderautomation.com.
This code has its origins with
paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk)
who wrote a small program to read 100 registers from a modbus slave.
I have used his code as a catalist to produce this more functional set
of functions. Thanks paul.
10/2001 - Mario de Sousa
Slightly re-organized the code.
Miscelaneous cleanups
Removed layer1 functions (i.e. write and read to /dev/ttySx)
Added support for transaction id
TODO
add retries at layer2 (i.e. in this file)
check response frame for correctness
*
*
* Revision : v1.0
* Date : 11/2004 - F.Locci
* Objet : .remove static prefix into modbus_tcp_write() declaration
* to make code reentrant.
* .move global recv_buf_ to local one into read/write_bdata()
* Look at v1.0 comments
*
* Revision : v2.0
* Date : 11/2006 - F.Locci
* Objet : swap16 bits from SILECS client instead of application level
* Look at v2.0 comments
*/
#include <fcntl.h> /* File control definitions */
#include <stdio.h> /* Standard input/output */
#include <string.h>
#include <stdlib.h>
#include <termio.h> /* POSIX terminal control definitions */
#include <time.h> /* Time structures for select() */
#include <unistd.h> /* POSIX Symbolic Constants */
#include <errno.h> /* Error definitions */
#include <netinet/in.h> /* required for htons() and ntohs() */
#include "mb_layer1.h"
#include "mb_master.h"
#include "mb_master_private.h"
/*v1.0*/
#include "mb_tcp_private.h"
#ifdef __cplusplus
extern "C" {
#endif
/* #define DEBUG */ /* uncomment to see the data sent and received */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/******************************************/
/******************************************/
/** **/
/** Global Variables... **/
/** **/
/******************************************/
/******************************************/
/*v1.0
static u8 *query_buffer_ = NULL;
*/
#ifndef __Lynx__
#if RECV_BUFFER_SIZE < 5 //TCP_HEADER_LENGTH
#error The receive buffer is smaller than the frame header length.
#endif
#endif
/**/
/******************************************/
/******************************************/
/** **/
/** Local Utility functions... **/
/** **/
/******************************************/
/******************************************/
/*
* Function to determine next transaction id.
*
* We use a library wide transaction id, which means that we
* use a new transaction id no matter what slave to which we will
* be sending the request...
*/
static inline u16 next_transaction_id(void) {
static u16 next_id = 0;
return next_id++;
}
/*
* Functions to convert u16 variables
* between network and host byte order
*
* NOTE: Modbus uses MSByte first, just like
* tcp/ip, so we use the htons() and
* ntoh() functions to guarantee
* code portability.
*/
static inline u16 mb_hton(u16 h_value) {
/* return h_value; */
return htons(h_value);
}
static inline u16 mb_ntoh(u16 m_value) {
/* return m_value; */
return ntohs(m_value);
}
static inline u8 msb(u16 value) {
/* return Most Significant Byte of value; */
return (value >> 8) & 0xFF;
}
static inline u8 lsb(u16 value) {
/* return Least Significant Byte of value; */
return value & 0xFF;
}
#define u16_v(char_ptr) (*((u16 *)(&(char_ptr))))
/***********************************************************************
The following functions construct the required query into
a modbus query packet.
***********************************************************************/
static inline int build_query_packet(u8 slave,
u8 function,
u16 start_addr,
u16 count,
u8 *packet)
{
packet[ 0 ] = slave,
packet[ 1 ] = function;
/* NOTE:
* Modbus uses high level addressing starting off from 1, but
* this is sent as 0 on the wire!
*/
u16_v(packet[2]) = mb_hton(start_addr - 1);
u16_v(packet[4]) = mb_hton(count);
return 6;
}
/************************************************************************
read_bdata
F.Locci: just read raw byte array. Take care of frame which exceeds
modbus frame std. length.
*************************************************************************/
/*v2.0*/
#define swap16(w) ((((unsigned short)w & 0x00ff)<<8)+(((unsigned short)w & 0xff00)>>8))
int read_bdata(int slave, /* slave id */
int start_addr, /* word pointer addr. */
int count, /* byte count to read */
u8 *dest, /* byte array */
int ttyfd, /* connection id */
int send_retries, /* number of request retries */
const struct timespec *response_timeout) /* timeout value */
{
/*v1.0*/
u8 data[RECV_BUFFER_SIZE];
u8 packet[QUERY_BUFFER_SIZE];
/**/
int rl, response_length=0;
int query_length;
u16 send_transaction_id, recv_transaction_id;
u8 *destp = dest;
int global_length, length; /* word count for read */
/*Attention! ModBus travaille sur une zone memoire [1..n] tandis que l'espace memoire
du PLC est definie [0..n-1] => start_addr = start_addr +1
start_addr est exprime en word pour le PLC (alignement 16bits).
*/
start_addr+=1;
/*'global_length' is a word counter*/
global_length = (count/2) + (count%2);
while(count) {
if (count > MAX_READ_BDATA)
/*'length' is a word counter*/
length = MAX_READ_BDATA/2;
else
/*'length' is a word counter*/
length = (count/2) + (count%2);
/* We must also initialize the recv_transaction_id with the same value,
* since some layer 1 protocols do not support transaction id's, so
* simply return the recv_transaction_id variable without any changes...
*/
send_transaction_id = recv_transaction_id = next_transaction_id();
query_length = build_query_packet(slave, 0x03, /*function*/
start_addr, length,
packet);
if (query_length < 0)
return -1;
if (modbus_write(ttyfd, packet, query_length, send_transaction_id) < 0 )
return PORT_FAILURE;
rl = modbus_read(&ttyfd, data/*v1.0*/, &recv_transaction_id,
packet, query_length,
response_timeout);
if( rl <= 0 ) return PORT_FAILURE;
/* first check whther we have correct transaction id */
if (send_transaction_id != recv_transaction_id)
return PORT_FAILURE;
if( rl > 0 )
{ rl -= 3; /*F.Locci, bug: 2->3*/
if (count<MAX_READ_BDATA)
rl -= (count%2);
}
if( rl > 0 ) {
memcpy(destp, (u8 *)&(data[3]), rl);
destp += rl;
start_addr += length; /*F.Locci, bug if rl = 0 */
}
/* start_addr += length; F.Locci, bug if rl = 0 */
response_length += rl;
count -= rl;
}
/*v2.0:
Independamment de son mapping memoire (Little-endian), le PLC SCHNEIDER
swap chaque mot de 16bits qu'il transmet. Cette ligne permet de redresser
les donnees pour transmettre l'image exacte du mapping memoire. Charge
a l'application ensuite d'appliquer le swapping necessaire relatif a son
"Endianness".
*/
{
int j;
u16 *wdestp = (u16 *)dest; /* for swapping 16bit */
for(j=0; j<global_length; j++){ wdestp[j] = swap16(wdestp[j]); }
}
/**/
#ifdef DEBUG
{ int i;
printf("read_bdata: ");
for(i=0; i<response_length; printf("%02x ", dest[i++]));
printf("\n");
}
#endif
return response_length;
}
/*************************************************************************
write_bdata
F.Locci: just write raw byte array. Take care of frame which exceeds
modbus frame std. length.
!!byte count MUST be even value - 16 bits alignment in that PLC
***************************************************************************/
int write_bdata(int slave, /* slave id */
int start_addr, /* word pointer addr. */
int count, /* byte count to write - MUST be even value */
u8 *data, /* byte array */
int ttyfd, /* connection id */
int send_retries, /* number of request retries */
const struct timespec *response_timeout) /* timeout value */
{
int byte_count;
int i, rl, response_length=0;
int query_length;
/*v1.0*/
u8 rdata[RECV_BUFFER_SIZE];
u8 packet[QUERY_BUFFER_SIZE];
u16 send_transaction_id, recv_transaction_id;
int length; /* word count */
u8 *destp, *srcp = data;
/*Attention! ModBus travaille sur une zone memoire [1..n] tandis que l'espace memoire
du PLC est definie [0..n-1] => start_addr = start_addr +1
start_addr est exprime en word pour le PLC (alignement 16bits).
*/
start_addr+=1;
while(count) {
if (count > MAX_WRITE_BDATA)
{
/*'length' is a word counter*/
length = MAX_WRITE_BDATA/2;
}
else
{
/*'length' is a word counter*/
length = (count/2) + (count%2);
}
/* We must also initialize the recv_transaction_id with the same value,
* since some layer 1 protocols do not support transaction id's, so
* simply return the recv_transaction_id variable without any changes...
*/
send_transaction_id = recv_transaction_id = next_transaction_id();
query_length = build_query_packet(slave, 0x10 /* function */,
start_addr, length,
packet);
if (query_length < 0)
return -1;
byte_count = (length * 2);
packet[ query_length ] = byte_count;
destp = &(packet[ ++query_length ]);
memcpy(destp, srcp, byte_count-(count%2));
/*v2.0:
Independamment de son mapping memoire (Little-endian), le PLC SCHNEIDER
swap chaque mot de 16bits qu'il transmet. Cette ligne permet de redresser
les donnees pour transmettre l'image exacte du mapping memoire. Charge
a l'application ensuite d'appliquer le swapping necessaire relatif a son
"Endianness".
*/
{
u16 *wdestp = (u16 *)destp;
for(i=0; i<length; i++){ wdestp[i] = swap16(wdestp[i]); }
}
/**/
srcp += byte_count-(count%2);
query_length += byte_count;
if( modbus_write( ttyfd, packet, query_length, send_transaction_id) < 0 )
return PORT_FAILURE;
rl = modbus_read(&ttyfd, rdata/*v1.0*/, &recv_transaction_id,
packet, query_length, response_timeout);
if( rl <= 0 ) return PORT_FAILURE;
/* first check whther we have correct transaction id */
if (send_transaction_id != recv_transaction_id)
return PORT_FAILURE;
start_addr += length;
response_length += byte_count;
count -= (byte_count - (count%2));
}
return response_length;
}
/************************************************************************
initialise / shutdown the library
These functions sets up/shut down the library state
(allocate memory for buffers, initialise data strcutures, etc)
**************************************************************************/
int mb_master_init(int nd_count) {
int extra_bytes;
#ifdef DEBUG
fprintf( stderr, "mb_master_init()\n");
fprintf( stderr, "creating %d nodes\n", nd_count);
#endif
/* initialise layer 1 library */
if (modbus_init(nd_count, DEF_OPTIMIZATION, &extra_bytes)
< 0)
goto error_exit_0;
/*v1.0 initialise send buffer
query_buffer_ = (u8 *)malloc(QUERY_BUFFER_SIZE + extra_bytes);
if (query_buffer_ == NULL)
goto error_exit_1;
*/
return 0;
error_exit_0:
return -1;
}
int mb_master_done(void) {
/*v1.0
free(query_buffer_);
query_buffer_ = NULL;
*/
return modbus_done();
}
/************************************************************************
open/close master connection
This function opens/closes a connection to the remote slave.
**************************************************************************/
int mb_master_connect(node_addr_t node_addr) {
#ifdef DEBUG
fprintf( stderr, "mb_master_connect()\n");
#endif
/* call layer 1 library */
return modbus_connect(node_addr);
}
int mb_master_close(int nd) {
#ifdef DEBUG
fprintf( stderr, "mb_master_close(): nd = %d\n", nd);
#endif
/* call layer 1 library */
return modbus_close(nd);
}
#ifdef __cplusplus
}
#endif
/* modbus_rtu.h
By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au
These library of functions are designed to enable a program send and
receive data from a device that communicates using the Modbus protocol.
Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The functions included here have been derived from the
Modicon Modbus Protocol Reference Guide
which can be obtained from Schneider at www.schneiderautomation.com.
This code has its origins with
paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk)
who wrote a small program to read 100 registers from a modbus slave.
I have used his code as a catalist to produce this more functional set
of functions. Thanks paul.
*/
#ifndef MODBUS_MASTER_H
#define MODBUS_MASTER_H
#ifdef __cplusplus
extern "C" {
#endif
/*F.Locci #include <plc.h>*/ /* get the plc data types */
#include <time.h> /* struct timespec data structure */
#include "mb_addr.h" /* get definition of common variable types */
/***********************************************************************
Note: All functions used for sending or receiving data via
modbus return these return values.
Returns: string_length if OK
0 if failed
Less than 0 for exception errors
***********************************************************************/
/*F.Locci: error constants adjustement to be SILECS conformed
#define COMMS_FAILURE 0
#define ILLEGAL_FUNCTION -1
#define ILLEGAL_DATA_ADDRESS -2
#define ILLEGAL_DATA_VALUE -3
#define SLAVE_DEVICE_FAILURE -4
#define ACKNOWLEDGE -5
#define SLAVE_DEVICE_BUSY -6
#define NEGATIVE_ACKNOWLEDGE -7
#define MEMORY_PARITY_ERROR -8
#define PORT_FAILURE -11
*/
#define PORT_FAILURE -3
/************************************************************************
read_bdata
F.Locci: just read raw byte array. Take care of frame longer than
125 words.
*************************************************************************/
#define MAX_READ_BDATA 200
int read_bdata(int slave, /* slave id */
int start_addr, /* word pointer addr. */
int count, /* byte count to read */
u8 *dest, /* byte array */
int ttyfd, /* connection id */
int send_retries, /* number of request retries */
const struct timespec *response_timeout); /* timeout value */
/*************************************************************************
write_bdata
F.Locci: just write raw byte array. Take care of frame which exceeds
modbus frame std. length.
!!byte count MUST be even value - 16 bits alignment in that PLC
***************************************************************************/
#define MAX_WRITE_BDATA 200
int write_bdata(int slave, /* slave id */
int start_addr, /* word pointer addr. */
int count, /* byte count to write - MUST be even value */
u8 *data, /* byte array */
int ttyfd, /* connection id */
int send_retries, /* number of request retries */
const struct timespec *response_timeout); /* timeout value */
/************************************************************************
initialise
This function sets up the libraries
(allocate memory for buffers, initialise data strcutures, etc)
**************************************************************************/
int mb_master_init(int nd_count);
int mb_master_done(void);
/***************************************************************************
set_up_comms
This function sets up (closes) a connection to a remote modbus
slave.
***************************************************************************/
int mb_master_connect(node_addr_t node_addr);
int mb_master_close(int nd);
#ifdef __cplusplus
}
#endif
#endif /* MODBUS_MASTER_H */
/*
* (c) 2002 Mario de Sousa
*
* Offered to the public under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
#ifndef MODBUS_MASTER_PRIVATE_H
#define MODBUS_MASTER_PRIVATE_H
/*F.Locci #include <plc.h>*/ /* get the plc data types */
#include "mb_util.h"
#include "mb_master.h"
#define QUERY_BUFFER_SIZE MAX_L2_FRAME_LENGTH
#define DEF_LAYER2_SEND_RETRIES 1
#define DEF_IGNORE_ECHO 0
#define DEF_OPTIMIZATION optimize_speed
#endif /* MODBUS_MASTER_PRIVATE_H */
/*
* (c) 2002 Mario de Sousa
*
* Offered to the public under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
#ifndef MODBUS_TCP_PRIVATE_H
#define MODBUS_TCP_PRIVATE_H
/*F.Locci #include <plc.h>*/ /* get the plc data types */
#include "mb_util.h"
/* tcp port default configuration... */
#define DEF_SERVICE "502" /* port used by modbus */
#define DEF_PROTOCOL "tcp" /* protocol used by modbus tcp */
#define DEF_TYPE SOCK_STREAM /* Quality of service required of the socket... */
#define DEF_MAX_PENDING_CONNECTION_REQUESTS 5
/* maximum number of pending connection requests
* that have not yet been accept()'ed
*/
#define DEF_CLOSE_ON_SILENCE 1 /* Used only by master nodes.
* Flag indicating whether, by default, the connection
* to the slave device should be closed whenever the
* modbus_tcp_silence_init() function is called.
*
* 0 -> do not close connection
* >0 -> close connection
*
* The spec sugests that connections that will not
* be used for longer than 1 second should be closed.
* Even though we expect most connections to have
* silence intervals much shorted than 1 second, we
* decide to use the default of shuting down the
* connections because it is safer, and most other
* implementations seem to do the same.
* If we do not close we risk using up all the possible
* connections that the slave can simultaneouly handle,
* effectively locking out every other master that
* wishes to communicate with that same slave.
*/
/* Since the receive buffer is also re-used to store the frame header,
* we set it to the larger of the two.
*/
#ifndef __Lynx__
#if TCP_HEADER_LENGTH > MAX_L2_FRAME_LENGTH
#define RECV_BUFFER_SIZE TCP_HEADER_LENGTH
#else
#define RECV_BUFFER_SIZE MAX_L2_FRAME_LENGTH
#endif
#else
#if defined(TCP_HEADER_LENGTH) > defined(MAX_L2_FRAME_LENGTH)
#define RECV_BUFFER_SIZE TCP_HEADER_LENGTH
#else
#define RECV_BUFFER_SIZE MAX_L2_FRAME_LENGTH
#endif
#endif
#endif /* MODBUS_TCP_PRIVATE_H */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment