Skip to content

Commit

Permalink
bindings: add u32/SR_T_UINT32 support for config keys
Browse files Browse the repository at this point in the history
Previous bindings for C++ and other languages lacked support for the
uint32_t data type for config keys. Which terminated the program with
the message:

  Exception: internal error

The following PulseView commands reproduced the issue:

  $ pulseview -i /dev/null -I csv:single_column=1
  $ pulseview -i /dev/null -I csv:first_column=1
  $ pulseview -i /dev/null -I csv:logic_channels=1
  $ pulseview -i /dev/null -I csv:start_line=1

  $ pulseview -i /dev/null -I saleae:wordsize=1
  $ pulseview -i /dev/null -I saleae:logic_channels=1

  $ pulseview -i /dev/null -I vcd:numchannels=1

Add support for uint32_t data types in the C++, Python, and Ruby
language bindings.

[ gsi: separate stou32() helper ]
  • Loading branch information
marcows authored and gsigh committed Dec 19, 2022
1 parent f806de1 commit 0db1b18
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 0 deletions.
21 changes: 21 additions & 0 deletions bindings/cxx/ConfigKey_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ static inline unsigned long stoul(const std::string &str)
}
#endif

// Conversion from text to uint32_t, including a range check.
// This is sigrok specific, _not_ part of any C++ standard library.
static uint32_t stou32(const std::string &str)
{
unsigned long ret;
errno = 0;
ret = stoul(str);
if (errno == ERANGE)
throw std::out_of_range("stou32");
if (ret > std::numeric_limits<uint32_t>::max())
throw std::out_of_range("stou32");
return ret;
}

Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt)
{
GVariant *variant;
Expand Down Expand Up @@ -139,6 +153,13 @@ Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt
throw Error(SR_ERR_ARG);
}
break;
case SR_T_UINT32:
try {
variant = g_variant_new_uint32(stou32(value));
} catch (invalid_argument&) {
throw Error(SR_ERR_ARG);
}
break;
default:
throw Error(SR_ERR_BUG);
}
Expand Down
2 changes: 2 additions & 0 deletions bindings/cxx/classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,8 @@ Glib::VariantBase Option::parse_string(string value)
dt = SR_T_FLOAT;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_INT32)) {
dt = SR_T_INT32;
} else if (g_variant_is_of_type(tmpl, G_VARIANT_TYPE_UINT32)) {
dt = SR_T_UINT32;
} else {
throw Error(SR_ERR_BUG);
}
Expand Down
4 changes: 4 additions & 0 deletions bindings/python/sigrok/core/classes.i
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::Config
return Glib::Variant<double>::create(PyFloat_AsDouble(input));
else if (type == SR_T_INT32 && PyInt_Check(input))
return Glib::Variant<gint32>::create(PyInt_AsLong(input));
else if (type == SR_T_UINT32 && PyInt_Check(input))
return Glib::Variant<guint32>::create(PyInt_AsLong(input));
else if ((type == SR_T_RATIONAL_VOLT) && PyTuple_Check(input) && (PyTuple_Size(input) == 2)) {
PyObject *numObj = PyTuple_GetItem(input, 0);
PyObject *denomObj = PyTuple_GetItem(input, 1);
Expand Down Expand Up @@ -369,6 +371,8 @@ Glib::VariantBase python_to_variant_by_option(PyObject *input,
return Glib::Variant<double>::create(PyFloat_AsDouble(input));
else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input))
return Glib::Variant<gint32>::create(PyInt_AsLong(input));
else if (type == G_VARIANT_TYPE_UINT32 && PyInt_Check(input))
return Glib::Variant<guint32>::create(PyInt_AsLong(input));
else
throw sigrok::Error(SR_ERR_ARG);
}
Expand Down
4 changes: 4 additions & 0 deletions bindings/ruby/classes.i
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ Glib::VariantBase ruby_to_variant_by_key(VALUE input, const sigrok::ConfigKey *k
return Glib::Variant<double>::create(RFLOAT_VALUE(input));
else if (type == SR_T_INT32 && RB_TYPE_P(input, T_FIXNUM))
return Glib::Variant<gint32>::create(NUM2INT(input));
else if (type == SR_T_UINT32 && RB_TYPE_P(input, T_FIXNUM))
return Glib::Variant<guint32>::create(NUM2UINT(input));
else
throw sigrok::Error(SR_ERR_ARG);
}
Expand All @@ -261,6 +263,8 @@ Glib::VariantBase ruby_to_variant_by_option(VALUE input, std::shared_ptr<sigrok:
return Glib::Variant<double>::create(RFLOAT_VALUE(input));
else if (variant.is_of_type(Glib::VARIANT_TYPE_INT32) && RB_TYPE_P(input, T_FIXNUM))
return Glib::Variant<gint32>::create(NUM2INT(input));
else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT32) && RB_TYPE_P(input, T_FIXNUM))
return Glib::Variant<guint32>::create(NUM2UINT(input));
else
throw sigrok::Error(SR_ERR_ARG);
}
Expand Down
1 change: 1 addition & 0 deletions include/libsigrok/libsigrok.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ enum sr_datatype {
SR_T_DOUBLE_RANGE,
SR_T_INT32,
SR_T_MQ,
SR_T_UINT32,

/* Update sr_variant_type_get() (hwdriver.c) upon changes! */
};
Expand Down
2 changes: 2 additions & 0 deletions src/hwdriver.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ SR_PRIV const GVariantType *sr_variant_type_get(int datatype)
switch (datatype) {
case SR_T_INT32:
return G_VARIANT_TYPE_INT32;
case SR_T_UINT32:
return G_VARIANT_TYPE_UINT32;
case SR_T_UINT64:
return G_VARIANT_TYPE_UINT64;
case SR_T_STRING:
Expand Down

0 comments on commit 0db1b18

Please sign in to comment.