Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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;
  }
Example #4
0
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)
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
0
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 */