enum mb_register_type_e /* {{{ */
{ REG_TYPE_INT16,
REG_TYPE_INT32,
+ REG_TYPE_INT32_CDAB,
REG_TYPE_UINT16,
REG_TYPE_UINT32,
- REG_TYPE_FLOAT }; /* }}} */
+ REG_TYPE_UINT32_CDAB,
+ REG_TYPE_INT64,
+ REG_TYPE_UINT64,
+ REG_TYPE_FLOAT,
+ REG_TYPE_FLOAT_CDAB }; /* }}} */
+
enum mb_mreg_type_e /* {{{ */
{ MREG_HOLDING,
MREG_INPUT }; /* }}} */
mb_mreg_type_t modbus_register_type;
char type[DATA_MAX_NAME_LEN];
char instance[DATA_MAX_NAME_LEN];
+ double scale;
+ double shift;
mb_data_t *next;
}; /* }}} */
int port; /* for Modbus/TCP */
int baudrate; /* for Modbus/RTU */
mb_conntype_t conntype;
- cdtime_t interval;
mb_slave_t *slaves;
size_t slaves_num;
#else
modbus_t *connection;
#endif
- _Bool is_connected;
+ bool is_connected;
}; /* }}} */
typedef struct mb_host_s mb_host_t;
/*
* Global variables
*/
-static mb_data_t *data_definitions = NULL;
+static mb_data_t *data_definitions;
/*
* Functions
if ((host == NULL) || (slave == NULL) || (data == NULL))
return EINVAL;
- if (host->interval == 0)
- host->interval = plugin_get_interval();
-
if (slave->instance[0] == 0)
snprintf(slave->instance, sizeof(slave->instance), "slave_%i", slave->id);
vl.values = &value;
vl.values_len = 1;
- vl.interval = host->interval;
sstrncpy(vl.host, host->host, sizeof(vl.host));
sstrncpy(vl.plugin, "modbus", sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, slave->instance, sizeof(vl.plugin_instance));
return status;
}
- host->is_connected = 1;
+ host->is_connected = true;
return 0;
} /* }}} int mb_init_connection */
/* #endif LEGACY_LIBMODBUS */
} /* }}} int mb_init_connection */
#endif /* !LEGACY_LIBMODBUS */
-#define CAST_TO_VALUE_T(ds, vt, raw) \
+#define CAST_TO_VALUE_T(ds, vt, raw, scale, shift) \
do { \
if ((ds)->ds[0].type == DS_TYPE_COUNTER) \
- (vt).counter = (counter_t)(raw); \
+ (vt).counter = (((counter_t)(raw)*scale) + shift); \
else if ((ds)->ds[0].type == DS_TYPE_GAUGE) \
- (vt).gauge = (gauge_t)(raw); \
+ (vt).gauge = (((gauge_t)(raw)*scale) + shift); \
else if ((ds)->ds[0].type == DS_TYPE_DERIVE) \
- (vt).derive = (derive_t)(raw); \
+ (vt).derive = (((derive_t)(raw)*scale) + shift); \
else /* if (ds->ds[0].type == DS_TYPE_ABSOLUTE) */ \
- (vt).absolute = (absolute_t)(raw); \
+ (vt).absolute = (((absolute_t)(raw)*scale) + shift); \
} while (0)
static int mb_read_data(mb_host_t *host, mb_slave_t *slave, /* {{{ */
mb_data_t *data) {
- uint16_t values[2] = {0};
+ uint16_t values[4] = {0};
int values_num;
const data_set_t *ds;
int status = 0;
}
if (ds->ds_num != 1) {
- ERROR("Modbus plugin: The type \"%s\" has %zu data sources. "
+ ERROR("Modbus plugin: The type \"%s\" has %" PRIsz " data sources. "
"I can only handle data sets with only one data source.",
data->type, ds->ds_num);
return -1;
if ((ds->ds[0].type != DS_TYPE_GAUGE) &&
(data->register_type != REG_TYPE_INT32) &&
- (data->register_type != REG_TYPE_UINT32)) {
+ (data->register_type != REG_TYPE_INT32_CDAB) &&
+ (data->register_type != REG_TYPE_UINT32) &&
+ (data->register_type != REG_TYPE_UINT32_CDAB) &&
+ (data->register_type != REG_TYPE_INT64) &&
+ (data->register_type != REG_TYPE_UINT64)) {
NOTICE(
"Modbus plugin: The data source of type \"%s\" is %s, not gauge. "
"This will most likely result in problems, because the register type "
- "is not UINT32.",
+ "is not UINT32 or UINT64.",
data->type, DS_TYPE_TO_STRING(ds->ds[0].type));
}
if ((data->register_type == REG_TYPE_INT32) ||
+ (data->register_type == REG_TYPE_INT32_CDAB) ||
(data->register_type == REG_TYPE_UINT32) ||
- (data->register_type == REG_TYPE_FLOAT))
+ (data->register_type == REG_TYPE_UINT32_CDAB) ||
+ (data->register_type == REG_TYPE_FLOAT) ||
+ (data->register_type == REG_TYPE_FLOAT_CDAB))
values_num = 2;
+ else if ((data->register_type == REG_TYPE_INT64) ||
+ (data->register_type == REG_TYPE_UINT64))
+ values_num = 4;
else
values_num = 1;
if (status != 0) {
ERROR("Modbus plugin: mb_init_connection (%s/%s) failed. ", host->host,
host->node);
- host->is_connected = 0;
+ host->is_connected = false;
host->connection = NULL;
return -1;
}
}
if (status != values_num) {
ERROR("Modbus plugin: modbus read function (%s/%s) failed. "
- " status = %i, values_num = %i. Giving up.",
- host->host, host->node, status, values_num);
+ " status = %i, start_addr = %i, values_num = %i. Giving up.",
+ host->host, host->node, status, data->register_base, values_num);
#if LEGACY_LIBMODBUS
modbus_close(&host->connection);
#else
"Returned float value is %g",
(double)float_value);
- CAST_TO_VALUE_T(ds, vt, float_value);
+ CAST_TO_VALUE_T(ds, vt, float_value, data->scale, data->shift);
+ mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_FLOAT_CDAB) {
+ float float_value;
+ value_t vt;
+
+ float_value = mb_register_to_float(values[1], values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned float value is %g",
+ (double)float_value);
+
+ CAST_TO_VALUE_T(ds, vt, float_value, data->scale, data->shift);
mb_submit(host, slave, data, vt);
} else if (data->register_type == REG_TYPE_INT32) {
union {
"Returned int32 value is %" PRIi32,
v.i32);
- CAST_TO_VALUE_T(ds, vt, v.i32);
+ CAST_TO_VALUE_T(ds, vt, v.i32, data->scale, data->shift);
+ mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_INT32_CDAB) {
+ union {
+ uint32_t u32;
+ int32_t i32;
+ } v;
+ value_t vt;
+
+ v.u32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned int32 value is %" PRIi32,
+ v.i32);
+
+ CAST_TO_VALUE_T(ds, vt, v.i32, data->scale, data->shift);
mb_submit(host, slave, data, vt);
} else if (data->register_type == REG_TYPE_INT16) {
union {
"Returned int16 value is %" PRIi16,
v.i16);
- CAST_TO_VALUE_T(ds, vt, v.i16);
+ CAST_TO_VALUE_T(ds, vt, v.i16, data->scale, data->shift);
mb_submit(host, slave, data, vt);
} else if (data->register_type == REG_TYPE_UINT32) {
uint32_t v32;
"Returned uint32 value is %" PRIu32,
v32);
- CAST_TO_VALUE_T(ds, vt, v32);
+ CAST_TO_VALUE_T(ds, vt, v32, data->scale, data->shift);
+ mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_UINT32_CDAB) {
+ uint32_t v32;
+ value_t vt;
+
+ v32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned uint32 value is %" PRIu32,
+ v32);
+
+ CAST_TO_VALUE_T(ds, vt, v32, data->scale, data->shift);
+ mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_UINT64) {
+ uint64_t v64;
+ value_t vt;
+
+ v64 = (((uint64_t)values[0]) << 48) | (((uint64_t)values[1]) << 32) |
+ (((uint64_t)values[2]) << 16) | (((uint64_t)values[3]));
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned uint64 value is %" PRIu64,
+ v64);
+
+ CAST_TO_VALUE_T(ds, vt, v64, data->scale, data->shift);
+ mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_INT64) {
+ union {
+ uint64_t u64;
+ int64_t i64;
+ } v;
+ value_t vt;
+
+ v.u64 = (((uint64_t)values[0]) << 48) | (((uint64_t)values[1]) << 32) |
+ (((uint64_t)values[2]) << 16) | ((uint64_t)values[3]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned uint64 value is %" PRIi64,
+ v.i64);
+
+ CAST_TO_VALUE_T(ds, vt, v.i64, data->scale, data->shift);
mb_submit(host, slave, data, vt);
} else /* if (data->register_type == REG_TYPE_UINT16) */
{
"Returned uint16 value is %" PRIu16,
values[0]);
- CAST_TO_VALUE_T(ds, vt, values[0]);
+ CAST_TO_VALUE_T(ds, vt, values[0], data->scale, data->shift);
mb_submit(host, slave, data, vt);
}
data.name = NULL;
data.register_type = REG_TYPE_UINT16;
data.next = NULL;
+ data.scale = 1;
+ data.shift = 0;
status = cf_util_get_string(ci, &data.name);
if (status != 0)
else if (strcasecmp("Instance", child->key) == 0)
status = cf_util_get_string_buffer(child, data.instance,
sizeof(data.instance));
+ else if (strcasecmp("Scale", child->key) == 0)
+ status = cf_util_get_double(child, &data.scale);
+ else if (strcasecmp("Shift", child->key) == 0)
+ status = cf_util_get_double(child, &data.shift);
else if (strcasecmp("RegisterBase", child->key) == 0)
status = cf_util_get_int(child, &data.register_base);
else if (strcasecmp("RegisterType", child->key) == 0) {
data.register_type = REG_TYPE_INT16;
else if (strcasecmp("Int32", tmp) == 0)
data.register_type = REG_TYPE_INT32;
+ else if (strcasecmp("Int32LE", tmp) == 0)
+ data.register_type = REG_TYPE_INT32_CDAB;
else if (strcasecmp("Uint16", tmp) == 0)
data.register_type = REG_TYPE_UINT16;
else if (strcasecmp("Uint32", tmp) == 0)
data.register_type = REG_TYPE_UINT32;
+ else if (strcasecmp("Uint32LE", tmp) == 0)
+ data.register_type = REG_TYPE_UINT32_CDAB;
else if (strcasecmp("Float", tmp) == 0)
data.register_type = REG_TYPE_FLOAT;
+ else if (strcasecmp("FloatLE", tmp) == 0)
+ data.register_type = REG_TYPE_FLOAT_CDAB;
+ else if (strcasecmp("Uint64", tmp) == 0)
+ data.register_type = REG_TYPE_UINT64;
+ else if (strcasecmp("Int64", tmp) == 0)
+ data.register_type = REG_TYPE_INT64;
else {
ERROR("Modbus plugin: The register type \"%s\" is unknown.", tmp);
status = -1;
static int mb_config_add_host(oconfig_item_t *ci) /* {{{ */
{
+ cdtime_t interval = 0;
mb_host_t *host;
int status;
} else if (strcasecmp("Baudrate", child->key) == 0)
status = cf_util_get_int(child, &host->baudrate);
else if (strcasecmp("Interval", child->key) == 0)
- status = cf_util_get_cdtime(child, &host->interval);
+ status = cf_util_get_cdtime(child, &interval);
else if (strcasecmp("Slave", child->key) == 0)
/* Don't set status: Gracefully continue if a slave fails. */
mb_config_add_slave(host, child);
plugin_register_complex_read(/* group = */ NULL, name,
/* callback = */ mb_read,
- /* interval = */ host->interval,
+ /* interval = */ interval,
&(user_data_t){
.data = host, .free_func = host_free,
});