X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=blobdiff_plain;f=type_decoder.c;h=cde2900b01a22f083539d0f751e82a7fa9633212;hp=d21e92d5d0df76501c0ceb7722e3089e3be7279d;hb=HEAD;hpb=11c6995e4bdaf176e1a38b8ee642217cdb98dfda diff --git a/type_decoder.c b/type_decoder.c index d21e92d..6932cde 100644 --- a/type_decoder.c +++ b/type_decoder.c @@ -33,7 +33,7 @@ typedef struct { /* This is only used for nicer srd_dbg() output. */ SRD_PRIV const char *output_type_name(unsigned int idx) { - static const char names[][16] = { + static const char *names[] = { "OUTPUT_ANN", "OUTPUT_PYTHON", "OUTPUT_BINARY", @@ -67,16 +67,16 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, /* Should be a list of [annotation class, [string, ...]]. */ if (!PyList_Check(obj)) { - srd_err("Protocol decoder %s submitted an annotation that" - " is not a list", di->decoder->name); + srd_err("Protocol decoder %s submitted an annotation that is not a list", + di->decoder->name); goto err; } /* Should have 2 elements. */ if (PyList_Size(obj) != 2) { - srd_err("Protocol decoder %s submitted annotation list with " - "%zd elements instead of 2", di->decoder->name, - PyList_Size(obj)); + ssize_t sz = PyList_Size(obj); + srd_err("Protocol decoder %s submitted annotation list with %zd elements instead of 2", + di->decoder->name, sz); goto err; } @@ -86,27 +86,27 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, */ py_tmp = PyList_GetItem(obj, 0); if (!PyLong_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted annotation list, but " - "first element was not an integer.", di->decoder->name); + srd_err("Protocol decoder %s submitted annotation list, but first element was not an integer.", + di->decoder->name); goto err; } ann_class = PyLong_AsLong(py_tmp); if (!(pdo = g_slist_nth_data(di->decoder->annotations, ann_class))) { - srd_err("Protocol decoder %s submitted data to unregistered " - "annotation class %d.", di->decoder->name, ann_class); + srd_err("Protocol decoder %s submitted data to unregistered annotation class %d.", + di->decoder->name, ann_class); goto err; } /* Second element must be a list. */ py_tmp = PyList_GetItem(obj, 1); if (!PyList_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted annotation list, but " - "second element was not a list.", di->decoder->name); + srd_err("Protocol decoder %s submitted annotation list, but second element was not a list.", + di->decoder->name); goto err; } if (py_strseq_to_char(py_tmp, &ann_text) != SRD_OK) { - srd_err("Protocol decoder %s submitted annotation list, but " - "second element was malformed.", di->decoder->name); + srd_err("Protocol decoder %s submitted annotation list, but second element was malformed.", + di->decoder->name); goto err; } @@ -235,38 +235,38 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, /* Should have 2 elements. */ if (PyList_Size(obj) != 2) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list " - "with %zd elements instead of 2", di->decoder->name, - PyList_Size(obj)); + ssize_t sz = PyList_Size(obj); + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list with %zd elements instead of 2", + di->decoder->name, sz); goto err; } /* The first element should be an integer. */ py_tmp = PyList_GetItem(obj, 0); if (!PyLong_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " - "but first element was not an integer.", di->decoder->name); + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, but first element was not an integer.", + di->decoder->name); goto err; } bin_class = PyLong_AsLong(py_tmp); if (!(class_name = g_slist_nth_data(di->decoder->binary, bin_class))) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with " - "unregistered binary class %d.", di->decoder->name, bin_class); + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with unregistered binary class %d.", + di->decoder->name, bin_class); goto err; } /* Second element should be bytes. */ py_tmp = PyList_GetItem(obj, 1); if (!PyBytes_Check(py_tmp)) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " - "but second element was not bytes.", di->decoder->name); + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, but second element was not bytes.", + di->decoder->name); goto err; } /* Consider an empty set of bytes a bug. */ if (PyBytes_Size(py_tmp) == 0) { - srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY " - "with empty data set.", di->decoder->name); + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with empty data set.", + di->decoder->name); goto err; } @@ -359,8 +359,8 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) if (g_variant_type_equal(pdata->pdo->meta_type, G_VARIANT_TYPE_INT64)) { if (!PyLong_Check(obj)) { - PyErr_Format(PyExc_TypeError, "This output was registered " - "as 'int', but something else was passed."); + PyErr_Format(PyExc_TypeError, + "This output was registered as 'int', but something else was passed."); goto err; } intvalue = PyLong_AsLongLong(obj); @@ -369,8 +369,8 @@ static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) pdata->data = g_variant_new_int64(intvalue); } else if (g_variant_type_equal(pdata->pdo->meta_type, G_VARIANT_TYPE_DOUBLE)) { if (!PyFloat_Check(obj)) { - PyErr_Format(PyExc_TypeError, "This output was registered " - "as 'float', but something else was passed."); + PyErr_Format(PyExc_TypeError, + "This output was registered as 'float', but something else was passed."); goto err; } dvalue = PyFloat_AsDouble(obj); @@ -482,9 +482,9 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) start_sample, end_sample, output_type_name(pdo->output_type), output_id, pdo->proto_id, next_di->inst_id); - if (!(py_res = PyObject_CallMethod( - next_di->py_inst, "decode", "KKO", start_sample, - end_sample, py_data))) { + py_res = PyObject_CallMethod(next_di->py_inst, "decode", + "KKO", start_sample, end_sample, py_data); + if (!py_res) { srd_exception_catch("Calling %s decode() failed", next_di->inst_id); } @@ -1089,6 +1089,27 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) /* Signal the main thread that we handled all samples. */ g_cond_signal(&di->handled_all_samples_cond); + /* + * When EOF was provided externally, communicate the + * Python EOFError exception to .decode() and return + * from the .wait() method call. This is motivated by + * the use of Python context managers, so that .decode() + * methods can "close" incompletely accumulated data + * when the sample data is exhausted. + */ + if (di->communicate_eof) { + /* Advance self.samplenum to the (absolute) last sample number. */ + py_samplenum = PyLong_FromUnsignedLongLong(di->abs_cur_samplenum); + PyObject_SetAttrString(di->py_inst, "samplenum", py_samplenum); + Py_DECREF(py_samplenum); + /* Raise an EOFError Python exception. */ + srd_dbg("%s: %s: Raising EOF from wait().", + di->inst_id, __func__); + g_mutex_unlock(&di->data_mutex); + PyErr_SetString(PyExc_EOFError, "samples exhausted"); + goto err; + } + /* * When termination of wait() and decode() was requested, * then exit the loop after releasing the mutex. @@ -1196,7 +1217,7 @@ static PyMethodDef Decoder_methods[] = { Decoder_has_channel, METH_VARARGS, Decoder_has_channel_doc, }, - {NULL, NULL, 0, NULL} + ALL_ZERO, }; /** @@ -1213,7 +1234,7 @@ SRD_PRIV PyObject *srd_Decoder_type_new(void) { Py_tp_doc, Decoder_doc }, { Py_tp_methods, Decoder_methods }, { Py_tp_new, (void *)&PyType_GenericNew }, - { 0, NULL } + ALL_ZERO, }; PyObject *py_obj; PyGILState_STATE gstate;