Skip to content

Commit

Permalink
v0.6 (#14)
Browse files Browse the repository at this point in the history
* make libmodbus as nested submodule
* encapsulated TCP: use enc:// before IP. for Modbus TCP is used as default if no protocol is defined. Also tcp:// might be used
* implemented multiport semaphores (using hash function with scaling to number of nsems)
* added item short alias: modbus_read
  • Loading branch information
v-zhuravlev authored Jun 1, 2017
1 parent 7983b95 commit 4a1f226
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 59 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "libmodbus"]
path = libmodbus
url=https://github.com/v-zhuravlev/libmodbus
branch = v3.1.4
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SUBDIRS = src
SUBDIRS = libmodbus src
EXTRA_DIST = \
include
ACLOCAL_AMFLAGS = -I m4
25 changes: 4 additions & 21 deletions configure.ac
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
AC_INIT([libzbxmodbus], [0.5])
AC_INIT([libzbxmodbus], [0.6])
AM_INIT_AUTOMAKE([foreign -Wall -Werror])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SUBDIRS([libmodbus])
AC_CONFIG_SRCDIR([src/modbus.c])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
# Checks for libraries.
have_modbus=no
AC_SEARCH_LIBS([modbus_get_float], [modbus], [have_modbus=yes])
if test "x${have_modbus}" = xno; then
AC_MSG_ERROR([
------------------------------------------
The modbus library and header file
required to build zbxmodbus. Stopping...
Check 'config.log' for more information.
------------------------------------------])
fi
PKG_CHECK_MODULES([LIBMODBUS], [libmodbus >= 3.1.1], [],
[AC_MSG_ERROR([
------------------------------------------
libmodbus 3.1.1 or higher is required.
Versions below that can cause serious performance issues with pollers
because of bugged timeout handling. Please download and build latest
libmodbus from http://libmodbus.org/
------------------------------------------])
])



#Zabbix 2.4 / Zabbix 3.0 / 3.2 chooser
AC_ARG_ENABLE([zabbix-2],
Expand Down
1 change: 1 addition & 0 deletions libmodbus
Submodule libmodbus added at 681b43
7 changes: 4 additions & 3 deletions src/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
lib_LTLIBRARIES = libzbxmodbus.la

libzbxmodbus_la_SOURCES = \
modbus.c
libzbxmodbus_la_CFLAGS = $(LIBMODBUS_CFLAGS)
libzbxmodbus_la_CFLAGS = -I$(top_srcdir)/libmodbus/src

if ZABBIX_2
libzbxmodbus_la_CFLAGS += -I../include/zabbix-2.4
Expand All @@ -12,8 +13,8 @@ endif
if ZABBIX_3_2
libzbxmodbus_la_CFLAGS += -I../include/zabbix-3.2
endif

libzbxmodbus_la_LDFLAGS = $(LIBMODBUS_LIBS) \
libzbxmodbus_la_LIBADD = $(top_srcdir)/libmodbus/src/libmodbus.la
libzbxmodbus_la_LDFLAGS = \
-module \
-shared \
-avoid-version
110 changes: 76 additions & 34 deletions src/modbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,18 @@
#define MODBUS_PDU_ADDRESS_0 0
#define MODBUS_PROTOCOL_ADDRESS_1 1

#define LOCK_SERIAL_PORT sem_lock(MODBUS_SEM_ID)
#define UNLOCK_SERIAL_PORT sem_unlock(MODBUS_SEM_ID)
#define NSEMS 128

#define LOCK_PORT(x) sem_lock(x)
#define UNLOCK_PORT(x) sem_unlock(x)


//semaphore constants
#define MODBUS_SEM_KEY "."
int MODBUS_SEM_ID = -1;
#define ZBX_MUTEX int
#define ZBX_MUTEX_NULL -1
#define ZBX_MUTEX_ERROR 1
#define ZBX_MUTEX_ERROR -1
#define ZBX_MUTEX_OK 1
#define ZBX_MUTEX_NAME int
#define MAX_RETRIES 10
Expand All @@ -68,7 +71,7 @@ union semun {
static int item_timeout = 0;
static ZBX_MUTEX serial_port_access = ZBX_MUTEX_NULL;
int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result);
void create_modbus_context(char *con_string, modbus_t **ctx_out, int *lock_required_out);
void create_modbus_context(char *con_string, modbus_t **ctx_out, int *lock_required_out, short *lock_key);
int param_is_empty(char *param_to_check);
int validate_datatype_param (char *datatype_param);
int initsem();
Expand All @@ -80,6 +83,7 @@ static ZBX_METRIC keys[] =
/* KEY FLAG FUNCTION TEST PARAMETERS */
{
{"modbus_read_registers", CF_HAVEPARAMS, zbx_modbus_read_registers, NULL},
{"modbus_read", CF_HAVEPARAMS, zbx_modbus_read_registers, NULL},
{NULL}
};

Expand Down Expand Up @@ -126,7 +130,17 @@ ZBX_METRIC *zbx_module_item_list()
return keys;
}

//generate hash for nsem pseudo unique number.
unsigned long hash(unsigned char *str)
{
unsigned long hash = 5381;
int c;

while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

return hash;
}

/******************************************************************************
* *
Expand Down Expand Up @@ -183,14 +197,13 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result)
return SYSINFO_RET_FAIL;
}


modbus_t *ctx;
int lock_required;



short lock_key = 0;

create_modbus_context(param1,&ctx,&lock_required);

create_modbus_context(param1,&ctx,&lock_required, &lock_key);
if (ctx == NULL) {
SET_MSG_RESULT(result, strdup("Unable to create the libmodbus context"));
modbus_free(ctx);
Expand Down Expand Up @@ -280,13 +293,7 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result)
}
}

/* 3.0.3
struct timeval response_timeout ;
response_timeout.tv_sec = 0;
response_timeout.tv_usec = 0;

modbus_set_response_timeout(ctx, &response_timeout);
*/
modbus_set_response_timeout(ctx, item_timeout, 0);

//read part
Expand All @@ -296,12 +303,14 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result)
int regs_to_read = 1;
if (datatype == MODBUS_FLOAT || datatype == MODBUS_LONG) { regs_to_read=2;}

if (lock_required == 1 ) LOCK_SERIAL_PORT;


if (lock_required == 1 ) LOCK_PORT(lock_key);

if (modbus_connect(ctx) == -1) {
SET_MSG_RESULT(result, strdup(modbus_strerror(errno)));
modbus_free(ctx);
if (lock_required == 1 ) UNLOCK_SERIAL_PORT;
if (lock_required == 1 ) UNLOCK_PORT(lock_key);
return SYSINFO_RET_FAIL;
}

Expand All @@ -323,14 +332,14 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result)
SET_MSG_RESULT(result, strdup("Check function (1,2,3,4) used"));
//close connection
modbus_close(ctx);
if (lock_required == 1 ) UNLOCK_SERIAL_PORT;
if (lock_required == 1 ) UNLOCK_PORT(lock_key);
modbus_free(ctx);
return SYSINFO_RET_FAIL;
break;
}
//close connection
modbus_close(ctx);
if (lock_required == 1 ) UNLOCK_SERIAL_PORT;
if (lock_required == 1 ) UNLOCK_PORT(lock_key);
modbus_free(ctx);

if (rc == -1) {
Expand Down Expand Up @@ -407,7 +416,7 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result)
int zbx_module_init()
{
if (ZBX_MUTEX_ERROR == (MODBUS_SEM_ID = initsem())) {
//"unable to create semaphore set for serial port"));
printf("libzbxmodbus: unable to create semaphores. Please check maximum allowed nsem, it must be no less than %d. See limits in /proc/sys/kernel/sem\n", NSEMS);
return ZBX_MODULE_FAIL;
}

Expand Down Expand Up @@ -442,33 +451,65 @@ int validate_datatype_param (char *datatype_param) {//checks that datatype provi
return (datatype_param[1] == '\0') ? 1: 0;
}

void create_modbus_context(char *con_string, modbus_t **ctx_out, int *lock_required_out) {
void create_modbus_context(char *con_string, modbus_t **ctx_out, int *lock_required_out, short *lock_key) {

char first_char = con_string[0];

if (first_char == '/') {//then its rtu(serial con)
// -- next code is to parse first arg and find all required to connect to rtu successfully
*lock_required_out = 1;
// -- next code is to parse first arg and find all required to connect to rtu successfully
char rtu_port[100];
int rtu_speed = 9600;
char rtu_parity = 'N';
int rtu_bits = 8;
int rtu_stop_bit = 1;

sscanf(con_string,"%s %d %c %d %d",rtu_port,&rtu_speed,&rtu_parity,&rtu_bits,&rtu_stop_bit);
*lock_required_out = 1;
*lock_key = hash(rtu_port) % 128;
*ctx_out = modbus_new_rtu(rtu_port, rtu_speed, rtu_parity, rtu_bits, rtu_stop_bit);

}
else {//try modbus_tcp
*lock_required_out = 0;
*ctx_out = modbus_new_tcp(con_string, MODBUS_TCP_DEFAULT_PORT );
else {//its TCP (encapsulated or Modbus TCP)

char host[100];
int port = MODBUS_TCP_DEFAULT_PORT;

if (strstr(con_string, "enc://") != NULL) {

*lock_required_out = 1;
memmove(con_string, con_string+6, strlen(con_string));
sscanf(con_string, "%99[^:]:%99d[^\n]", host, &port);
*lock_key = hash(host) % NSEMS;
*ctx_out = modbus_new_rtutcp(host, port);

} else if (strstr(con_string, "tcp://") != NULL) {

*lock_required_out = 0;
memmove(con_string, con_string+6, strlen(con_string));
sscanf(con_string, "%99[^:]:%99d[^\n]", host, &port);
*lock_key = hash(host) % NSEMS;
*ctx_out = modbus_new_tcp(host, port);

}
else {//try Modbus TCP

*lock_required_out = 0;
sscanf(con_string, "%99[^:]:%99d[^\n]", host, &port);
*lock_key = hash(host) % NSEMS;
*ctx_out = modbus_new_tcp(host, port);

}
}

return;
}




int initsem() /* sem_key from ftok() */
{
int nsems = 1;
int nsems = NSEMS;
key_t sem_key;
int semid;
int i;
Expand Down Expand Up @@ -496,7 +537,7 @@ int initsem() /* sem_key from ftok() */
int e = errno;
semctl(semid, 0, IPC_RMID); /* clean up */
errno = e;
return -1; /* error, check errno */
return ZBX_MUTEX_ERROR; /* error, check errno */
}
}
} else if (errno == EEXIST) { /* someone else got it first */
Expand All @@ -516,7 +557,7 @@ int initsem() /* sem_key from ftok() */
}
if (!ready) {
errno = ETIME;
return -1;
return ZBX_MUTEX_ERROR;
}
} else {
return semid; /* error, check errno */
Expand All @@ -525,10 +566,10 @@ int initsem() /* sem_key from ftok() */
}


void sem_lock () {
void sem_lock (int sem_num) {
struct sembuf sb;

sb.sem_num = 0;
sb.sem_num = sem_num;
sb.sem_op = -1; /* set to allocate resource */
sb.sem_flg = SEM_UNDO;

Expand All @@ -539,10 +580,10 @@ void sem_lock () {
}


void sem_unlock () {
void sem_unlock (int sem_num) {
struct sembuf sb;

sb.sem_num = 0;
sb.sem_num = sem_num;
sb.sem_op = 1; /* free resource */
sb.sem_flg = SEM_UNDO;

Expand All @@ -557,5 +598,6 @@ void sem_uninit (int semid) {

if (semctl(semid, 0, IPC_RMID) == -1) {
//zabbix_log(LOG_LEVEL_ERROR, "Failed to destroy semaphore set for semid: %d",MODBUS_SEM_ID);
printf("libzbxmodbus: failed to destroy semaphore set for semid: %d",MODBUS_SEM_ID);
}
}
}

0 comments on commit 4a1f226

Please sign in to comment.