diff --git a/README.md b/README.md index 164fd9f..3b8cfbc 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,8 @@ Resource locking (via IPC semaphores) is used when using RTU or Encapsulated Mod ## 1.B Install from tar.gz Download from https://share.zabbix.com/dir-libraries/zabbix-loadable-modules/modbus-loadable-module - - `tar zxvpf libzbxmodbus-0.6.tar.gz` - - `cd libzbxmodbus-0.6` + - `tar zxvpf libzbxmodbus-0.7.tar.gz` + - `cd libzbxmodbus-0.7` - `./configure --prefix=/etc/zabbix --enable-zabbix-[2|3|3.2]` - `make` - `make install` @@ -86,17 +86,26 @@ and some optional params can be provided as well: * **datatype(optional):** provide datatype as single char: - b - for MODBUS_BIT - i - for MODBUS_INTEGER (unsigned) - s - for MODBUS_SIGNED_INT (NOTE: in Zabbix use 'Type of information' Numeric(float) ) - l - for MODBUS_LONG - f - for MODBUS_FLOAT + `b` - for MODBUS_BIT + `i` - for MODBUS_INTEGER (unsigned) + `s` - for MODBUS_SIGNED_INT (NOTE: in Zabbix use 'Type of information' Numeric(float) ) + `l` - for MODBUS_LONG, 32bit + `f` - for MODBUS_FLOAT, 32bit + + There is also experimental support added for 64bit Modbus datatypes: + `S` - for MODBUS_SIGNED_INT64 (NOTE: in Zabbix use 'Type of information' Numeric(float) ) + `I` - for MODBUS_INT64 (unsigned) (NOTE: in Zabbix use 'Type of information' Numeric(unsigned) ) + `d` - for MODBUS_FLOAT64, 64 bit + otherwise, defaults will be used: MODBUS_BIT if modbus function 1 or 2. MODBUS_INTEGER if modbus_function 3 or 4. + + Please also note Zabbix datatypes constraints when working with 64bit: + https://www.zabbix.com/documentation/3.4/manual/config/items * **endianness(optional):** - Modbus endianness for long and float 32bit datatypes: + Modbus endianness(word swap) for long and float 32bit/64bit datatypes: 0 - for MODBUS_16BIT_LE (16 bit little endian) 1 - for MODBUS_16BIT_BE (16 bit big endian) default is BE diff --git a/configure.ac b/configure.ac index 9c6220c..3b1d181 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([libzbxmodbus], [0.6]) +AC_INIT([libzbxmodbus], [0.7]) AM_INIT_AUTOMAKE([foreign -Wall -Werror]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SUBDIRS([libmodbus]) diff --git a/src/modbus.c b/src/modbus.c index 9b967e5..486b08e 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -38,6 +38,9 @@ #define MODBUS_SIGNED_INT 's' #define MODBUS_LONG 'l' #define MODBUS_FLOAT 'f' +#define MODBUS_SIGNED_INT64 'S' +#define MODBUS_INT64 'I' +#define MODBUS_FLOAT64 'd' #define MODBUS_16BIT_LE 0 #define MODBUS_16BIT_BE 1 @@ -141,6 +144,18 @@ unsigned long hash(unsigned char *str) return hash; } +/* Get a float from 8 bytes (Modbus) with swapped words (GH EF CD AB) */ +double modbus_get_double(const uint16_t *src) +{ + double d; + uint64_t i; + + i = (((uint64_t)src[3]) << 48) + (((uint64_t)src[2]) << 32) + (((uint64_t)src[1]) << 16) + src[0]; + memcpy(&d, &i, sizeof(double)); + + return d; +} + /****************************************************************************** * * * Function: zbx_modbus_read_registers * @@ -301,6 +316,7 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result) uint8_t tab_reg_bits[64]; int regs_to_read = 1; if (datatype == MODBUS_FLOAT || datatype == MODBUS_LONG) { regs_to_read=2;} + else if (datatype == MODBUS_SIGNED_INT64 || datatype == MODBUS_INT64 || datatype == MODBUS_FLOAT64) { regs_to_read=4;} @@ -347,7 +363,7 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result) } //post-parsing - uint16_t temp_arr[2]; //output based on datatype + uint16_t temp_arr[4]; //output based on datatype switch(datatype){ case MODBUS_BIT: @@ -367,8 +383,7 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result) if (end == MODBUS_16BIT_LE) { temp_arr[0] = tab_reg[0]; temp_arr[1] = tab_reg[1]; - } - if (end == MODBUS_16BIT_BE) { + } else if (end == MODBUS_16BIT_BE) { temp_arr[0] = tab_reg[1]; temp_arr[1] = tab_reg[0]; } @@ -377,15 +392,65 @@ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result) case MODBUS_LONG: //MODBUS_GET_INT32_FROM_INT16 is doing BIG_ENDIAN for register pair, so inverse registers (sort of hack) - if (end == MODBUS_16BIT_LE) { + if (end == MODBUS_16BIT_LE) {//word swap temp_arr[0] = tab_reg[1]; temp_arr[1] = tab_reg[0]; + } else if (end == MODBUS_16BIT_BE) { + temp_arr[0] = tab_reg[0]; + temp_arr[1] = tab_reg[1]; + } + SET_UI64_RESULT(result, MODBUS_GET_INT32_FROM_INT16(temp_arr, 0)); + break; + + case MODBUS_SIGNED_INT64: + if (end == MODBUS_16BIT_LE) { + temp_arr[0] = tab_reg[3]; + temp_arr[1] = tab_reg[2]; + temp_arr[2] = tab_reg[1]; + temp_arr[3] = tab_reg[0]; } if (end == MODBUS_16BIT_BE) { temp_arr[0] = tab_reg[0]; temp_arr[1] = tab_reg[1]; + temp_arr[2] = tab_reg[2]; + temp_arr[3] = tab_reg[3]; } - SET_UI64_RESULT(result, MODBUS_GET_INT32_FROM_INT16(temp_arr, 0)); + SET_DBL_RESULT(result, ((int64_t)MODBUS_GET_INT64_FROM_INT16(temp_arr,0))); + break; + + case MODBUS_INT64: + //INT64 + if (end == MODBUS_16BIT_LE) { + temp_arr[0] = tab_reg[3]; + temp_arr[1] = tab_reg[2]; + temp_arr[2] = tab_reg[1]; + temp_arr[3] = tab_reg[0]; + } + if (end == MODBUS_16BIT_BE) { + temp_arr[0] = tab_reg[0]; + temp_arr[1] = tab_reg[1]; + temp_arr[2] = tab_reg[2]; + temp_arr[3] = tab_reg[3]; + } + + SET_UI64_RESULT(result, ((uint64_t)MODBUS_GET_INT64_FROM_INT16(temp_arr,0))); + break; + + case MODBUS_FLOAT64: + + if (end == MODBUS_16BIT_LE) { + temp_arr[0] = tab_reg[3]; + temp_arr[1] = tab_reg[2]; + temp_arr[2] = tab_reg[1]; + temp_arr[3] = tab_reg[0]; + } + if (end == MODBUS_16BIT_BE) { + temp_arr[0] = tab_reg[0]; + temp_arr[1] = tab_reg[1]; + temp_arr[2] = tab_reg[2]; + temp_arr[3] = tab_reg[3]; + } + SET_DBL_RESULT(result, modbus_get_double(temp_arr)); break; default :