Documentation

FieldTalk Modbus Slave C++ Library  Library version 2.11.0
Examples

Serial Example

The following example tinyslave.cpp shows how to implement a small Modbus RTU slave:

// HM platform detection
#include "hmplatf.h"
// Platform header
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Include FieldTalk package header
#include "MbusRtuSlaveProtocol.hpp"
/*****************************************************************************
* Gobal data
*****************************************************************************/
#if defined(__WIN32__)
const TCHAR *portName = TEXT("COM1");
#elif defined(__LINUX__)
const char *portName = "/dev/ttyS0";
#elif defined(__MACOSX__)
const char *portName = "/dev/ttys0";
#elif defined(__FREEBSD__) || defined(__NETBSD__) || defined(__OPENBSD__)
const char *portName = "/dev/ttyd0";
#elif defined(__QNX__)
const char *portName = "/dev/ser1";
#elif defined(__VXWORKS__)
const char *portName = "/tyCo/0";
#elif defined(__SOLARIS__)
const char *portName = "/dev/ttya";
#elif defined(__IRIX__)
const char *portName = "/dev/ttyf1";
#elif defined(__OSF__)
const char *portName = "/dev/tty00";
#else
const char *portName = "/dev/tty";
#endif
/*****************************************************************************
* Modbus data table
*****************************************************************************/
typedef struct
{
short actTemp; // Register 1
short minTemp; // Register 2
long scanCounter; // Register 3 and 4
float setPoint; // Register 5 and 6
short statusReg; // Register 7
short configType; // Register 8
} MyDeviceData;
MyDeviceData deviceData;
/*****************************************************************************
* Data provider
*****************************************************************************/
class MyDataProvider: public MbusDataTableInterface
{
public:
int readHoldingRegistersTable(int startRef, short regArr[], int refCnt)
{
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > int(sizeof(deviceData) / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(regArr, &((short *) &deviceData)[startRef],
refCnt * sizeof(short));
return 1;
}
int writeHoldingRegistersTable(int startRef,
const short regArr[],
int refCnt)
{
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > int(sizeof(deviceData) / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(&((short *) &deviceData)[startRef],
regArr, refCnt * sizeof(short));
return 1;
}
} dataProvider;
/*****************************************************************************
* Modbus protocol declaration
*****************************************************************************/
/*****************************************************************************
* Function implementation
*****************************************************************************/
void startupServer()
{
int result;
result = mbusServer.addDataTable(1, &dataProvider);
if (result == FTALK_SUCCESS)
result = mbusServer.startupServer(portName,
19200L, // Baudrate
8, // Databits
1, // Stopbits
2); // Even parity
if (result != FTALK_SUCCESS)
{
fprintf(stderr, "Error starting server: %s!\n",
exit(EXIT_FAILURE);
}
}
void shutdownServer()
{
mbusServer.shutdownServer();
}
void runServer()
{
int result = FTALK_SUCCESS;
while (result == FTALK_SUCCESS)
{
result = mbusServer.serverLoop();
if (result != FTALK_SUCCESS)
fprintf(stderr, "%s!\n", getBusProtocolErrorText(result));
}
}
#if defined(_WIN32_WCE)
int wmain()
#else
int main()
#endif
{
atexit(shutdownServer);
startupServer();
runServer();
return EXIT_FAILURE;
}

MODBUS/TCP Example

The following example tcpslave.cpp shows how to implement a small Modbus/TCP slave:

// Platform header
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Include FieldTalk package header
#include "MbusTcpSlaveProtocol.hpp"
/*****************************************************************************
* Modbus data table
*****************************************************************************/
typedef struct
{
short actTemp; // Register 1
short minTemp; // Register 2
long scanCounter; // Register 3 and 4
float setPoint; // Register 5 and 6
short statusReg; // Register 7
short configType; // Register 8
} MyDeviceData;
MyDeviceData deviceData;
/*****************************************************************************
* Data provider
*****************************************************************************/
const char* VENDOR_NAME = "proconX Pty Ltd";
const char* PRODUCT_CODE = "FT-MBSV";
const char* VENDOR_URL = "http://www.modbusdriver.com";
const char* PRODUCT_NAME = "FieldTalk";
const char* MODEL_NAME = "Modbus Slave C++ Library";
const char* USER_APPLICATION_NAME = "diagslave";
class MyDataProvider: public MbusDataTableInterface
{
public:
void printHello()
{
printf("Hello!\n");
}
int readHoldingRegistersTable(int startRef, short regArr[], int refCnt)
{
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > int(sizeof(deviceData) / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(regArr, &((short *) &deviceData)[startRef],
refCnt * sizeof(short));
return 1;
}
int writeHoldingRegistersTable(int startRef,
const short regArr[],
int refCnt)
{
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > int(sizeof(deviceData) / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(&((short *) &deviceData)[startRef],
regArr, refCnt * sizeof(short));
return 1;
}
int readDeviceIdentification(int objId, char bufferArr[], int maxBufSize)
{
switch (objId)
{
//
// VendorName
//
case 0:
if (bufferArr)
{
#ifdef HAS_STRNCPY
strncpy(bufferArr, VENDOR_NAME, maxBufSize);
#else
strcpy(bufferArr, VENDOR_NAME);
#endif
}
return strlen(VENDOR_NAME);
//
// ProductCode
//
case 1:
if (bufferArr)
{
#ifdef HAS_STRNCPY
strncpy(bufferArr, PRODUCT_CODE, maxBufSize);
#else
strcpy(bufferArr, PRODUCT_CODE);
#endif
}
return strlen(PRODUCT_CODE);
//
// MajorMinorRevision
//
case 2:
if (bufferArr)
{
#ifdef HAS_STRNCPY
strncpy(bufferArr, MbusSlaveServer::getPackageVersion(), maxBufSize);
#else
strcpy(bufferArr, MbusSlaveServer::getPackageVersion());
#endif
}
}
return 0; // Return 0 for object not found
}
} dataProvider;
/*****************************************************************************
* Modbus protocol declaration
*****************************************************************************/
/*****************************************************************************
* Function implementation
*****************************************************************************/
int masterPollEvent(const char* masterIpAddrSz)
{
printf("masterPollEvent for %s!\n", masterIpAddrSz);
return 1;
}
void masterDisconnectEventOld(const char* masterIpAddrSz)
{
printf("masterDisconnectEvent for %s!\n", masterIpAddrSz);
}
void masterDisconnectEventNew(const char* masterIpAddrSz, void* userData)
{
printf("masterDisconnectEvent for %s!\n", masterIpAddrSz);
((MyDataProvider*)userData)->printHello();
}
void startupServer()
{
int result;
mbusServer.setTimeout(3000); // 3 sec activity time-out
mbusServer.setConnectionTimeOut(10000); // 10 s connection time-out
mbusServer.installMasterPollNotifyCallBack(masterPollEvent);
mbusServer.installMasterDisconnectCallBack(masterDisconnectEventOld);
//mbusServer.installMasterDisconnectCallBack(masterDisconnectEventNew, (void*)&dataProvider);
result = mbusServer.addDataTable(1, &dataProvider); // Unit ID is 1
if (result == FTALK_SUCCESS)
result = mbusServer.startupServer();
if (result != FTALK_SUCCESS)
{
fprintf(stderr, "Error starting server: %s!\n",
exit(EXIT_FAILURE);
}
}
void shutdownServer()
{
mbusServer.shutdownServer();
}
void runServer()
{
int result = FTALK_SUCCESS;
while (result == FTALK_SUCCESS)
{
result = mbusServer.serverLoop();
if (result != FTALK_SUCCESS)
fprintf(stderr, "%s!\n", getBusProtocolErrorText(result));
}
}
#if defined(_WIN32_WCE)
int wmain()
#else
int main()
#endif
{
atexit(shutdownServer);
startupServer();
runServer();
return EXIT_FAILURE;
}

Shared Memory Data Provider example

The following example shows how to implement a Data Provider which serves it's data from shared memory:

class ShmemMbusDataTable: public MbusDataTableInterface
{
public:
ShmemMbusDataTable(int table0Size, int table1Size, int table3Size, int table4Size)
{
int i;
int fd;
for (i = 0; i < 5; i++)
{
//
// Determine table sizes
//
switch (i)
{
case 0:
if (table0Size <= 0)
break; // No table will be created for this type
dataTableArr[i].size = table0Size * sizeof(char);
break;
case 1:
if (table1Size <= 0)
break; // No table will be created for this type
dataTableArr[i].size = table1Size * sizeof(char);
break;
case 2:
dataTableArr[i].size = sizeof(SlaveStatusInfo);
break;
case 3:
if (table3Size <= 0)
break; // No table will be created for this type
dataTableArr[i].size = table3Size * sizeof(short);
break;
case 4:
if (table4Size <= 0)
break; // No table will be created for this type
dataTableArr[i].size = table4Size * sizeof(short);
break;
}
//
// Open shared memory tables
//
shm_unlink(dataTableArr[i].name);
if (dataTableArr[i].size == 0)
continue;
fd = shm_open(dataTableArr[i].name, O_CREAT | O_RDWR | O_EXCL, S_IRWXU);
if (fd < 0)
{
perror("Shared memory open failed");
abort();
}
//
// Size it
//
if (ftruncate(fd, dataTableArr[i].size) < 0)
{
perror("Shared memory ftruncate failed");
abort();
}
//
// Map shared memory into address space
//
dataTableArr[i].ptr = (short *) mmap(0, dataTableArr[i].size,
PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0L);
if (dataTableArr[i].ptr == NULL)
{
perror("Shared memory mmap failed");
abort();
}
close (fd); // No we can close the file descriptor
memset(dataTableArr[i].ptr, 0, dataTableArr[i].size);
}
//
// Handle special cases where we map table 3 to point to table 4 and
// table 1 to point to table 0
//
if (table3Size == -1) // Map table 3 to table 4
{
dataTableArr[3].size = dataTableArr[4].size;
dataTableArr[3].ptr = dataTableArr[4].ptr;
}
if (table1Size == -1) // Map table 1 to table 0
{
dataTableArr[1].size = dataTableArr[0].size;
dataTableArr[1].ptr = dataTableArr[0].ptr;
}
// Setup pointer to status table
slaveStatusInfoPtr = (SlaveStatusInfo *) dataTableArr[2].ptr;
}
~ShmemMbusDataTable()
{
int i;
for (i = 0; i < 5; i++)
{
if (dataTableArr[i].ptr != NULL)
{
munmap(dataTableArr[i].ptr, dataTableArr[i].size);
shm_unlink(dataTableArr[i].name);
}
}
}
void timeOutHandler()
{
slaveStatusInfoPtr->timeoutCnt++;
}
int readInputDiscretesTable(int startRef,
char bitArr[],
int refCnt)
{
printf("\nreadInputDiscretesTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[1].size / sizeof(char)))
return 0;
//
// Copy data
//
memcpy(bitArr, &((char *) dataTableArr[1].ptr)[startRef], refCnt * sizeof(char));
slaveStatusInfoPtr->readDiscretesCnt++;
return 1;
}
int readCoilsTable(int startRef,
char bitArr[],
int refCnt)
{
printf("\nreadCoilsTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[0].size / sizeof(char)))
return 0;
//
// Copy data
//
memcpy(bitArr, &((char *) dataTableArr[0].ptr)[startRef], refCnt * sizeof(char));
slaveStatusInfoPtr->readDiscretesCnt++;
return 1;
}
int writeCoilsTable(int startRef,
const char bitArr[],
int refCnt)
{
printf("\nriteCoilsTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[0].size / sizeof(char)))
return 0;
//
// Copy data
//
memcpy(&((char *) dataTableArr[0].ptr)[startRef], bitArr, refCnt * sizeof(char));
slaveStatusInfoPtr->writeDiscretesCnt++;
return 1;
}
int readInputRegistersTable(int startRef,
short regArr[],
int refCnt)
{
printf("\nreadInputRegistersTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[3].size / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(regArr, &((short *) dataTableArr[3].ptr)[startRef], refCnt * sizeof(short));
slaveStatusInfoPtr->readRegistersCnt++;
return 1;
}
int readHoldingRegistersTable(int startRef,
short regArr[],
int refCnt)
{
printf("\nreadHoldingRegistersTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[4].size / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(regArr, &((short *) dataTableArr[4].ptr)[startRef], refCnt * sizeof(short));
slaveStatusInfoPtr->readRegistersCnt++;
return 1;
}
int writeHoldingRegistersTable(int startRef,
const short regArr[],
int refCnt)
{
printf("\nwriteHoldingRegistersTable: %d, %d\n", startRef, refCnt);
// Adjust Modbus reference counting
startRef--;
//
// Validate range
//
if (startRef + refCnt > (int) (dataTableArr[4].size / sizeof(short)))
return 0;
//
// Copy data
//
memcpy(&((short *) dataTableArr[4].ptr)[startRef], regArr, refCnt * sizeof(short));
slaveStatusInfoPtr->writeRegistersCnt++;
return 1;
}
private:
SlaveStatusInfo *slaveStatusInfoPtr;
};