From: Markus Heidelberg Date: Sun, 11 Dec 2022 00:28:55 +0000 (+0100) Subject: bindings: add u32/SR_T_UINT32 support for config keys X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=0db1b189bee3ffe5c6ea39d7ca2e62715856b538;p=libsigrok.git bindings: add u32/SR_T_UINT32 support for config keys 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 ] --- diff --git a/bindings/cxx/ConfigKey_methods.cpp b/bindings/cxx/ConfigKey_methods.cpp index 7381c922..d899ddcc 100644 --- a/bindings/cxx/ConfigKey_methods.cpp +++ b/bindings/cxx/ConfigKey_methods.cpp @@ -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::max()) + throw std::out_of_range("stou32"); + return ret; +} + Glib::VariantBase ConfigKey::parse_string(std::string value, enum sr_datatype dt) { GVariant *variant; @@ -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); } diff --git a/bindings/cxx/classes.cpp b/bindings/cxx/classes.cpp index de600d03..d5477847 100644 --- a/bindings/cxx/classes.cpp +++ b/bindings/cxx/classes.cpp @@ -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); } diff --git a/bindings/python/sigrok/core/classes.i b/bindings/python/sigrok/core/classes.i index eb557d03..8bccae1d 100644 --- a/bindings/python/sigrok/core/classes.i +++ b/bindings/python/sigrok/core/classes.i @@ -340,6 +340,8 @@ Glib::VariantBase python_to_variant_by_key(PyObject *input, const sigrok::Config return Glib::Variant::create(PyFloat_AsDouble(input)); else if (type == SR_T_INT32 && PyInt_Check(input)) return Glib::Variant::create(PyInt_AsLong(input)); + else if (type == SR_T_UINT32 && PyInt_Check(input)) + return Glib::Variant::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); @@ -369,6 +371,8 @@ Glib::VariantBase python_to_variant_by_option(PyObject *input, return Glib::Variant::create(PyFloat_AsDouble(input)); else if (type == G_VARIANT_TYPE_INT32 && PyInt_Check(input)) return Glib::Variant::create(PyInt_AsLong(input)); + else if (type == G_VARIANT_TYPE_UINT32 && PyInt_Check(input)) + return Glib::Variant::create(PyInt_AsLong(input)); else throw sigrok::Error(SR_ERR_ARG); } diff --git a/bindings/ruby/classes.i b/bindings/ruby/classes.i index 13496a86..fbd7c36c 100644 --- a/bindings/ruby/classes.i +++ b/bindings/ruby/classes.i @@ -236,6 +236,8 @@ Glib::VariantBase ruby_to_variant_by_key(VALUE input, const sigrok::ConfigKey *k return Glib::Variant::create(RFLOAT_VALUE(input)); else if (type == SR_T_INT32 && RB_TYPE_P(input, T_FIXNUM)) return Glib::Variant::create(NUM2INT(input)); + else if (type == SR_T_UINT32 && RB_TYPE_P(input, T_FIXNUM)) + return Glib::Variant::create(NUM2UINT(input)); else throw sigrok::Error(SR_ERR_ARG); } @@ -261,6 +263,8 @@ Glib::VariantBase ruby_to_variant_by_option(VALUE input, std::shared_ptr::create(RFLOAT_VALUE(input)); else if (variant.is_of_type(Glib::VARIANT_TYPE_INT32) && RB_TYPE_P(input, T_FIXNUM)) return Glib::Variant::create(NUM2INT(input)); + else if (variant.is_of_type(Glib::VARIANT_TYPE_UINT32) && RB_TYPE_P(input, T_FIXNUM)) + return Glib::Variant::create(NUM2UINT(input)); else throw sigrok::Error(SR_ERR_ARG); } diff --git a/include/libsigrok/libsigrok.h b/include/libsigrok/libsigrok.h index 42614fd0..5300fbe1 100644 --- a/include/libsigrok/libsigrok.h +++ b/include/libsigrok/libsigrok.h @@ -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! */ }; diff --git a/src/hwdriver.c b/src/hwdriver.c index 572748ac..7b497e07 100644 --- a/src/hwdriver.c +++ b/src/hwdriver.c @@ -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: