decoder: internal 'always false' term, handle invalid skip and channel
authorGerhard Sittig <gerhard.sittig@gmx.net>
Sun, 24 Nov 2019 08:52:42 +0000 (09:52 +0100)
committerUwe Hermann <uwe@hermann-uwe.de>
Sun, 24 Nov 2019 19:41:54 +0000 (20:41 +0100)
Introduce an "always false" type for .wait() terms. Map invalid counts
of skip conditions (zero or negative numbers) as well as invalid channel
references for level/edge conditions to this type which never matches.
Keep this "always false" term type an internal detail of the common
support code.

This is most robust and least intrusive at the same time, it keeps the
existing API, and simplifies the implementation of Python decoders for
rare edge cases (optional input signals or optional features, handling
of initial samples at the very start of a capture).

This commit passes sample counts internally in a signed data type. This
is essential for proper operation, and the loss of one bit out of 64
shall not be considered a severe limitation.

This fixes bug #1444.

instance.c
libsigrokdecode-internal.h
type_decoder.c
util.c

index 36fb2d0c32889b609712ba6dc2f42a00f1aecda2..5264bd0bd3a54d72f8503e926931f542ab310d96 100644 (file)
@@ -895,6 +895,8 @@ static gboolean all_terms_match(const struct srd_decoder_inst *di,
 
        for (l = cond; l; l = l->next) {
                term = l->data;
+               if (term->type == SRD_TERM_ALWAYS_FALSE)
+                       return FALSE;
                if (!term_matches(di, term, sample_pos))
                        return FALSE;
        }
index d5a34a2536ecfea1d2c7ed77a360fa8330060262..af245f6ad197f5b75ab8a2782a0399bb43b2a95c 100644 (file)
@@ -28,6 +28,7 @@
 #include "libsigrokdecode.h"
 
 enum {
+       SRD_TERM_ALWAYS_FALSE,
        SRD_TERM_HIGH,
        SRD_TERM_LOW,
        SRD_TERM_RISING_EDGE,
@@ -123,7 +124,7 @@ SRD_PRIV int py_attr_as_strlist(PyObject *py_obj, const char *attr, GSList **out
 SRD_PRIV int py_dictitem_as_str(PyObject *py_obj, const char *key, char **outstr);
 SRD_PRIV int py_listitem_as_str(PyObject *py_obj, Py_ssize_t idx, char **outstr);
 SRD_PRIV int py_pydictitem_as_str(PyObject *py_obj, PyObject *py_key, char **outstr);
-SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t *out);
+SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, int64_t *out);
 SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr);
 SRD_PRIV int py_strseq_to_char(PyObject *py_strseq, char ***out_strv);
 SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj);
index 17204f069fa6bf866c2e1fb29c344b5c52444620..454e7ea90deea3b0a89ecf1ba6b90aaad62978e4 100644 (file)
@@ -625,18 +625,20 @@ static PyObject *get_current_pinvalues(const struct srd_decoder_inst *di)
  *
  * If there are no terms in the condition, 'term_list' will be NULL.
  *
+ * @param di The decoder instance to use. Must not be NULL.
  * @param py_dict A Python dict containing terms. Must not be NULL.
  * @param term_list Pointer to a GSList which will be set to the newly
  *                  created list of terms. Must not be NULL.
  *
  * @return SRD_OK upon success, a negative error code otherwise.
  */
-static int create_term_list(PyObject *py_dict, GSList **term_list)
+static int create_term_list(struct srd_decoder_inst *di,
+       PyObject *py_dict, GSList **term_list)
 {
        Py_ssize_t pos = 0;
        PyObject *py_key, *py_value;
        struct srd_term *term;
-       uint64_t num_samples_to_skip;
+       int64_t num_samples_to_skip;
        char *term_str;
        PyGILState_STATE gstate;
 
@@ -653,7 +655,6 @@ static int create_term_list(PyObject *py_dict, GSList **term_list)
                /* Check whether the current key is a string or a number. */
                if (PyLong_Check(py_key)) {
                        /* The key is a number. */
-                       /* TODO: Check if the number is a valid channel. */
                        /* Get the value string. */
                        if ((py_pydictitem_as_str(py_dict, py_key, &term_str)) != SRD_OK) {
                                srd_err("Failed to get the value.");
@@ -662,10 +663,12 @@ static int create_term_list(PyObject *py_dict, GSList **term_list)
                        term = g_malloc(sizeof(struct srd_term));
                        term->type = get_term_type(term_str);
                        term->channel = PyLong_AsLong(py_key);
+                       if (term->channel < 0 || term->channel >= di->dec_num_channels)
+                               term->type = SRD_TERM_ALWAYS_FALSE;
                        g_free(term_str);
                } else if (PyUnicode_Check(py_key)) {
                        /* The key is a string. */
-                       /* TODO: Check if it's "skip". */
+                       /* TODO: Check if the key is "skip". */
                        if ((py_pydictitem_as_long(py_dict, py_key, &num_samples_to_skip)) != SRD_OK) {
                                srd_err("Failed to get number of samples to skip.");
                                goto err;
@@ -674,6 +677,8 @@ static int create_term_list(PyObject *py_dict, GSList **term_list)
                        term->type = SRD_TERM_SKIP;
                        term->num_samples_to_skip = num_samples_to_skip;
                        term->num_samples_already_skipped = 0;
+                       if (num_samples_to_skip < 1)
+                               term->type = SRD_TERM_ALWAYS_FALSE;
                } else {
                        srd_err("Term key is neither a string nor a number.");
                        goto err;
@@ -784,7 +789,7 @@ static int set_new_condition_list(PyObject *self, PyObject *args)
                }
 
                /* Create the list of terms in this condition. */
-               if ((ret = create_term_list(py_dict, &term_list)) < 0)
+               if ((ret = create_term_list(di, py_dict, &term_list)) < 0)
                        break;
 
                /* Add the new condition to the PD instance's condition list. */
diff --git a/util.c b/util.c
index 442d0a6e1433c47abd035cc0f42839b8df9b4e73..b7fd4fb4900728c6df3bc186f22aa141dac0578d 100644 (file)
--- a/util.c
+++ b/util.c
@@ -303,7 +303,7 @@ err:
  *
  * @private
  */
-SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t *out)
+SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, int64_t *out)
 {
        PyObject *py_value;
        PyGILState_STATE gstate;
@@ -328,7 +328,7 @@ SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t
                goto err;
        }
 
-       *out = PyLong_AsUnsignedLongLong(py_value);
+       *out = PyLong_AsLongLong(py_value);
 
        PyGILState_Release(gstate);