ioPAC RTU Controllers
C/C++ Sample Code Programming Guide
Data Structures | Macros | Typedefs | Functions | Variables
modbus_rtu_slave.c File Reference

Modbus RTU Slave Sample Application More...

#include <libmoxa_rtu.h>

Data Structures

struct  _MODBUS_MAP
 

Macros

#define MODBUS_SERIAL_PARITY   'N'
 
#define MODBUS_DEVICE_ID   1
 
#define MODBUS_SIZE   3000
 
#define DIM(x)   (sizeof(x)/sizeof(x[0]))
 

Typedefs

typedef struct _MODBUS_MAP MODBUS_MAP
 
typedef struct _MODBUS_MAPpMODBUS_MAP
 

Functions

void stopHandler (int signum)
 
int main (int argc, char *argv[])
 

Variables

volatile sig_atomic_t keepRunning
 
MODBUS_MAP ModbusMap []
 

Detailed Description

Modbus RTU Slave Sample Application

Date
04-02-2015
Author
TJ Tai
Version
V1.0
modbus_rtu_slave.jpg
Modbus RTU Slave Sample Application
Introduction:
The Modbus Slave creates two Modbus addresses, one for DIs (input register) and one for DOs (holding register).
Then, PC Modbus Master polls for DI values and sets the DO statuses equal to the DI values.
Example:
1. Using default: ./modbus_rtu_slave
Default:
Environment Setting on ioPAC8600
RTU Slot = 1
DI  Slot = 2
DO  Slot = 3
Help:
root@Moxa:/tmp#./modbus_rtu_slave -h
Modbus RTU Slave sample program.

Usage: ./modbus_rtu_slave [OPTIONS]

Get DI value and set DO value

Options:
        -r       Slot of RTU(Serial) module [1-9]. Default slot = 1
        -i       Slot of DI module [1-9]. Default slot = 2
        -s       Slot of DO module [1-9]. Default slot = 3

Library:
ModbusRTUSlave APIs

Macro Definition Documentation

#define MODBUS_SERIAL_PARITY   'N'
/*******************************************************************************
* Copyright Moxa Inc.
*
* Modbus RTU Slave Sample Application
*
* Date Author Comment
* 04-02-2015 TJ Tai Created.
******************************************************************************/
#include <libmoxa_rtu.h>
#define MODBUS_SERIAL_PARITY 'N'
#define MODBUS_DEVICE_ID 1
#define MODBUS_SIZE 3000
#define DIM(x) (sizeof(x)/sizeof(x[0]))
volatile sig_atomic_t keepRunning;
//static int keepRunning = 1;
void stopHandler(int signum)
{
keepRunning = 1;
}
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;
static int getReg(UINT8 *pData, UINT16 nth, void *pUserData);
static int setReg(UINT8 *pData, UINT16 nth, void *pUserData);
{
//{ MODBUS_INPUT_REGISTER, 0x0001, getReg, NULL, 0xFFFF },
//{ MODBUS_HOLDING_REGISTER, 0x0002, getReg, setReg, 0xFFFF },
{ 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 main(int argc, char *argv[])
{
UINT32 handle_num;
int rc = 0;
int i;
UINT32 rtuSlot = 1;
UINT32 diSlot = 2;
UINT32 doSlot = 3, slotMin = 1, slotMax = 0;
int diChannelAmount = 16;
int doChannelAmount = 16;
UINT32 *pDIValue;
UINT32 *pDOValue;
UINT32 lastDOValue;
while(-1 != (rc = getopt(argc, argv, "hr:i:s:")))
{
switch(rc)
{
case 'r':
rtuSlot = atoi(optarg);
if (rtuSlot < slotMin || rtuSlot > slotMax) {
printf("Error parameter: slot: %d\n", rtuSlot);
return -1;
}
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 '?':
case 'h':
default:
printf("Modbus RTU Slave sample program.\n\n");
printf("Usage: ./modbus_rtu_slave [OPTIONS]\n\n");
printf("Get DI value and set DO value\n\n");
printf("Options:\n");
printf("\t%-8s Slot of RTU module [%d-%d]. Default slot = %d\n",
"-r", slotMin, slotMax, rtuSlot);
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("\n");
return 0;
}
}
printf("%-10s: %d\n", "RTU slot", rtuSlot);
printf("%-10s: %d\n", "DI slot", diSlot);
printf("%-10s: %d\n", "DO slot", doSlot);
TTY_PARAM param;
memset(&param, 0, sizeof(param));
param.mode = RS232_MODE;
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("MX_RTU_Modbus_Rtu_Slave_Init error, rc = %d\r\n", rc);
return -1;
}
rc = MX_RTU_Modbus_Rtu_Slave_Register(rtuSlot, PORT1, MODBUS_DEVICE_ID, MODBUS_SIZE, &param, &handle_num);
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("Rtu Slave Register Fail, rtuSlot = %d, port = %d, handle = %d, rc = %d\n", rtuSlot, PORT1, handle_num, rc);
return -1;
}
//Init modbus entries
for(i = 0; i < DIM(ModbusMap); i++)
{
rc = MX_RTU_Modbus_Rtu_Slave_Add_Entry(handle_num, ModbusMap[i].slave_group,
ModbusMap[i].slave_addr, &ModbusMap[i], ModbusMap[i].pfnModRead,
ModbusMap[i].pfnModWrite);
{
printf("MX_RTU_Modbus_Rtu_Slave_Add_Entry(), return code = %d.\n", rc);
return -1;
}
}
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("MX_RTU_Modbus_Rtu_Slave_Start handle %d error, rc = %d\r\n", handle_num, rc);
return -1;
}
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... UnitID: %d\n\n", MODBUS_DEVICE_ID);
signal(SIGINT, stopHandler);
// Start to polling DI and set DO
while(!keepRunning)
{
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;
}
}
usleep(200000);
}
printf("Stop Server\n");
rc = MX_RTU_Modbus_Rtu_Slave_Stop(handle_num);
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("MX_RTU_Modbus_Rtu_Slave_Stop handle %d error, rc = %d\r\n", handle_num, rc);
return -1;
}
//rc = MX_RTU_Modbus_Rtu_Slave_Unregister(handle_num, rtuSlot, PORT1);
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("Modbus Rtu Slave Unregister handle %d error, rc = %d\r\n", handle_num, rc);
return -1;
}
if (rc != MODBUS_SLAVE_ERR_OK) {
printf("MX_RTU_Modbus_Rtu_Slave_UnInit error, rc = %d\r\n", rc);
return -1;
}
return 0;
}
#define MODBUS_DEVICE_ID   1
#define MODBUS_SIZE   3000
#define DIM (   x)    (sizeof(x)/sizeof(x[0]))

Typedef Documentation

typedef struct _MODBUS_MAP MODBUS_MAP
typedef struct _MODBUS_MAP * pMODBUS_MAP

Function Documentation

void stopHandler ( int  signum)
int main ( int  argc,
char *  argv[] 
)

Variable Documentation

volatile sig_atomic_t keepRunning
MODBUS_MAP ModbusMap[]
Initial value:
=
{
{ MODBUS_INPUT_REGISTER, 0x0800, getReg, NULL, 0xFFFF },
{ MODBUS_HOLDING_REGISTER, 0x0810, getReg, setReg, 0xFFFF },
}
#define MODBUS_HOLDING_REGISTER
Definition: libmoxa_rtu.h:4086
#define MODBUS_INPUT_REGISTER
Definition: libmoxa_rtu.h:4087