?? modbus_tcp_c.c
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY><XMP>/* modbus_tcp.c
By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au
These library of functions are designed to enable a program send and
receive data from a device that communicates using the Modbus tcp protocol.
Copyright (C) 2000 Philip Costigan P.C. SCADA LINK PTY. LTD.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The functions included here have been derived from the
Modicon Modbus Protocol and Modbus TCP Protocol Reference Guide
which can be obtained from Schneider at www.schneiderautomation.com.
This code has its origins with
paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk)
who wrote a small program to read 100 registers from a modbus slave.
I have used his code as a catalist to produce this more functional set
of functions. Thanks paul.
*/
#include <fcntl.h> /* File control definitions */
#include <stdio.h> /* Standard input/output */
#include <string.h>
#include <termio.h> /* POSIX terminal control definitions */
#include <sys/time.h> /* Time structures for select() */
#include <unistd.h> /* POSIX Symbolic Constants */
#include <errno.h> /* Error definitions */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "modbus_tcp.h"
/*#define DEBUG*/ /* uncomment to see the data sent and received */
/***********************************************************************
send_query( file_descriptor, query_string, query_length )
Function to send a query out to a modbus slave.
************************************************************************/
int send_query( int sfd, unsigned char *query, size_t string_length )
{
int write_stat;
#ifdef DEBUG
int i;
#endif
#ifdef DEBUG
/* Print to stderr the hex value of each character that is about to be */
/* sent to the modbus slave. */
for( i = 0; i < string_length; i++ )
{
fprintf( stderr, "[%0.2X]", query[ i ] );
}
fprintf( stderr, "\n" );
#endif
tcflush( sfd, TCIOFLUSH ); /* flush the input & output streams */
write_stat = send( sfd, query, string_length, 0);
tcflush( sfd, TCIFLUSH ); /* maybe not neccesary */
return( write_stat );
}
/*********************************************************************
modbus_response( response_data_array, query_array )
Function to the correct response is returned and check for correctness.
Returns: string_length if OK
0 if failed
Less than 0 for exception errors
Note: All functions used for sending or receiving data via
modbus return these return values.
**********************************************************************/
int modbus_response( unsigned char *data, unsigned char *query, int fd )
{
int response_length;
/* local declaration */
int receive_response( unsigned char *received_string, int sfd );
response_length = receive_response( data, fd );
if( response_length > 0 )
{
/********** check for exception response *****/
if( response_length && data[ 7 ] != query [ 7 ] )
{
/* return the exception value as a -ve number */
response_length = 0 - data[ 8 ];
}
}
return( response_length );
}
/***********************************************************************
receive_response( array_for_data )
Function to monitor for the reply from the modbus slave.
This function blocks for timeout seconds if there is no reply.
Returns: Total number of characters received.
***********************************************************************/
int receive_response( unsigned char *received_string, int sfd )
{
int rxchar = -1;
int data_avail = FALSE;
int bytes_received = 0;
int read_stat;
int timeout = 1; /* 1 second */
int char_interval_timeout = 10000; /* 10 milliseconds. */
int max_fds = 32;
fd_set rfds;
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
FD_ZERO( &rfds );
FD_SET( sfd, &rfds );
#ifdef DEBUG
fprintf( stderr, "Waiting for response.\n");
#endif
/* wait for a response */
data_avail = select( max_fds, &rfds, NULL, NULL, &tv );
if( !data_avail )
{
bytes_received = 0;
#ifdef DEBUG
fprintf( stderr, "Comms time out\n" );
#endif
}
tv.tv_sec = 0;
tv.tv_usec = char_interval_timeout;
FD_ZERO( &rfds );
FD_SET( sfd, &rfds );
while( data_avail )
{
/* if no character at the buffer wait char_interval_timeout */
/* before accepting end of response */
if( select( max_fds, &rfds, NULL, NULL, &tv) > 0 )
{
read_stat = recv( sfd, &rxchar, 1, 0);
if( read_stat < 0 )
{
bytes_received = SOCKET_FAILURE;
data_avail = FALSE;
}
else
{
rxchar = rxchar & 0xFF;
received_string[ bytes_received ++ ] = rxchar;
}
if( bytes_received >= MAX_RESPONSE_LENGTH )
{
bytes_received = SOCKET_FAILURE;
data_avail = FALSE;
}
#ifdef DEBUG
/* display the hex code of each character received */
fprintf( stderr, "<%0.2X>", rxchar );
#endif
}
else
{
data_avail = FALSE;
}
}
#ifdef DEBUG
fprintf( stderr, "\n" );
#endif
if( bytes_received > 7 )
{
bytes_received -= 7;
}
return( bytes_received );
}
/***********************************************************************
The following functions construct the required query into
a modbus query packet.
***********************************************************************/
#define REQUEST_QUERY_SIZE 12 /* the following packets require */
#define CHECKSUM_SIZE 2 /* 6 unsigned chars for the packet plus */
/* 2 for the checksum. */
void build_request_packet( int slave, int function, int start_addr,
int count, unsigned char *packet )
{
int i;
for( i = 0; i < 5 ; i++ ) packet[ i ] = 0;
packet[ i++ ] = 6;
packet[ i++ ] = slave;
packet[ i++ ] = function;
start_addr -= 1;
packet[ i++ ] = start_addr >> 8;
packet[ i++ ] = start_addr & 0x00ff;
packet[ i++ ] = count >> 8;
packet[ i ] = count &0x00ff;
}
/************************************************************************
read_IO_status
read_coil_stat_query and read_coil_stat_response interigate
a modbus slave to get coil status. An array of coils shall be
set to TRUE or FALSE according to the response from the slave.
*************************************************************************/
int read_IO_status( int function, int slave, int start_addr, int count,
int *dest, int dest_size, int sfd )
{
/* local declaration */
int read_IO_stat_response( int *dest, int dest_size, int coil_count,
unsigned char *query, int fd );
int status;
unsigned char packet[ REQUEST_QUERY_SIZE + CHECKSUM_SIZE ];
build_request_packet( slave, function, start_addr, count, packet );
if( send_query( sfd, packet, REQUEST_QUERY_SIZE ) > -1 )
{
status = read_IO_stat_response( dest, dest_size,
count, packet, sfd );
}
else
{
status = SOCKET_FAILURE;
}
return( status );
}
/************************************************************************
read_coil_status_tcp
reads the boolean status of coils and sets the array elements
in the destination to TRUE or FALSE
*************************************************************************/
int read_coil_status_tcp( int slave, int start_addr, int count,
int *dest, int dest_size, int sfd )
{
int function = 0x01;
int status;
status = read_IO_status( function, slave, start_addr, count,
dest, dest_size, sfd );
return( status );
}
/************************************************************************
read_input_status_tcp
same as read_coil_status but reads the slaves input table.
************************************************************************/
int read_input_status_tcp( int slave, int start_addr, int count,
int *dest, int dest_size, int sfd )
{
int function = 0x02; /* Function: Read Input Status */
int status;
status = read_IO_status( function, slave, start_addr, count,
dest, dest_size, sfd );
return( status );
}
/**************************************************************************
read_IO_stat_response
this function does the work of setting array elements to TRUE
or FALSE.
**************************************************************************/
int read_IO_stat_response( int *dest, int dest_size, int coil_count,
unsigned char *query, int fd )
{
unsigned char data[ MAX_RESPONSE_LENGTH ];
int raw_response_length;
int temp, i, bit, dest_pos = 0;
int coils_processed = 0;
raw_response_length = modbus_response( data, query, fd );
if( raw_response_length > 0 )
{
for( i = 0; i < ( data[8] ) && i < dest_size; i++ )
{
/* shift reg hi_byte to temp */
temp = data[ 9 + i ] ;
for( bit = 0x01; bit & 0xff &&
coils_processed < coil_count; )
{
if( temp & bit )
{
dest[ dest_pos ] = TRUE;
}
else
{
dest[ dest_pos ] = FALSE;
}
coils_processed++;
dest_pos++;
bit = bit << 1;
}
}
}
return( raw_response_length );
}
/************************************************************************
read_registers
read the data from a modbus slave and put that data into an array.
************************************************************************/
int read_registers( int function, int slave, int start_addr, int count,
int *dest, int dest_size, int sfd )
{
/* local declaration */
int read_reg_response( int *dest, int dest_size,
unsigned char *query, int fd );
int status;
unsigned char packet[ REQUEST_QUERY_SIZE + CHECKSUM_SIZE ];
build_request_packet( slave, function, start_addr, count, packet );
if( send_query( sfd, packet, REQUEST_QUERY_SIZE ) > -1 )
{
status = read_reg_response( dest, dest_size, packet, sfd );
}
else
{
status = SOCKET_FAILURE;
}
return( status );
}
/************************************************************************
read_holding_registers
Read the holding registers in a slave and put the data into
an array.
*************************************************************************/
int read_holding_registers_tcp( int slave, int start_addr, int count,
int *dest, int dest_size, int sfd )
{
int function = 0x03; /* Function: Read Holding Registers */
int status;
if( count > MAX_READ_REGS )
{
count = MAX_READ_REGS;
#ifdef DEBUG
fprintf( stderr, "Too many registers requested.\n" );
#endif
}
status = read_registers( function, slave, start_addr, count,
dest, dest_size, sfd );
return( status);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -