| ioPAC RTU Controllers C/C++ Sample Code Programming Guide

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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_MAP * | pMODBUS_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

Copyright
  Moxa Inc.

Date
  03-27-2013

Author
  Wanhan Hsieh

Version
  V1.0
  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
{
UINT8 slave_group;
UINT16 slave_addr;
int (*pfnModRead)(UINT8 *pData, UINT16 nth, void *pUserData);
int (*pfnModWrite)(UINT8 *pData, UINT16 nth, void *pUserData);
UINT32 reg;
} MODBUS_MAP, *pMODBUS_MAP;
static int getReg(UINT8 *pData, UINT16 nth, void *pUserData);
static int setReg(UINT8 *pData, UINT16 nth, void *pUserData);
MODBUS_MAP ModbusMap[] =
{
{ 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)
{
MODBUS_MASTER_ERR_CODE rc;
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;
rc = MX_RTU_Modbus_Tcp_Slave_Init();
if(rc != MODBUS_SLAVE_ERR_OK)
{
printf("MX_RTU_Modbus_Tcp_Slave_Init(), return code = %d.\n", rc);
}
else
{
rc = MX_RTU_Modbus_Tcp_Slave_Register(port, mapSize, idleTimeoutMS, pHandle);
if(rc != MODBUS_SLAVE_ERR_OK)
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);
if(rc != MODBUS_SLAVE_ERR_OK)
{
printf("MX_RTU_Modbus_Tcp_Slave_Add_Entry(), return code = %d.\n", rc);
break;
}
}
}
return rc;
}
int modbusSlaveUninit(UINT32 *pHandle)
{
int rc = 0;
rc = MX_RTU_Modbus_Tcp_Slave_Unregister(*pHandle);
if(rc != MODBUS_SLAVE_ERR_OK)
printf("MX_RTU_Modbus_Tcp_Slave_Unregister(%d), return code = %d.\n",
*pHandle, rc);
rc = MX_RTU_Modbus_Tcp_Slave_Uninit();
if(rc != MODBUS_SLAVE_ERR_OK)
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;
MX_RTU_Total_Slots_Get(&slotMax);
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 0;
}
}
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);
if(rc != MODBUS_SLAVE_ERR_OK)
printf("ModbusSlaveInit(%d), return code = %d.\n\n", port, rc);
rc = MX_RTU_Modbus_Tcp_Slave_Map_Count(handle, &count);
if(rc != MODBUS_SLAVE_ERR_OK)
printf("MX_RTU_Modbus_Tcp_Slave_Map_Count(%d), return code = %d.\n\n", handle, rc);
else
printf("Entry count = %d\n", count);
rc = MX_RTU_Modbus_Tcp_Slave_Map_Dump(handle);
if(rc != MODBUS_SLAVE_ERR_OK)
printf("MX_RTU_Modbus_Tcp_Slave_Map_Dump(%d), return code = %d.\n\n", handle, rc);
rc = MX_RTU_Modbus_Tcp_Slave_Start(handle);
if(rc != MODBUS_SLAVE_ERR_OK)
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);
if(rc != MODBUS_SLAVE_ERR_OK && rc != MODBUS_SLAVE_ERR_NO_CONNECTIONS)
{
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");
rc = MX_RTU_Modbus_Tcp_Slave_Stop(handle);
if(rc != MODBUS_SLAVE_ERR_OK)
printf("MX_RTU_Modbus_Tcp_Slave_Stop(%d), return code = %d.\n", handle, rc);
rc = modbusSlaveUninit(&handle);
if(rc != MODBUS_SLAVE_ERR_OK)
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 },
}
MODBUS_HOLDING_REGISTER
#define MODBUS_HOLDING_REGISTER
Definition: libmoxa_rtu.h:4086
MODBUS_INPUT_REGISTER
#define MODBUS_INPUT_REGISTER
Definition: libmoxa_rtu.h:4087