Ejemplo n.º 1
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;
  int i;

  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_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_UINT32)
      || (data->register_type == REG_TYPE_FLOAT))
    values_num = 2;
  else
    values_num = 1;

#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

  for (i = 0; i < 2; i++)
  {
    status = modbus_read_registers (host->connection,
        /* start_addr = */ data->register_base,
        /* num_registers = */ values_num, /* buffer = */ values);
    if (status > 0)
      break;

    if (host->is_connected)
    {
#if LEGACY_LIBMODBUS
      modbus_close (&host->connection);
      host->is_connected = 0;
#else
      modbus_close (host->connection);
      modbus_free (host->connection);
      host->connection = NULL;
#endif
    }

    /* If we already tried reconnecting this round, give up. */
    if (host->have_reconnected)
    {
      ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
          "Reconnecting has already been tried. Giving up.", host->host);
      return (-1);
    }

    /* Maybe the device closed the connection during the waiting interval.
     * Try re-establishing the connection. */
    status = mb_init_connection (host);
    if (status != 0)
    {
      ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
          "While trying to reconnect, connecting to \"%s\" failed. "
          "Giving up.",
          host->host, host->node);
      return (-1);
    }

    DEBUG ("Modbus plugin: Re-established connection to %s", host->host);

    /* try again */
    continue;
  } /* for (i = 0, 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_UINT32)
  {
    uint32_t v32;
    value_t vt;

    v32 = (values[0] << 16) | 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 */
Ejemplo n.º 2
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 */