FieldTalk Modbus® Slave Library
C++ Editions
FOCUS Software Engineering

Main Page | Modules | Class Hierarchy | Class List | Class Members | Related Pages

How to integrate the Protocol in your Application

Using Serial Protocols

Let's assume we want to implement a Modbus slave device with slave address 1.

The registers for reading are in the reference range 4:00100 to 4:00119 and the registers for writing are in the range 4:00200 to 4:00219. The discretes for reading are in the reference range 0:00010 to 0:00019 and the discretes for writing are in the range 0:00020 to 0:00029.

1. Include the package header files

#include "MbusRtuSlaveProtocol.hpp"

2. Device data profile definition

Define the data sets which reflects the slave's data profile by type and size:

short readRegSet[20];
short writeRegSet[20];
char readBitSet[10];
char writeBitSet[10];

3. Declare a Data Provider

class MyDataProvider: public MbusDataTableInterface
{

  public:

   int readHoldingRegistersTable(int startRef, short regArr[], int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for reading is at 100, so deduct offset
      startRef -= 100;

      // Validate range
      if (startRef + refCnt > (int) sizeof(readRegSet) / sizeof(short))
         return (0);

      // Copy data
      memcpy(regArr, &readRegSet[startRef], refCnt * sizeof(short));
      return (1);
   }


   int writeHoldingRegistersTable(int startRef,
                                  const short regArr[],
                                  int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for writing is at 200, so deduct offset
      startRef -= 200;

      // Validate range
      if (startRef + refCnt > (int) sizeof(writeRegSet) / sizeof(short))
         return (0);

      // Copy data
      memcpy(&writeRegSet[startRef], regArr, refCnt * sizeof(short));
      return (1);
   }


   int readCoilsTable(int startRef,
                      char bitArr[],
                      int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for reading is at 10, so deduct offset
      startRef -= 10;

      // Validate range
      if (startRef + refCnt > (int) sizeof(readBitSet) / sizeof(char))
         return (0);

      // Copy data
      memcpy(bitArr, &readBitSet[startRef], refCnt * sizeof(char));
      return (1);
   }


   int writeCoilsTable(int startRef,
                       const char bitArr[],
                       int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for writing is at 20, so deduct offset
      startRef -= 20;

      // Validate range
      if (startRef + refCnt > (int) sizeof(writeBitSet) / sizeof(char))
         return (0);

      // Copy data
      memcpy(&writeBitSet[startRef], bitArr, refCnt * sizeof(char));
      return (1);
   }

} dataProvider;

4. Declare and instantiate a server object and associate it with the Data Provider

MbusRtuSlaveProtocol mbusServer;
mbusServer.addDataTable(1, &dataProvider);

5. Start-up the server

   int result;

   result = mbusServer.startupServer(portName,
                                     9600L, // Baudrate
                                     8,     // Databits
                                     1,     // Stopbits
                                     0);    // Parity
   if (result != FTALK_SUCCESS)
   {
      fprintf(stderr, "Error starting server: %s!\n",
              getBusProtocolErrorText(result));
      exit(EXIT_FAILURE);
   }

6. Execute cyclically the server loop

   int result = FTALK_SUCCESS;

   while (result == FTALK_SUCCESS)
   {
      result = mbusServer.serverLoop();
      if (result != FTALK_SUCCESS)
         fprintf(stderr, "%s!\n", getBusProtocolErrorText(result));
   }

7. Shutdown the server if not needed any more

mbusServer.shutdownServer();

Using MODBUS/TCP Protocol

Let's assume we want to implement a Modbus slave device with slave address 1.

The registers for reading are in the reference range 4:00100 to 4:00119 and the registers for writing are in the range 4:00200 to 4:00219. The discretes for reading are in the reference range 0:00010 to 0:00019 and the discretes for writing are in the range 0:00020 to 0:00029.

1. Include the package header files

#include "MbusTcpSlaveProtocol.hpp"

2. Device data profile definition

Define the data sets which reflects the slave's data profile by type and size:

short readRegSet[20];
short writeRegSet[20];
char readBitSet[10];
char writeBitSet[10];

3. Declare a Data Provider

class MyDataProvider: public MbusDataTableInterface
{

  public:

   int readHoldingRegistersTable(int startRef, short regArr[], int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for reading is at 100, so deduct offset
      startRef -= 100;

      // Validate range
      if (startRef + refCnt > (int) sizeof(readRegSet) / sizeof(short))
         return (0);

      // Copy data
      memcpy(regArr, &readRegSet[startRef], refCnt * sizeof(short));
      return (1);
   }


   int writeHoldingRegistersTable(int startRef,
                                  const short regArr[],
                                  int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for writing is at 200, so deduct offset
      startRef -= 200;

      // Validate range
      if (startRef + refCnt > (int) sizeof(writeRegSet) / sizeof(short))
         return (0);

      // Copy data
      memcpy(&writeRegSet[startRef], regArr, refCnt * sizeof(short));
      return (1);
   }


   int readCoilsTable(int startRef,
                      char bitArr[],
                      int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for reading is at 10, so deduct offset
      startRef -= 10;

      // Validate range
      if (startRef + refCnt > (int) sizeof(readBitSet) / sizeof(char))
         return (0);

      // Copy data
      memcpy(bitArr, &readBitSet[startRef], refCnt * sizeof(char));
      return (1);
   }


   int writeCoilsTable(int startRef,
                       const char bitArr[],
                       int refCnt)
   {
      // Adjust Modbus reference counting
      startRef--;

      // Our start address for writing is at 20, so deduct offset
      startRef -= 20;

      // Validate range
      if (startRef + refCnt > (int) sizeof(writeBitSet) / sizeof(char))
         return (0);

      // Copy data
      memcpy(&writeBitSet[startRef], bitArr, refCnt * sizeof(char));
      return (1);
   }

} dataProvider;

4. Declare and instantiate a server object and associate it with the Data Provider and the slave address.

MbusTcpSlaveProtocol mbusServer();
mbusServer.addDataTable(1, &dataProvider);

5. Change the default port from 502 to semething else if server shall not run as root. This step is not necessary when the server can run with root privilege.

   mbusServer.setPort(5000);

6. Start-up the server

   int result;

   result = mbusServer.startupServer();
   if (result != FTALK_SUCCESS)
   {
      fprintf(stderr, "Error starting server: %s!\n",
              getBusProtocolErrorText(result));
      exit(EXIT_FAILURE);
   }

7. Execute cyclically the server loop

   int result = FTALK_SUCCESS;

   while (result == FTALK_SUCCESS)
   {
      result = mbusServer.serverLoop();
      if (result != FTALK_SUCCESS)
         fprintf(stderr, "%s!\n", getBusProtocolErrorText(result));
   }

8. Shutdown the server if not needed any more

mbusServer.shutdownServer();

Examples