ioPAC RTU Controllers
C/C++ Sample Code Programming Guide
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Data Structures | Macros | Typedefs | Functions | Variables
modbus_tcp_slave.c File Reference

Modbus TCP Slave Sample Application More...

#include <libmoxa_rtu.h>

Data Structures

struct  _MODBUS_MAP
 

Macros

#define MODBUS_TCP_PORT   502
 
#define MODBUS_TCP_TIMEOUT   1000
 
#define DIM(x)   (sizeof(x)/sizeof(x[0]))
 

Typedefs

typedef struct _MODBUS_MAP MODBUS_MAP
 
typedef struct _MODBUS_MAPpMODBUS_MAP
 

Functions

int modbusSlaveInit (int port, UINT32 *pHandle)
 
int modbusSlaveUninit (UINT32 *pHandle)
 
int main (int argc, char **const argv)
 

Variables

MODBUS_MAP ModbusMap []
 

Detailed Description

Modbus TCP Slave Sample Application

Date
03-27-2013
Author
Wanhan Hsieh
Version
V1.0
modbus_tcp.jpg
Modbus TCP Slave Sample Application
Introduction:
The Modbus Slave creates two Modbus addresses, one for DIs (input register) and one for DOs (holding register).
Then, the Modbus Master polls for DI values and sets the DO statuses equal to the DI values.
Both the Slave and the Master use Moxa Modbus APIs (modbus_tcp_slave and modbus_tcp_master).
Example:
1. Using default: ./modbus_tcp_slave
2. Setting port: ./modbus_tcp_slave -p1234
Default:
DI Slot = 1
DO Slot = 2
Port of Modbus TCP Slave = 502
Help:
root@Moxa:/tmp#./modbus_tcp_slave -h
Modbus TCP Slave sample program.

Usage: ./modbus_tcp_slave [OPTIONS]

Get DI value and set DO value

Options:
        -i       Slot of DI module [1-9]. Default slot = 1
        -s       Slot of DO module [1-9]. Default slot = 2
        -p       Port of Modbus TCP Slave. Default port = 502

Library:
ModbusTCPSlave APIs

Macro Definition Documentation

#define MODBUS_TCP_PORT   502
#define MODBUS_TCP_TIMEOUT   1000
#define DIM (   x)    (sizeof(x)/sizeof(x[0]))

Typedef Documentation

typedef struct _MODBUS_MAP MODBUS_MAP
typedef struct _MODBUS_MAP * pMODBUS_MAP

Function Documentation

int modbusSlaveInit ( int  port,
UINT32 pHandle 
)
int modbusSlaveUninit ( UINT32 pHandle)
int main ( int  argc,
char **const  argv 
)
/*******************************************************************************
* Copyright Moxa Inc.
*
* Modbus TCP Slave Sample Application
*
* Date Author Comment
* 03-27-2013 Wanhan Hsieh Created.
******************************************************************************/
#include <libmoxa_rtu.h>
#define MODBUS_TCP_PORT 502
#define MODBUS_TCP_TIMEOUT 1000
#define DIM(x) (sizeof(x)/sizeof(x[0]))
typedef struct _MODBUS_MAP
{
int (*pfnModRead)(UINT8 *pData, UINT16 nth, void *pUserData);
int (*pfnModWrite)(UINT8 *pData, UINT16 nth, void *pUserData);
static int getReg(UINT8 *pData, UINT16 nth, void *pUserData);
static int setReg(UINT8 *pData, UINT16 nth, void *pUserData);
{
{ MODBUS_INPUT_REGISTER, 0x0800, getReg, NULL, 0xFFFF },
{ MODBUS_HOLDING_REGISTER, 0x0810, getReg, setReg, 0xFFFF },
};
static int getReg(UINT8 *pData, UINT16 nth, void *pUserData)
{
UINT16 data = 0;
char *ptr = (char *)&data;
pMODBUS_MAP info = (pMODBUS_MAP)pUserData;
data = info->reg;
pData[nth * 2] = ptr[1];
pData[nth * 2 + 1] = ptr[0];
return RETURN_OK;
}
static int setReg(UINT8 *pData, UINT16 nth, void *pUserData)
{
UINT16 value = MAKE_WORD(pData[nth * 2], pData[nth * 2 + 1]);
pMODBUS_MAP info = (pMODBUS_MAP)pUserData;
info->reg = value;
return RETURN_OK;
}
int modbusSlaveInit(int port, UINT32 *pHandle)
{
int rc = 0;
int mapSize = DIM(ModbusMap);
int idleTimeoutMS = MODBUS_TCP_TIMEOUT;
UINT16 count = 0;
int i, j;
{
printf("MX_RTU_Modbus_Tcp_Slave_Init(), return code = %d.\n", rc);
}
else
{
rc = MX_RTU_Modbus_Tcp_Slave_Register(port, mapSize, idleTimeoutMS, pHandle);
printf("MX_RTU_Modbus_Tcp_Slave_Register(%d, %d, %d), return code = %d.\n",
port, mapSize, idleTimeoutMS, rc);
// Init modbus entries
for(i = 0; i < DIM(ModbusMap); i++)
{
rc = MX_RTU_Modbus_Tcp_Slave_Add_Entry(*pHandle, ModbusMap[i].slave_group,
ModbusMap[i].slave_addr, &ModbusMap[i], ModbusMap[i].pfnModRead,
ModbusMap[i].pfnModWrite);
{
printf("MX_RTU_Modbus_Tcp_Slave_Add_Entry(), return code = %d.\n", rc);
break;
}
}
}
return rc;
}
{
int rc = 0;
printf("MX_RTU_Modbus_Tcp_Slave_Unregister(%d), return code = %d.\n",
*pHandle, rc);
printf("MX_RTU_Modbus_Tcp_Slave_Uninit(), return code = %d.\n", rc);
}
/*******************************************************************************
*
* Sample code for Modbus TCP Slave
*
******************************************************************************/
int main(int argc, char **const argv)
{
int rc, i;
int port = MODBUS_TCP_PORT;
UINT32 handle;
int mapSize = DIM(ModbusMap);
int idleTimeoutMS = MODBUS_TCP_TIMEOUT;
UINT16 count = 0;
UINT32 diSlot = 1;
UINT32 doSlot = 2, slotMin = 1, slotMax = 0;
int diChannelAmount = 16;
int doChannelAmount = 16;
UINT32 *pDIValue;
UINT32 *pDOValue;
UINT32 lastDOValue;
struct Modbus_TCP_Master_Connection_Info connectionInfo;
int connectionAmount = 0;
while(-1 != (rc = getopt(argc, argv, "hi:s:p:")))
{
switch(rc)
{
case 'i':
diSlot = atoi(optarg);
if(diSlot < slotMin || diSlot > slotMax)
{
printf("Error parameter: slot: %d\n", diSlot);
return -1;
}
break;
case 's':
doSlot = atoi(optarg);
if(doSlot < slotMin || doSlot > slotMax)
{
printf("Error parameter: slot: %d\n", doSlot);
return -1;
}
break;
case 'p':
port = atoi(optarg);
if(port < 0)
{
printf("Error parameter: port: %d\n", port);
return -1;
}
break;
case '?':
case 'h':
default:
printf("Modbus TCP Slave sample program.\n\n");
printf("Usage: ./modbus_tcp_slave [OPTIONS]\n\n");
printf("Get DI value and set DO value\n\n");
printf("Options:\n");
printf("\t%-8s Slot of DI module [%d-%d]. Default slot = %d\n",
"-i", slotMin, slotMax, diSlot);
printf("\t%-8s Slot of DO module [%d-%d]. Default slot = %d\n",
"-s", slotMin, slotMax, doSlot);
printf("\t%-8s Port of Modbus TCP Slave. Default port = %d\n",
"-p", port);
printf("\n");
return;
}
}
printf("%-10s: %d\n", "DI slot", diSlot);
printf("%-10s: %d\n", "DO slot", doSlot);
printf("%-10s: %d\n", "TCP port", port);
// Init modbus slave
rc = modbusSlaveInit(port, &handle);
printf("ModbusSlaveInit(%d), return code = %d.\n\n", port, rc);
rc = MX_RTU_Modbus_Tcp_Slave_Map_Count(handle, &count);
printf("MX_RTU_Modbus_Tcp_Slave_Map_Count(%d), return code = %d.\n\n", handle, rc);
else
printf("Entry count = %d\n", count);
printf("MX_RTU_Modbus_Tcp_Slave_Map_Dump(%d), return code = %d.\n\n", handle, rc);
printf("MX_RTU_Modbus_Tcp_Slave_Start(%d), return code = %d.\n", handle, rc);
pDIValue = &(ModbusMap[0].reg);
pDOValue = &(ModbusMap[1].reg);
lastDOValue = *pDOValue;
// Config DO module
rc = MX_RTU_Module_DO_Value_Set(doSlot, *pDOValue);
if(rc != MODULE_RW_ERR_OK)
printf("MX_RTU_Module_DO_Value_Set(%d, 0x%04X), return code = %d.\n",
doSlot, *pDOValue, rc);
printf("\nModbus Server is running... port: %d\n\n", port);
// Start to polling DI and set DO
while(1)
{
rc = MX_RTU_Module_DI_Value_Get(diSlot, pDIValue, NULL);
if(rc != MODULE_RW_ERR_OK)
{
printf("MX_RTU_Module_DI_Value_Get(%d), return code = %d.\n", diSlot, rc);
break;
}
if(*pDOValue != lastDOValue)
{
lastDOValue = *pDOValue;
rc = MX_RTU_Module_DO_Value_Set(doSlot, *pDOValue);
if(rc != MODULE_RW_ERR_OK)
{
printf("MX_RTU_Module_DO_Value_Set(%d, 0x%04X), return code = %d.\n",
doSlot, *pDOValue, rc);
break;
}
}
memset(&connectionInfo, 0, sizeof(connectionInfo));
rc = MX_RTU_Modbus_Tcp_Slave_Connection_Info(handle, &connectionInfo);
{
printf("MX_RTU_Modbus_Tcp_Slave_Connection_Info(%d), return code = %d.\n",
handle, rc);
break;
}
if(connectionAmount != connectionInfo.accepted_connections)
{
connectionAmount = connectionInfo.accepted_connections;
printf("Number of connections = %d\n", connectionAmount);
for(i = 0; i < connectionAmount; i++)
{
printf("(%d) IP = %s, port = %d\n", i + 1, connectionInfo.ip[i],
connectionInfo.port[i]);
}
}
usleep(200000);
}
printf("Stop Server\n");
printf("MX_RTU_Modbus_Tcp_Slave_Stop(%d), return code = %d.\n", handle, rc);
rc = modbusSlaveUninit(&handle);
printf("ModbusSlaveUninit(), return code = %d.\n", rc);
return 0;
}

Variable Documentation

MODBUS_MAP ModbusMap[]
Initial value:
=
{
{ MODBUS_INPUT_REGISTER, 0x0800, getReg, NULL, 0xFFFF },
{ MODBUS_HOLDING_REGISTER, 0x0810, getReg, setReg, 0xFFFF },
}