Skip to content
Snippets Groups Projects
Commit 2458f5e3 authored by al.schwinn's avatar al.schwinn
Browse files

[SIL-170] Upgrade Modbus library to official 3.0.6 version and link

with 3rd party delivery.
parent 2733f7e3
No related branches found
No related tags found
No related merge requests found
/*
* (c) 2002 Mario de Sousa
*
* Offered to the public 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.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
/* Time handling functions used by the modbus protocols... */
#include <time.h>
#ifndef __MODBUS_TIME_UTIL_H
#define __MODBUS_TIME_UTIL_H
/************************************/
/** **/
/** Time format conversion **/
/** **/
/************************************/
/* Function to load a struct timeval correctly
* from a double.
*/
static inline struct timeval d_to_timeval(double time) {
struct timeval tmp;
tmp.tv_sec = time;
tmp.tv_usec = 1e6*(time - tmp.tv_sec);
return tmp;
}
/* Function to ... */
static inline struct timespec timespec_dif(struct timespec ts1, struct timespec ts2) {
struct timespec ts;
ts.tv_sec = ts1.tv_sec - ts2.tv_sec;
if(ts1.tv_nsec > ts2.tv_nsec) {
ts.tv_nsec = ts1.tv_nsec - ts2.tv_nsec;
} else {
ts.tv_nsec = 1000000000 + ts1.tv_nsec - ts2.tv_nsec;
ts.tv_sec--;
}
if (ts.tv_sec < 0)
ts.tv_sec = ts.tv_nsec = 0;
return ts;
}
/* Function to ... */
static inline struct timespec timespec_add(struct timespec ts1, struct timespec ts2) {
struct timespec ts;
ts.tv_sec = ts1.tv_sec + ts2.tv_sec;
ts.tv_nsec = ts1.tv_nsec + ts2.tv_nsec;
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec = ts.tv_nsec % 1000000000;
return ts;
}
/* Function to convert a struct timespec to a struct timeval. */
static inline struct timeval timespec_to_timeval(struct timespec ts) {
struct timeval tv;
tv.tv_sec = ts.tv_sec;
tv.tv_usec = ts.tv_nsec/1000;
return tv;
}
/************************************/
/** **/
/** select() with absolute timeout **/
/** **/
/************************************/
/* My private version of select using an absolute timeout, instead of the
* usual relative timeout.
*
* NOTE: Ususal select semantics for (a: end_time == NULL) and
* (b: *end_time == 0) also apply.
*
* (a) Indefinite timeout
* (b) Try once, and and quit if no data available.
*/
static int my_select(int fd, fd_set *rfds, const struct timespec *end_time) {
int res;
struct timespec cur_time;
struct timeval timeout, *tv_ptr;
fd_set tmp_fds;
/*============================*
* wait for data availability *
*============================*/
do {
tmp_fds = *rfds;
/* NOTE: To do the timeout correctly we would have to revert to timers
* and asociated signals. That is not very thread friendly, and is
* probably too much of a hassle trying to figure out which signal
* to use. What if we don't have any free signals?
*
* The following solution is not correct, as it includes a race
* condition. The following five lines of code should really
* be atomic!
*
* NOTE: see also the timeout related comment in the
* modbus_tcp_read() function!
*/
if (end_time == NULL) {
tv_ptr = NULL;
} else {
tv_ptr = &timeout;
if ((end_time->tv_sec == 0) && (end_time->tv_nsec == 0)) {
timeout.tv_sec = timeout.tv_usec = 0;
} else {
/* ATOMIC - start */
if (clock_gettime(CLOCK_REALTIME, &cur_time) < 0)
return -1;
timeout = timespec_to_timeval(timespec_dif(*end_time, cur_time));
}
}
res = select(fd, &tmp_fds, NULL, NULL, tv_ptr);
/* ATOMIC - end */
if (res == 0) {
#ifdef DEBUG
printf("Comms time out\n");
#endif
return -1;
}
if ((res < 0) && (errno != EINTR)) {
return -1;
}
} while (res <= 0);
*rfds = tmp_fds;
return res;
}
#endif /* __MODBUS_TIME_UTIL_H */
/*
* (c) 2002 Mario de Sousa
*
* Offered to the public 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.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
#ifndef MB_UTIL_H
#define MB_UTIL_H
/* This file has constants related to the modbus protocol */
/*
* Some of these constants are specific to the layer two protocols
* (i.e. master and slave), while others are specific of the
* layer one protocols (i.e. rtu, ascii, tcp).
*
* a) Unfortunately, due to the nature of the modbus protocol, that does not
* include a frame size field in the layer 1 frame (see note 1), and the
* fact that we are implementing it at the user level, the implementation
* of some layer 1 protocols need to know the content of the layer 2 protocol
* in order to determine the size of the frame.
*
* b) The layer two message formats are in fact the same, just reversing the role
* being played (master or slave).
*
* Bothe a) and b) mean we need the same modbus protocol constants in several files.
* It ends up making more sense to put them all together in a single file, which
* makes updating easier, even though we are trying to strictly seperate the layer 1
* and layer 2 protocols.
*
*
*
* Notes:
* (1) There is no layer 1 field with the frame size, nevertheless this
* size can be determined indirectly due to timing restrictions on the rtu
* protocol. Unfortunately, due to the fact that we are implementing
* it at the user level, we are not guaranteed to detect these timings
* correctly, and therefore have to rely on layer 2 protocol info to
* determine the frame size.
* For the ascii protocol, the frame size is determined indirectly by
* a frame header and tail, so we do not use layer 2 protocol info.
*/
/* Layer 2 Frame Structure... */
/* Valid for both master and slave protocols */
#define L2_FRAME_HEADER_LENGTH 6
#define L2_FRAME_BYTECOUNT_LENGTH 1
#define L2_FRAME_DATABYTES_LENGTH 255
#define MAX_L2_FRAME_LENGTH (L2_FRAME_HEADER_LENGTH + L2_FRAME_BYTECOUNT_LENGTH + L2_FRAME_DATABYTES_LENGTH)
#define L2_FRAME_SLAVEID_OFS 0
#define L2_FRAME_FUNCTION_OFS 1
/* Layer 1 - Ascii Frame sizes... */
#define L2_TO_ASC_CODING 2 /* number of ascii bytes used to code a Layer 2 frame byte */
#define ASC_FRAME_HEADER_LENGTH 1
#define ASC_FRAME_HEADER ':'
#define ASC_FRAME_TAIL_LENGTH 2
#define ASC_FRAME_TAIL_0 '\13' /* 'CR' */
#define ASC_FRAME_TAIL_1 '\10' /* 'LF' */
#define ASC_FRAME_LRC_LENGTH 2
/* Layer 1 - RTU Frame sizes... */
#define RTU_FRAME_CRC_LENGTH 2
/* Layer 1 - TCP Frame sizes... */
#define TCP_HEADER_LENGTH 6
/* Global Frame sizes */
#define MAX_RTU_FRAME_LENGTH MAX_L2_FRAME_LENGTH + RTU_FRAME_CRC_LENGTH
#define MAX_ASC_FRAME_LENGTH ((MAX_L2_FRAME_LENGTH * L2_TO_ASC_CODING) + ASC_FRAME_HEADER_LENGTH + ASC_FRAME_TAIL_LENGTH + ASC_FRAME_LRC_LENGTH)
#endif /* MB_UTIL_H */
/*
* (c) 2000 Jiri Baum
* Mario de Sousa
*
* Offered to the public 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.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
/*
* Socket INET utility routines
*
* This file implements the routines in sin_util.h
*
* These routines merely make life simpler when working with
* internet protocol sockets
*/
#include "sin_util.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ERR_EXIT(mesg, err_num) {perror(mesg);return err_num;}
#define MSG_EXIT(mesg, err_num) {fprintf(stderr, "%s\n", mesg);return err_num;}
int sin_init_dot_addr(struct sockaddr_in *sad_in,
char *dot_addr,
unsigned short int port)
{
sad_in->sin_family = AF_INET;
if( inet_aton(dot_addr, &(sad_in->sin_addr)) == 0 )
ERR_EXIT("inet_aton", -1);
sad_in->sin_port = htons(port);
return 1;
} /* sin_init_dot_addr */
int sin_init_addr(struct sockaddr_in *addr,
const char *host,
const char *service,
const char *protocol)
/* initialize an address structure */
{
int port_flag;
long int tmp_numb;
long long int lli = 1;
char *error_char;
struct servent *serv_entry_ptr;
struct hostent *host_entry_ptr;
bzero ((char *)addr, sizeof(*addr));
addr->sin_family = AF_INET;
/* Map service name to port number */
port_flag = 0;
if (port_flag == 0)
if ((service == NULL) || (strcmp(service, "") == 0))
{addr->sin_port = htons(0); /* OS will sugest a port when binding */
port_flag = 1;
}
if (port_flag == 0)
if ((serv_entry_ptr = getservbyname ((char *)service, (char *)protocol)) )
{addr->sin_port = serv_entry_ptr->s_port;
port_flag = 1;
}
if (port_flag == 0)
{tmp_numb = strtol(service, &error_char, 0);
if ((*error_char == '\0') && (error_char != service) &&
(tmp_numb >= 0) && (tmp_numb < (lli << (8*sizeof(addr->sin_port)))))
{addr->sin_port = htons(tmp_numb);
port_flag = 1;
}
}
if (port_flag == 0)
MSG_EXIT("sin_init_addr: Could not determine the port number.", -1);
/* Map host name to IP address, allowing dotted decimal */
addr->sin_addr.s_addr = INADDR_NONE;
if (addr->sin_addr.s_addr == INADDR_NONE)
if ( (host_entry_ptr = gethostbyname ((char *)host)) )
bcopy (host_entry_ptr->h_addr,
(char *)&(addr->sin_addr),
host_entry_ptr->h_length);
if (addr->sin_addr.s_addr == INADDR_NONE)
inet_aton (host, (struct in_addr *)addr);
if (addr->sin_addr.s_addr == INADDR_NONE)
MSG_EXIT("sin_init_addr: Could not determine the host IP address.", -1);
return 1;
} /* sin_init_addr(...) */
int sin_init_proto(int *type,
int *protocol_num,
const char *protocol)
{
struct protoent *proto_entry_ptr;
/* determine the protocol */
*type = SOCK_RDM;
if (strcasecmp (protocol, "udp") == 0) *type = SOCK_DGRAM;
if (strcasecmp (protocol, "tcp") == 0) *type = SOCK_STREAM;
if (strcasecmp (protocol, "raw") == 0) *type = SOCK_RAW;
if (*type == SOCK_RDM)
MSG_EXIT ("sin_init_proto: protocol not supported.", -1);
/* map protocol name to protocol number */
if ( (proto_entry_ptr = getprotobyname ((char *)protocol)) == NULL )
MSG_EXIT ("sin_init_proto: can't get protocol number.", -1);
*protocol_num = proto_entry_ptr->p_proto;
return 1;
} /* sin_init_proto(...) */
int bind_socket(const char *host,
const char *service,
const char *protocol)
/* create a socket and bind to a local port */
{
struct sockaddr_in sock_addr;
int socket_id, type, protocol_num;
/* initialize the sock_addr sturcture */
if ( (sin_init_addr (&sock_addr, host, service, protocol)) < 0)
MSG_EXIT ("bind_socket: wrong address format", -1);
/* determine the protocol */
if ( (sin_init_proto (&type, &protocol_num, protocol)) < 0)
MSG_EXIT ("bind_socket: wrong protocol format", -1);
/* create the socket */
if ( (socket_id = socket (PF_INET, type, protocol_num)) < 0)
ERR_EXIT ("socket", -1);
/* bind the socket */
if ( bind (socket_id, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0)
ERR_EXIT ("bind", -1);
return socket_id;
} /* bind_socket(...) */
int connect_socket(const char *host,
const char *service,
const char *protocol)
/* create a socket and connect to a remote host */
{
struct sockaddr_in sock_addr;
int socket_id, type, protocol_num;
/* initialize the sock_addr sturcture */
if ( (sin_init_addr (&sock_addr, host, service, protocol)) < 0)
MSG_EXIT ("bind_socket: wrong address format", -1);
/* determine the protocol */
if ( (sin_init_proto (&type, &protocol_num, protocol)) < 0)
MSG_EXIT ("bind_socket: wrong protocol format", -1);
/* create the socket */
if ( (socket_id = socket (PF_INET, type, protocol_num)) < 0)
ERR_EXIT ("socket", -1);
/* bind the socket */
if ( connect(socket_id, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0)
ERR_EXIT ("bind", -1);
return socket_id;
} /* connect_socket(...) */
int get_socket_port(int sock)
/* returns the port to which the socket is bound */
{
int length;
struct sockaddr_in srv_addr;
length = sizeof(srv_addr);
if (getsockname(sock, (struct sockaddr *)&srv_addr, (socklen_t *)&length) < 0)
return -1;
if (srv_addr.sin_family == AF_INET)
return ntohs(srv_addr.sin_port);
return -1; /* not INET socket... */
} /* get_socket_port(...) */
#ifdef __cplusplus
}
#endif
/*
* (c) 2000 Jiri Baum
* Mario de Sousa
*
* Offered to the public 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.
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
#ifndef SIN_UTIL_H
#define SIN_UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int sin_init_addr(struct sockaddr_in *addr,
const char *host,
const char *service,
const char *protocol);
/* initialize an address structure */
int bind_socket(const char *host,
const char *service,
const char *protocol);
/* create a socket and bind to a local port */
int connect_socket(const char *host,
const char *service,
const char *protocol);
/* create a socket and connect to a remote host */
int get_socket_port(int sock);
/* returns the port to which the socket is bound */
#ifdef __cplusplus
}
#endif
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment