📄 mb_tcp_s.c
字号:
/******************************************************************************
*
* (c) 2004 by BECK IPC GmbH
*
*******************************************************************************
*
* Module: mb_tcp_s.c
* Function: This program provides a tcp modbus single server for SC1x3/DK60, SC12/DK40 SC13/DK50.
* It shall be used as a template for building own own tcp modbus single
* server applications on IPC@CHIP based devices.
* The server executes(serves) incoming tcp client modbus requests.
* The application programmer shall feel free to modify,expand and improve this
* example for his own modbus server application.
*
* The server executes(serves)incoming modbus requests, according to the
* SC1x3/DK60,DK50/DK40 register and coil definition below.
* The application programmer shall feel free to modify,expand and improve this
* example for his own modbus slave application.
*
* For understanding the source code and using it for own applications the
* following premises are required:
* 1. Good knowledge about the modbus protocol
* 2. Careful reading and understanding of this example program
*
* Required hardware/software for testing:
* 1. SC1x3/DK60,DK50/SC13 or DK40/SC12 as modbus rtu server, running this program
* 2. Windows PC running a modbus tcp client application
*
* The implementation based on the follwing docunments from modbus.org
* Please note: The server uses only a subset of the specified modbus features
* 1. Modbus over serial line Specification & Implementation V1.0
* 2. Modbus application protocol specification V1.1
*
* Main files of this project:
* 1. Modbus.h : Contains several modbus specific defines
* 2. Mb_tcp_s.c: Contains the modbus server initialzation
and the general parts for receiving/executing
an incoming modbus client request and sending of
the reply.
* 3. Mb_dev.c : Basic functions for handle the different types of incoming
* modbus requests. Inside of the several function handlers
* the DK40/DK50 specific register/coil read/write functions
* are inserted, according to the DKxx demo modbus
* register and coil definition below.
* Implemented modbus function codes:
* 01, 02, 05, 15, 04, 03, 06 , 43 (only in parts)
*
* 4. Mb_dkxx.c : Contains our DK40/DK50 specfic functions. which are called
* inside of the modbus handler functions implemented at mb_dev.c.
*
* To exit the modbus server it is necessary to reboot the IPC@CHIP
*
* The implementation based on the follwing documents from modbus.org
* 1. Modbus Messaging on TCP/IP Implementation guide
* 2. Modbus application protocol specification V1.1
********************************************************************************
* DKxx Modbus demo holding register definition
* Register address Access Meaning
* 00 R/W DKxx 8Bit IO port at IO addr 600h/c00h
* (on DK40 only Bit 6-0 available)
* 01 R/W 16 Bit variable, for
* demonstration purpose only
* 02 R/W 16 Bit counter variable, for
* demonstration purpose only, counter
* is automatically incremented by a RTOS tiner
* 03 R/W another 16 Bit counter variable, for
* demonstration purpose only, counter
* is automatically changed by a RTOS timer
*
* DKxx Modbus demo input register definition
* Register address Access Meaning
* 00 R DKxx 8Bit I port at IO addr 600h/c00h
* (on DK40 only Bit 6-0 available)
* 01 R 16 Bit counter variable, for
* demonstration purpose only, counter
* is automatically incremented by a RTOS
* 02 R 16 Bit counter variable, for
* demonstration purpose only, counter
* is automatically changed by a RTOS timer
********************************************************************************
* DKxx Modbus demo coil definition
* Register address Access Meaning
* 00 R/W DKxx/SC1x PIO 3
* 01 R/W DKxx/SC1x PIO 13
* 02 R/W Bit 0 of mb_dkxx_var (Holding reg var 01)
* 03 R/W Bit 1 of mb_dkxx_var
* 04 R/W Bit 2 of mb_dkxx_var
* 05 R/W Bit 3 of mb_dkxx_var
* 06 R/W Bit 4 of mb_dkxx_var
* 07 R/W Bit 5 of mb_dkxx_var
* 08 R/W Bit 6 of mb_dkxx_var
* 09 R/W Bit 7 of mb_dkxx_var
* 10 R/W Bit 8 of mb_dkxx_var
* 11 R/W Bit 9 of mb_dkxx_var
* 12 R/W Bit 10 of mb_dkxx_var
* 13 R/W Bit 11 of mb_dkxx_var
* 14 R/W Bit 12 of mb_dkxx_var
********************************************************************************
* DKxx Modbus demo discrete input definition
* Register address Access Meaning
* 00 R Bit 0 of DKxx IO port 0x600/0xC00
* 01 R Bit 1 of DKxx IO port 0x600/0xC00
* 02 R Bit 2 of DKxx IO port 0x600/0xC00
* 03 R Bit 3 of DKxx IO port 0x600/0xC00
* 04 R Bit 4 of DKxx IO port 0x600/0xC00
* 05 R Bit 5 of DKxx IO port 0x600/0xC00
* 06 R Bit 6 of DKxx IO port 0x600/0xC00
********************************************************************************
* Disclaimer: This program is an example and should be used as such.
* If you wish to use this program or parts of it in your application,
* you must validate the code yourself. BECK IPC GmbH can not be held
* responsible for the correct functioning or coding of this example.
*******************************************************************************
*
* $Header: mb_tcp_s.c, 6, 02.09.2005 11:07:59, Markus Bartat$
*
******************************************************************************/
/******************************************************************************
* Includes
******************************************************************************/
#include <stdio.h>
#include <mem.h>
#include "clib.h"
#include "modbus.h"
#include "mb_dev.h"
/******************************************************************************
* Constants
******************************************************************************/
#define MB_PORT 502 // modbus server port
#define MB_RECV_TIMEOUT 2000 // ms
#define MB_TCP_IDLE 0 // no connection established
#define MB_TCP_CONN 1 // connection established
//#define MB_TCP_DEBUG
/******************************************************************************
* Global variables
******************************************************************************/
unsigned char mb_tcp_request_buf[MB_TCP_MAX_BUF];
unsigned char mb_tcp_response_buf[MB_TCP_MAX_BUF];
#ifdef MB_TCP_DEBUG
char ClientIP[17];
#endif
/*******************************************************************************
Check by given ip address unsigned long client_ip, if the client is authorized
to access the server.
Returns MB_ERROR, if client has no access, else MB_NO_ERROR is returned
At this example we allow everybody the access to the dkxx module.
The application programmer can insert here his own ip address check procedure
********************************************************************************/
#pragma argsused
int mb_tcp_authorized(unsigned long client_ip)
{
return MB_NO_ERROR;
}
/*******************************************************************************
Receive and parse a incoming modbus request
Input parameter sd: socket descriptor
Return: MB_NO_ERROR : sucessful, mb_recvbuf contains a valid modbus request
with MBAB header and modbus request data as specified at the
"Modbus Messaging on TCP/IP Implementation guide" fro modbus.org
MB_ERROR : receiving of modbus request timed out
MB_TCP_ERROR : A tcp socket error has occured
********************************************************************************/
int mb_tcp_recv_request(int sd, unsigned char * mb_recvbuf)
{
int fr_rcvd;
int retval;
int fr_length;
int error;
#ifdef MB_TCP_DEBUG
int i;
#endif
fr_rcvd=0;
retval = recv(sd,(char *)mb_recvbuf,MB_TCP_MAX_BUF,MSG_BLOCKING,0L,&error);
if(retval == API_ERROR)
{
//an tcpip socket error has occured
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: 1 socket error %d",error);
#endif
return MB_TCP_ERROR;
}
fr_rcvd=retval;
//Try to receive 7 bytes as a MBAB header
while(fr_rcvd<MBAB_SIZE)
{
retval = recv( sd, (char *)&mb_recvbuf[fr_rcvd], MB_TCP_MAX_BUF-fr_rcvd,
MSG_TIMEOUT, MB_RECV_TIMEOUT, &error );
if(retval>0)
{
fr_rcvd+=retval;
}
else
{
if(retval==0)
{
//tcp reveive timeout
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: 1 Receive timeout");
#endif
return MB_ERROR;
}
else
{
//tcp receive error
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: 2 socket error %d",error);
#endif
return MB_TCP_ERROR;
}
}
}
//Parse the MBAB header
if((mb_recvbuf[2]!=0) || (mb_recvbuf[3]!=0))
{
//invalid protocol field
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: Invalid protocol %02X %02X",mb_recvbuf[2],mb_recvbuf[3]);
#endif
return MB_ERROR;
}
//Get length
fr_length=(int)(((unsigned int)mb_recvbuf[4] << 8) + (unsigned int)mb_recvbuf[5]);
if(fr_length > 254)
{
//invalid length
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: Invalid length field %04X ",fr_length);
#endif
return MB_ERROR;
}
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: Length field %04X ",fr_length);
#endif
//Receive the whole frame with now known length
while(fr_rcvd < fr_length + 6)
{
retval = recv( sd, (char *)&mb_recvbuf[fr_rcvd], MB_TCP_MAX_BUF-fr_rcvd,
MSG_TIMEOUT, MB_RECV_TIMEOUT, &error );
if(retval > 0)
{
fr_rcvd+=retval;
}
else
{
if(retval==0)
{
//tcp reveive timeout
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: 2 Receive timeout");
#endif
return MB_ERROR;
}
else
{
//tcp receive error
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_recv: 3 socket error %d",error);
#endif
return MB_TCP_ERROR;
}
}
}
#ifdef MB_TCP_DEBUG
printf("\r\nRequest MBAB: ");
for(i=0;i<7;i++)
{
printf(" %02X",mb_recvbuf[i]);
}
printf("\r\nRequest PDU: ");
for(i=7;i<fr_rcvd;i++)
{
printf(" %02X",mb_recvbuf[i]);
}
printf("\r\n");
#endif
return MB_NO_ERROR;
}
/*******************************************************************************
Process an incoming mdobus request and send a reply to client
Input parameter mb_request_buf: contains modbus request frame
********************************************************************************/
int mb_tcp_process_request(int sd, unsigned char * mb_request_buf, unsigned char * mb_response_buf)
{
unsigned char function_code;
unsigned int response_length;
unsigned int start_address;
unsigned int output_value;
unsigned int quantity;
unsigned char read_dev_id_length;
unsigned char byte_count;
int result,error;
#ifdef MB_TCP_DEBUG
int i;
#endif
function_code = mb_request_buf[7];
#ifdef MB_TCP_DEBUG
printf("\r\nmb_tcp_process: function 0x%02X\r\n",function_code);
#endif
//general preformat of responsebuffer
memcpy(mb_response_buf,mb_request_buf,MBAB_SIZE+1); //copy from request_buf, incl. function_code
//Preset length of response
response_length = MBAB_SIZE + 1; //7 byte header + 1 byte function code
switch(function_code)
{
//************************************************************************
//Function code 0x01,0x02: read discrete input, coil
//************************************************************************
case MB_RD_COIL_STATE :
case MB_RD_DISCRETE_INP :
start_address = ((unsigned int)mb_request_buf[8] << 8)+(unsigned int)mb_request_buf[9];
quantity = ((unsigned int)mb_request_buf[10] << 8)+(unsigned int)mb_request_buf[11];
if(function_code==MB_RD_COIL_STATE)
{
//execute defined modbus device read coil operation
result = mb_read_coils(start_address,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -