void TSerialPort::Open() { if (Fd >= 0) throw TSerialDeviceException("port already open"); if (modbus_connect(Context->Inner) < 0) throw TSerialDeviceException("cannot open serial port"); Fd = modbus_get_socket(Context->Inner); }
static int ctx_get_socket(lua_State *L) { ctx_t *ctx = ctx_check(L, 1); lua_pushinteger(L, modbus_get_socket(ctx->modbus)); return 1; }
static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */ mb_data_t *data) { uint16_t values[2] = { 0 }; int values_num; const data_set_t *ds; int status = 0; if ((host == NULL) || (slave == NULL) || (data == NULL)) return (EINVAL); ds = plugin_get_ds (data->type); if (ds == NULL) { ERROR ("Modbus plugin: Type \"%s\" is not defined.", data->type); return (-1); } if (ds->ds_num != 1) { ERROR ("Modbus plugin: The type \"%s\" has %zu 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)) { 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.", data->type, DS_TYPE_TO_STRING (ds->ds[0].type)); } if ((data->register_type == REG_TYPE_INT32) || (data->register_type == REG_TYPE_UINT32) || (data->register_type == REG_TYPE_FLOAT)) values_num = 2; else values_num = 1; if (host->connection == NULL) { status = EBADF; } else if (host->conntype == MBCONN_TCP) { /* getpeername() is used only to determine if the socket is connected, not * because we're really interested in the peer's IP address. */ status = getpeername (modbus_get_socket (host->connection), (struct sockaddr *) &(struct sockaddr_storage) { 0 }, &(socklen_t) { sizeof (struct sockaddr_storage) }); if (status != 0) status = errno; }
int main(int argc, char*argv[]) { int s = -1; modbus_t *ctx; modbus_mapping_t *mb_mapping; int rc; int i; int use_backend; uint8_t *query; int header_length; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { use_backend = TCP; } else if (strcmp(argv[1], "tcppi") == 0) { use_backend = TCP_PI; } else if (strcmp(argv[1], "rtu") == 0) { use_backend = RTU; } else { printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus server for unit testing\n\n", argv[0]); return -1; } } else { /* By default */ use_backend = TCP; } if (use_backend == TCP) { ctx = modbus_new_tcp("127.0.0.1", 1502); query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); } else if (use_backend == TCP_PI) { ctx = modbus_new_tcp_pi("::0", "1502"); query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); } else { ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); modbus_set_slave(ctx, SERVER_ID); query = malloc(MODBUS_RTU_MAX_ADU_LENGTH); } header_length = modbus_get_header_length(ctx); modbus_set_debug(ctx, TRUE); mb_mapping = modbus_mapping_new( UT_BITS_ADDRESS + UT_BITS_NB, UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB, UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } /* Unit tests of modbus_mapping_new (tests would not be sufficient if two nb_* were identical) */ if (mb_mapping->nb_bits != UT_BITS_ADDRESS + UT_BITS_NB) { printf("Invalid nb bits (%d != %d)\n", UT_BITS_ADDRESS + UT_BITS_NB, mb_mapping->nb_bits); modbus_free(ctx); return -1; } if (mb_mapping->nb_input_bits != UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB) { printf("Invalid nb input bits: %d\n", UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB); modbus_free(ctx); return -1; } if (mb_mapping->nb_registers != UT_REGISTERS_ADDRESS + UT_REGISTERS_NB) { printf("Invalid nb registers: %d\n", UT_REGISTERS_ADDRESS + UT_REGISTERS_NB); modbus_free(ctx); return -1; } if (mb_mapping->nb_input_registers != UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB) { printf("Invalid nb input registers: %d\n", UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB); modbus_free(ctx); return -1; } /* Examples from PI_MODBUS_300.pdf. Only the read-only input values are assigned. */ /** INPUT STATUS **/ modbus_set_bits_from_bytes(mb_mapping->tab_input_bits, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, UT_INPUT_BITS_TAB); /** INPUT REGISTERS **/ for (i=0; i < UT_INPUT_REGISTERS_NB; i++) { mb_mapping->tab_input_registers[UT_INPUT_REGISTERS_ADDRESS+i] = UT_INPUT_REGISTERS_TAB[i];; } if (use_backend == TCP) { s = modbus_tcp_listen(ctx, 1); modbus_tcp_accept(ctx, &s); } else if (use_backend == TCP_PI) { s = modbus_tcp_pi_listen(ctx, 1); modbus_tcp_pi_accept(ctx, &s); } else { rc = modbus_connect(ctx); if (rc == -1) { fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } } for (;;) { do { rc = modbus_receive(ctx, query); /* Filtered queries return 0 */ } while (rc == 0); /* The connection is not closed on errors which require on reply such as bad CRC in RTU. */ if (rc == -1 && errno != EMBBADCRC) { /* Quit */ break; } /* Special server behavior to test client */ if (query[header_length] == 0x03) { /* Read holding registers */ if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 3) == UT_REGISTERS_NB_SPECIAL) { printf("Set an incorrect number of values\n"); MODBUS_SET_INT16_TO_INT8(query, header_length + 3, UT_REGISTERS_NB_SPECIAL - 1); } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == UT_REGISTERS_ADDRESS_SPECIAL) { printf("Reply to this special register address by an exception\n"); modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY); continue; } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE) { const int RAW_REQ_LENGTH = 5; uint8_t raw_req[] = { (use_backend == RTU) ? INVALID_SERVER_ID : 0xFF, 0x03, 0x02, 0x00, 0x00 }; printf("Reply with an invalid TID or slave\n"); modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t)); continue; } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == UT_REGISTERS_ADDRESS_SLEEP_500_MS) { printf("Sleep 0.5 s before replying\n"); usleep(500000); } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) { /* Test low level only available in TCP mode */ /* Catch the reply and send reply byte a byte */ uint8_t req[] = "\x00\x1C\x00\x00\x00\x05\xFF\x03\x02\x00\x00"; int req_length = 11; int w_s = modbus_get_socket(ctx); /* Copy TID */ req[1] = query[1]; for (i=0; i < req_length; i++) { printf("(%.2X)", req[i]); usleep(5000); send(w_s, (const char*)(req + i), 1, MSG_NOSIGNAL); } continue; } } rc = modbus_reply(ctx, query, rc, mb_mapping); if (rc == -1) { break; } } printf("Quit the loop: %s\n", modbus_strerror(errno)); if (use_backend == TCP) { if (s != -1) { close(s); } } modbus_mapping_free(mb_mapping); free(query); /* For RTU */ modbus_close(ctx); modbus_free(ctx); return 0; }
RETURN_NUMBER(modbus_set_error_recovery((modbus_t *)(SYS_INT)PARAM(0), (modbus_error_recovery_mode)PARAM(1))) END_IMPL //------------------------------------------------------------------------ CONCEPT_FUNCTION_IMPL(modbus_set_socket, 2) T_HANDLE(modbus_set_socket, 0) // modbus_t* T_NUMBER(modbus_set_socket, 1) // int modbus_set_socket((modbus_t *)(SYS_INT)PARAM(0), (int)PARAM(1)); RETURN_NUMBER(0) END_IMPL //------------------------------------------------------------------------ CONCEPT_FUNCTION_IMPL(modbus_get_socket, 1) T_HANDLE(modbus_get_socket, 0) // modbus_t* RETURN_NUMBER(modbus_get_socket((modbus_t *)(SYS_INT)PARAM(0))) END_IMPL //------------------------------------------------------------------------ CONCEPT_FUNCTION_IMPL(modbus_get_header_length, 1) T_HANDLE(modbus_get_header_length, 0) // modbus_t* RETURN_NUMBER(modbus_get_header_length((modbus_t *)(SYS_INT)PARAM(0))) END_IMPL //------------------------------------------------------------------------ CONCEPT_FUNCTION_IMPL(modbus_connect, 1) T_HANDLE(modbus_connect, 0) // modbus_t* RETURN_NUMBER(modbus_connect((modbus_t *)(SYS_INT)PARAM(0))) END_IMPL //------------------------------------------------------------------------ CONCEPT_FUNCTION_IMPL(modbus_close, 1)
retCode get_tx_connection(const int this_mb_tx_num, int *ret_connected) { char *fnct_name = "get_tx_connection"; int ret; mb_tx_t *this_mb_tx; mb_link_t *this_mb_link; int this_mb_link_num; struct timeval timeout; if (this_mb_tx_num < 0 || this_mb_tx_num > gbl.tot_mb_tx) { ERR(gbl.init_dbg, "parameter out of range this_mb_tx_num[%d]", this_mb_tx_num); return retERR; } this_mb_tx = &gbl.mb_tx[this_mb_tx_num]; if (ret_connected == NULL) { ERR(this_mb_tx->cfg_debug, "NULL pointer"); return retERR; } this_mb_link_num = this_mb_tx->mb_link_num; if (this_mb_link_num < 0 || this_mb_link_num >= gbl.tot_mb_links) { ERR(this_mb_tx->cfg_debug, "parameter out of range this_mb_link_num[%d]", this_mb_link_num); return retERR; } this_mb_link = &gbl.mb_links[this_mb_link_num]; *ret_connected = 0; //defaults to not connected if (modbus_get_socket(this_mb_link->modbus) < 0) { ret = modbus_connect(this_mb_link->modbus); if (ret != 0 || modbus_get_socket(this_mb_link->modbus) < 0) { modbus_set_socket(this_mb_link->modbus, -1); //some times ret was < 0 and fd > 0 ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] cannot connect to link, ret[%d] fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, ret, modbus_get_socket(this_mb_link->modbus)); return retOK; //not connected } DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] new connection -> fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, modbus_get_socket(this_mb_link->modbus)); } else { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] already connected to fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, modbus_get_socket(this_mb_link->modbus)); } //set slave id according to each mb_tx ret = modbus_set_slave(this_mb_link->modbus, this_mb_tx->mb_tx_slave_id); if (ret != 0) { ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] cannot set slave [%d]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_tx_slave_id); return retOK; //not connected } //set the low level mb_link debug according to each mb_tx modbus_set_debug(this_mb_link->modbus, this_mb_tx->protocol_debug); //set response and byte timeout according to each mb_tx timeout.tv_sec = this_mb_tx->mb_response_timeout_ms / 1000; timeout.tv_usec = (this_mb_tx->mb_response_timeout_ms % 1000) * 1000; #if (LIBMODBUS_VERSION_CHECK(3, 1, 2)) modbus_set_response_timeout(this_mb_link->modbus, timeout.tv_sec, timeout.tv_usec); #else modbus_set_response_timeout(this_mb_link->modbus, &timeout); #endif //DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] response timeout [%d] ([%d] [%d])", // this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_response_timeout_ms, // (int) timeout.tv_sec, (int) timeout.tv_usec); timeout.tv_sec = this_mb_tx->mb_byte_timeout_ms / 1000; timeout.tv_usec = (this_mb_tx->mb_byte_timeout_ms % 1000) * 1000; #if (LIBMODBUS_VERSION_CHECK(3, 1, 2)) modbus_set_byte_timeout(this_mb_link->modbus, timeout.tv_sec, timeout.tv_usec); #else modbus_set_byte_timeout(this_mb_link->modbus, &timeout); #endif //DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] byte timeout [%d] ([%d] [%d])", // this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_byte_timeout_ms, // (int) timeout.tv_sec, (int) timeout.tv_usec); *ret_connected = 1; //is connected (fd >= 0) return retOK; }
void *link_loop_and_logic(void *thrd_link_num) { char *fnct_name = "link_loop_and_logic"; int ret, ret_available, ret_connected; int tx_counter; mb_tx_t *this_mb_tx = NULL; int this_mb_tx_num; mb_link_t *this_mb_link = NULL; int this_mb_link_num; if (thrd_link_num == NULL) { ERR(gbl.init_dbg, "NULL pointer"); return NULL; } this_mb_link_num = *((int *)thrd_link_num); if (this_mb_link_num < 0 || this_mb_link_num >= gbl.tot_mb_links) { ERR(gbl.init_dbg, "parameter out of range this_mb_link_num[%d]", this_mb_link_num); return NULL; } this_mb_link = &gbl.mb_links[this_mb_link_num]; while (1) { for (tx_counter = 0; tx_counter < gbl.tot_mb_tx; tx_counter++) { if (gbl.quit_flag != 0) { //tell the threads to quit (SIGTERM o SGIQUIT) (unloadusr mb2hal). return NULL; } this_mb_tx_num = tx_counter; this_mb_tx = &gbl.mb_tx[this_mb_tx_num]; DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] going to TEST availability", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); //corresponding link and time (update_rate) if (is_this_tx_ready(this_mb_link_num, this_mb_tx_num, &ret_available) != retOK) { ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] is_this_tx_ready ERR", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); return NULL; } if (ret_available == 0) { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] NOT available", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); usleep(1000); continue; } DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] going to TEST connection", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); //first time connection or reconnection, run time parameters setting if (get_tx_connection(this_mb_tx_num, &ret_connected) != retOK) { ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] get_tx_connection ERR", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); return NULL; } if (ret_connected == 0) { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] NOT connected", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); usleep(1000); continue; } DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] lk_dbg[%d] going to EXECUTE transaction", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus), this_mb_tx->protocol_debug); switch (this_mb_tx->mb_tx_fnct) { case mbtx_02_READ_DISCRETE_INPUTS: ret = fnct_02_read_discrete_inputs(this_mb_tx, this_mb_link); break; case mbtx_03_READ_HOLDING_REGISTERS: ret = fnct_03_read_holding_registers(this_mb_tx, this_mb_link); break; case mbtx_04_READ_INPUT_REGISTERS: ret = fnct_04_read_input_registers(this_mb_tx, this_mb_link); break; case mbtx_06_WRITE_SINGLE_REGISTER: ret = fnct_06_write_single_register(this_mb_tx, this_mb_link); break; case mbtx_15_WRITE_MULTIPLE_COILS: ret = fnct_15_write_multiple_coils(this_mb_tx, this_mb_link); break; case mbtx_16_WRITE_MULTIPLE_REGISTERS: ret = fnct_16_write_multiple_registers(this_mb_tx, this_mb_link); break; default: ret = -1; ERR(this_mb_tx->cfg_debug, "case error with mb_tx_fnct %d [%s] in mb_tx_num[%d]", this_mb_tx->mb_tx_fnct, this_mb_tx->mb_tx_fnct_name, this_mb_tx_num); break; } if (gbl.quit_flag != 0) { //tell the threads to quit (SIGTERM o SGIQUIT) (unloadusr mb2hal). return NULL; } if (ret != retOK && modbus_get_socket(this_mb_link->modbus) < 0) { //link failure (*this_mb_tx->num_errors)++; ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] link failure, going to close link", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus)); modbus_close(this_mb_link->modbus); } else if (ret != retOK) { //transaction failure but link OK (**this_mb_tx->num_errors)++; ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] transaction failure, num_errors[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus), **this_mb_tx->num_errors); // Clear any unread data. Otherwise the link might get out of sync modbus_flush(this_mb_link->modbus); } else { //transaction and link OK OK(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] transaction OK, update_HZ[%0.03f]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus), 1.0/(get_time()-this_mb_tx->last_time_ok)); this_mb_tx->last_time_ok = get_time(); (**this_mb_tx->num_errors) = 0; } //set the next (waiting) time for update rate this_mb_tx->next_time = get_time() + this_mb_tx->time_increment; //wait time for serial lines if (this_mb_tx->cfg_link_type == linkRTU) { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] SERIAL_DELAY_MS activated [%d]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus), this_mb_tx->cfg_serial_delay_ms); usleep(this_mb_tx->cfg_serial_delay_ms * 1000); } //wait time to gbl.slowdown activity (debugging) if (gbl.slowdown > 0) { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] thread[%d] fd[%d] gbl.slowdown activated [%0.3f]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_link_num, modbus_get_socket(this_mb_link->modbus), gbl.slowdown); usleep(gbl.slowdown * 1000 * 1000); } } //end for } //end while return NULL; }
static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */ mb_data_t *data) { uint16_t values[2]; int values_num; const data_set_t *ds; int status; if ((host == NULL) || (slave == NULL) || (data == NULL)) return (EINVAL); ds = plugin_get_ds (data->type); if (ds == NULL) { ERROR ("Modbus plugin: Type \"%s\" is not defined.", data->type); return (-1); } if (ds->ds_num != 1) { ERROR ("Modbus plugin: The type \"%s\" has %i 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)) { 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.", data->type, DS_TYPE_TO_STRING (ds->ds[0].type)); } memset (values, 0, sizeof (values)); if ((data->register_type == REG_TYPE_INT32) || (data->register_type == REG_TYPE_UINT32) || (data->register_type == REG_TYPE_FLOAT)) values_num = 2; else values_num = 1; status = 0; if (host->connection == NULL) { status = EBADF; } else if (host->conntype == MBCONN_TCP) { struct sockaddr sockaddr; socklen_t saddrlen = sizeof (sockaddr); status = getpeername (modbus_get_socket (host->connection), &sockaddr, &saddrlen); if (status != 0) status = errno; } if ((status == EBADF) || (status == ENOTSOCK) || (status == ENOTCONN)) { status = mb_init_connection (host); if (status != 0) { ERROR ("Modbus plugin: mb_init_connection (%s/%s) failed. ", host->host, host->node); host->is_connected = 0; host->connection = NULL; return (-1); } } else if (status != 0) { #if LEGACY_LIBMODBUS modbus_close (&host->connection); #else modbus_close (host->connection); modbus_free (host->connection); #endif } #if LEGACY_LIBMODBUS /* Version 2.0.3: Pass the connection struct as a pointer and pass the slave * id to each call of "read_holding_registers". */ # define modbus_read_registers(ctx, addr, nb, dest) \ read_holding_registers (&(ctx), slave->id, (addr), (nb), (dest)) #else /* if !LEGACY_LIBMODBUS */ /* Version 2.9.2: Set the slave id once before querying the registers. */ status = modbus_set_slave (host->connection, slave->id); if (status != 0) { ERROR ("Modbus plugin: modbus_set_slave (%i) failed with status %i.", slave->id, status); return (-1); } #endif if (data->modbus_register_type == MREG_INPUT){ status = modbus_read_input_registers (host->connection, /* start_addr = */ data->register_base, /* num_registers = */ values_num, /* buffer = */ values); } else{ status = modbus_read_registers (host->connection, /* start_addr = */ data->register_base, /* num_registers = */ values_num, /* buffer = */ values); } 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); #if LEGACY_LIBMODBUS modbus_close (&host->connection); #else modbus_close (host->connection); modbus_free (host->connection); #endif host->connection = NULL; return (-1); } DEBUG ("Modbus plugin: mb_read_data: Success! " "modbus_read_registers returned with status %i.", status); if (data->register_type == REG_TYPE_FLOAT) { float float_value; value_t vt; float_value = mb_register_to_float (values[0], values[1]); DEBUG ("Modbus plugin: mb_read_data: " "Returned float value is %g", (double) float_value); CAST_TO_VALUE_T (ds, vt, float_value); mb_submit (host, slave, data, vt); } else if (data->register_type == REG_TYPE_INT32) { union { uint32_t u32; int32_t i32; } v; value_t vt; v.u32 = (((uint32_t) values[0]) << 16) | ((uint32_t) values[1]); DEBUG ("Modbus plugin: mb_read_data: " "Returned int32 value is %"PRIi32, v.i32); CAST_TO_VALUE_T (ds, vt, v.i32); mb_submit (host, slave, data, vt); } else if (data->register_type == REG_TYPE_INT16) { union { uint16_t u16; int16_t i16; } v; value_t vt; v.u16 = values[0]; DEBUG ("Modbus plugin: mb_read_data: " "Returned int16 value is %"PRIi16, v.i16); CAST_TO_VALUE_T (ds, vt, v.i16); mb_submit (host, slave, data, vt); } else if (data->register_type == REG_TYPE_UINT32) { uint32_t v32; value_t vt; v32 = (((uint32_t) values[0]) << 16) | ((uint32_t) values[1]); DEBUG ("Modbus plugin: mb_read_data: " "Returned uint32 value is %"PRIu32, v32); CAST_TO_VALUE_T (ds, vt, v32); mb_submit (host, slave, data, vt); } else /* if (data->register_type == REG_TYPE_UINT16) */ { value_t vt; DEBUG ("Modbus plugin: mb_read_data: " "Returned uint16 value is %"PRIu16, values[0]); CAST_TO_VALUE_T (ds, vt, values[0]); mb_submit (host, slave, data, vt); } return (0); } /* }}} int mb_read_data */