* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <stdio.h>
#include <glib.h>
-#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
-#include "libsigrok.h"
+#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
/** @cond PRIVATE */
*/
/** @private
- * Allocate and initialize new struct sr_channel
+ * Allocate and initialize new struct sr_channel and add to sdi.
+ * @param[in] sdi The device instance the channel is connected to.
* @param[in] index @copydoc sr_channel::index
* @param[in] type @copydoc sr_channel::type
* @param[in] enabled @copydoc sr_channel::enabled
* @param[in] name @copydoc sr_channel::name
*
- * @return NULL (failure) or new struct sr_channel*.
+ * @return A new struct sr_channel*.
*/
-SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
- gboolean enabled, const char *name)
+SR_PRIV struct sr_channel *sr_channel_new(struct sr_dev_inst *sdi,
+ int index, int type, gboolean enabled, const char *name)
{
struct sr_channel *ch;
- if (!(ch = g_try_malloc0(sizeof(struct sr_channel)))) {
- sr_err("Channel malloc failed.");
- return NULL;
- }
-
+ ch = g_malloc0(sizeof(struct sr_channel));
+ ch->sdi = sdi;
ch->index = index;
ch->type = type;
ch->enabled = enabled;
if (name)
ch->name = g_strdup(name);
+ sdi->channels = g_slist_append(sdi->channels, ch);
+
return ch;
}
/**
- * Set the name of the specified channel in the specified device.
+ * Set the name of the specified channel.
*
* If the channel already has a different name assigned to it, it will be
* removed, and the new name will be saved instead.
*
- * @param sdi The device instance the channel is connected to.
- * @param[in] channelnum The number of the channel whose name to set.
- * Note that the channel numbers start at 0.
- * @param[in] name The new name that the specified channel should get. A copy
- * of the string is made.
+ * @param[in] channel The channel whose name to set.
+ * @param[in] name The new name that the specified channel should get. A
+ * copy of the string is made.
*
* @return SR_OK on success, or SR_ERR_ARG on invalid arguments.
*
* @since 0.3.0
*/
-SR_API int sr_dev_channel_name_set(const struct sr_dev_inst *sdi,
- int channelnum, const char *name)
+SR_API int sr_dev_channel_name_set(struct sr_channel *channel,
+ const char *name)
{
- GSList *l;
- struct sr_channel *ch;
- int ret;
-
- if (!sdi) {
- sr_err("%s: sdi was NULL", __func__);
+ if (!channel) {
+ sr_err("%s: channel was NULL", __func__);
return SR_ERR_ARG;
}
- ret = SR_ERR_ARG;
- for (l = sdi->channels; l; l = l->next) {
- ch = l->data;
- if (ch->index == channelnum) {
- g_free(ch->name);
- ch->name = g_strdup(name);
- ret = SR_OK;
- break;
- }
- }
-
- return ret;
+ g_free(channel->name);
+ channel->name = g_strdup(name);
+ return SR_OK;
}
/**
- * Enable or disable a channel on the specified device.
+ * Enable or disable a channel.
*
- * @param sdi The device instance the channel is connected to.
- * @param channelnum The channel number, starting from 0.
- * @param state TRUE to enable the channel, FALSE to disable.
+ * @param[in] channel The channel to enable or disable.
+ * @param[in] state TRUE to enable the channel, FALSE to disable.
*
* @return SR_OK on success or SR_ERR on failure. In case of invalid
* arguments, SR_ERR_ARG is returned and the channel enabled state
*
* @since 0.3.0
*/
-SR_API int sr_dev_channel_enable(const struct sr_dev_inst *sdi, int channelnum,
+SR_API int sr_dev_channel_enable(struct sr_channel *channel,
gboolean state)
{
- GSList *l;
- struct sr_channel *ch;
int ret;
gboolean was_enabled;
+ struct sr_dev_inst *sdi;
- if (!sdi)
+ if (!channel)
return SR_ERR_ARG;
- ret = SR_ERR_ARG;
- for (l = sdi->channels; l; l = l->next) {
- ch = l->data;
- if (ch->index == channelnum) {
- was_enabled = ch->enabled;
- ch->enabled = state;
- ret = SR_OK;
- if (!state != !was_enabled && sdi->driver
- && sdi->driver->config_channel_set) {
- ret = sdi->driver->config_channel_set(
- sdi, ch, SR_CHANNEL_SET_ENABLED);
- /* Roll back change if it wasn't applicable. */
- if (ret == SR_ERR_ARG)
- ch->enabled = was_enabled;
- }
- break;
- }
+ sdi = channel->sdi;
+ was_enabled = channel->enabled;
+ channel->enabled = state;
+ if (!state != !was_enabled && sdi->driver
+ && sdi->driver->config_channel_set) {
+ ret = sdi->driver->config_channel_set(
+ sdi, channel, SR_CHANNEL_SET_ENABLED);
+ /* Roll back change if it wasn't applicable. */
+ if (ret != SR_OK)
+ return ret;
}
- return ret;
+ return SR_OK;
+}
+
+/* Returns the next enabled channel, wrapping around if necessary. */
+SR_PRIV struct sr_channel *sr_next_enabled_channel(const struct sr_dev_inst *sdi,
+ struct sr_channel *cur_channel)
+{
+ struct sr_channel *next_channel;
+ GSList *l;
+
+ next_channel = cur_channel;
+ do {
+ l = g_slist_find(sdi->channels, next_channel);
+ if (l && l->next)
+ next_channel = l->next->data;
+ else
+ next_channel = sdi->channels->data;
+ } while (!next_channel->enabled);
+
+ return next_channel;
}
/**
ret = FALSE;
devopts = g_variant_get_fixed_array(gvar, &num_opts, sizeof(int32_t));
for (i = 0; i < num_opts; i++) {
- if (devopts[i] == key) {
+ if ((devopts[i] & SR_CONF_MASK) == key) {
ret = TRUE;
break;
}
return ret;
}
-/** @private
- * Allocate and init new device instance struct.
- * @param[in] index @copydoc sr_dev_inst::index
- * @param[in] status @copydoc sr_dev_inst::status
- * @param[in] vendor @copydoc sr_dev_inst::vendor
- * @param[in] model @copydoc sr_dev_inst::model
- * @param[in] version @copydoc sr_dev_inst::version
- *
- * @retval NULL Error
- * @retval struct sr_dev_inst *. Dynamically allocated, free using
- * sr_dev_inst_free().
+/**
+ * Allocate and init a new user-generated device instance.
+ *
+ * @param vendor Device vendor
+ * @param model Device model
+ * @param version Device version
+ *
+ * @retval struct sr_dev_inst *. Dynamically allocated, free using
+ * sr_dev_inst_free().
*/
-SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int status,
- const char *vendor, const char *model, const char *version)
+SR_API struct sr_dev_inst *sr_dev_inst_user_new(const char *vendor,
+ const char *model, const char *version)
{
struct sr_dev_inst *sdi;
- if (!(sdi = g_try_malloc(sizeof(struct sr_dev_inst)))) {
- sr_err("Device instance malloc failed.");
- return NULL;
- }
+ sdi = g_malloc0(sizeof(struct sr_dev_inst));
- sdi->driver = NULL;
- sdi->status = status;
- sdi->inst_type = -1;
- sdi->vendor = vendor ? g_strdup(vendor) : NULL;
- sdi->model = model ? g_strdup(model) : NULL;
- sdi->version = version ? g_strdup(version) : NULL;
- sdi->serial_num = NULL;
- sdi->connection_id = NULL;
- sdi->channels = NULL;
- sdi->channel_groups = NULL;
- sdi->session = NULL;
- sdi->conn = NULL;
- sdi->priv = NULL;
+ sdi->vendor = g_strdup(vendor);
+ sdi->model = g_strdup(model);
+ sdi->version = g_strdup(version);
+ sdi->inst_type = SR_INST_USER;
return sdi;
}
+/**
+ * Add a new channel to the specified device instance.
+ */
+SR_API int sr_dev_inst_channel_add(struct sr_dev_inst *sdi, int index, int type, const char *name)
+{
+ if (!sdi || sdi->inst_type != SR_INST_USER || index < 0)
+ return SR_ERR_ARG;
+
+ sr_channel_new(sdi, index, type, TRUE, name);
+
+ return SR_OK;
+}
+
/** @private
* Free device instance struct created by sr_dev_inst().
- * @param sdi struct* to free.
+ * @param sdi device instance to free.
*/
SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
{
struct sr_channel *ch;
+ struct sr_channel_group *cg;
GSList *l;
for (l = sdi->channels; l; l = l->next) {
}
g_slist_free(sdi->channels);
- if (sdi->channel_groups)
- g_slist_free(sdi->channel_groups);
+ for (l = sdi->channel_groups; l; l = l->next) {
+ cg = l->data;
+ g_free(cg->name);
+ g_slist_free(cg->channels);
+ g_free(cg->priv);
+ g_free(cg);
+ }
+ g_slist_free(sdi->channel_groups);
g_free(sdi->vendor);
g_free(sdi->model);
* @param[in] address @copydoc sr_usb_dev_inst::address
* @param[in] hdl @copydoc sr_usb_dev_inst::devhdl
*
- * @retval NULL Error
* @retval other struct sr_usb_dev_inst * for USB device instance.
*/
SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
{
struct sr_usb_dev_inst *udi;
- if (!(udi = g_try_malloc(sizeof(struct sr_usb_dev_inst)))) {
- sr_err("USB device instance malloc failed.");
- return NULL;
- }
-
+ udi = g_malloc0(sizeof(struct sr_usb_dev_inst));
udi->bus = bus;
udi->address = address;
udi->devhdl = hdl;
*
* @param[in] port OS-specific serial port specification. Examples:
* "/dev/ttyUSB0", "/dev/ttyACM1", "/dev/tty.Modem-0", "COM1".
+ * Must not be NULL.
* @param[in] serialcomm A serial communication parameters string, in the form
* of \<speed\>/\<data bits\>\<parity\>\<stopbits\>, for example
* "9600/8n1" or "600/7o2". This is an optional parameter;
- * it may be filled in later.
+ * it may be filled in later. Can be NULL.
*
* @return A pointer to a newly initialized struct sr_serial_dev_inst,
* or NULL on error.
{
struct sr_serial_dev_inst *serial;
- if (!port) {
- sr_err("Serial port required.");
- return NULL;
- }
-
- if (!(serial = g_try_malloc0(sizeof(struct sr_serial_dev_inst)))) {
- sr_err("Serial device instance malloc failed.");
- return NULL;
- }
-
+ serial = g_malloc0(sizeof(struct sr_serial_dev_inst));
serial->port = g_strdup(port);
if (serialcomm)
serial->serialcomm = g_strdup(serialcomm);
{
struct sr_usbtmc_dev_inst *usbtmc;
- if (!device) {
- sr_err("Device name required.");
- return NULL;
- }
-
- if (!(usbtmc = g_try_malloc0(sizeof(struct sr_usbtmc_dev_inst)))) {
- sr_err("USBTMC device instance malloc failed.");
- return NULL;
- }
-
+ usbtmc = g_malloc0(sizeof(struct sr_usbtmc_dev_inst));
usbtmc->device = g_strdup(device);
usbtmc->fd = -1;
SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
{
if (driver && driver->dev_list)
- return driver->dev_list();
+ return driver->dev_list(driver);
else
return NULL;
}
}
if (driver->dev_clear)
- ret = driver->dev_clear();
+ ret = driver->dev_clear(driver);
else
ret = std_dev_clear(driver, NULL);
return ret;
}
+/**
+ * Queries a device instances' driver.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The driver instance or NULL on error.
+ */
+SR_API struct sr_dev_driver *sr_dev_inst_driver_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi || !sdi->driver)
+ return NULL;
+
+ return sdi->driver;
+}
+
+/**
+ * Queries a device instances' vendor.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The vendor string or NULL.
+ */
+SR_API const char *sr_dev_inst_vendor_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->vendor;
+}
+
+/**
+ * Queries a device instances' model.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The model string or NULL.
+ */
+SR_API const char *sr_dev_inst_model_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->model;
+}
+
+/**
+ * Queries a device instances' version.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The version string or NULL.
+ */
+SR_API const char *sr_dev_inst_version_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->version;
+}
+
+/**
+ * Queries a device instances' serial number.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The serial number string or NULL.
+ */
+SR_API const char *sr_dev_inst_sernum_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->serial_num;
+}
+
+/**
+ * Queries a device instances' connection identifier.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return A copy of the connection id string or NULL. The caller is responsible
+ * for g_free()ing the string when it is no longer needed.
+ */
+SR_API const char *sr_dev_inst_connid_get(const struct sr_dev_inst *sdi)
+{
+#ifdef HAVE_LIBUSB_1_0
+ struct drv_context *drvc;
+ int cnt, i, a, b;
+ char connection_id[64];
+ struct sr_usb_dev_inst *usb;
+ struct libusb_device **devlist;
+#endif
+
+ if (!sdi)
+ return NULL;
+
+#ifdef HAVE_LIBSERIALPORT
+ struct sr_serial_dev_inst *serial;
+
+ if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_SERIAL)) {
+ /* connection_id isn't populated, let's do that here. */
+
+ serial = sdi->conn;
+ ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(serial->port);
+ }
+#endif
+
+#ifdef HAVE_LIBUSB_1_0
+ if ((!sdi->connection_id) && (sdi->inst_type == SR_INST_USB)) {
+ /* connection_id isn't populated, let's do that here. */
+
+ drvc = sdi->driver->context;
+ usb = sdi->conn;
+
+ if ((cnt = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist)) < 0) {
+ sr_err("Failed to retrieve device list: %s.",
+ libusb_error_name(cnt));
+ return NULL;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ /* Find the USB device by the logical address we know. */
+ b = libusb_get_bus_number(devlist[i]);
+ a = libusb_get_device_address(devlist[i]);
+ if (b != usb->bus || a != usb->address)
+ continue;
+
+ usb_get_port_path(devlist[i], connection_id, sizeof(connection_id));
+ ((struct sr_dev_inst *)sdi)->connection_id = g_strdup(connection_id);
+ break;
+ }
+
+ libusb_free_device_list(devlist, 1);
+ }
+#endif
+
+ return sdi->connection_id;
+}
+
+/**
+ * Queries a device instances' channel list.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The GSList of channels or NULL.
+ */
+SR_API GSList *sr_dev_inst_channels_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->channels;
+}
+
+/**
+ * Queries a device instances' channel groups list.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return The GSList of channel groups or NULL.
+ */
+SR_API GSList *sr_dev_inst_channel_groups_get(const struct sr_dev_inst *sdi)
+{
+ if (!sdi)
+ return NULL;
+
+ return sdi->channel_groups;
+}
+
/** @} */