From: Bert Vermeulen Date: Sun, 10 Nov 2013 11:42:11 +0000 (+0100) Subject: Implement OUTPUT_BINARY X-Git-Tag: libsigrokdecode-0.3.0~233 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=d75d8a7c40011cdc15be8330b5efbdf812c4fe27 Implement OUTPUT_BINARY This requires the PD to have a tuple in its class called 'binary', which contains a list of strings describing the different binary classes it can output. For the SPI decoder this might be 'MOSI' and 'MISO', for example. The data is submitted to the frontend as struct srd_proto_data_binary, which contains the class that data belongs to. --- diff --git a/decoder.c b/decoder.c index 01dcf0a..ef7e15d 100644 --- a/decoder.c +++ b/decoder.c @@ -245,10 +245,11 @@ err_out: */ SRD_API int srd_decoder_load(const char *module_name) { - PyObject *py_basedec, *py_method, *py_attr, *py_annlist, *py_ann; + PyObject *py_basedec, *py_method, *py_attr, *py_annlist, *py_ann, \ + *py_bin_classes, *py_bin_class; struct srd_decoder *d; - int alen, ret, i; - char **ann; + int len, ret, i; + char **ann, *bin; struct srd_probe *p; GSList *l; @@ -362,7 +363,7 @@ SRD_API int srd_decoder_load(const char *module_name) if (py_attr_as_str(d->py_dec, "license", &(d->license)) != SRD_OK) goto err_out; - /* Convert class annotation attribute to GSList of **char. */ + /* Convert annotation class attribute to GSList of char **. */ d->annotations = NULL; if (PyObject_HasAttrString(d->py_dec, "annotations")) { py_annlist = PyObject_GetAttrString(d->py_dec, "annotations"); @@ -371,8 +372,8 @@ SRD_API int srd_decoder_load(const char *module_name) "should be a list.", module_name); goto err_out; } - alen = PyList_Size(py_annlist); - for (i = 0; i < alen; i++) { + len = PyList_Size(py_annlist); + for (i = 0; i < len; i++) { py_ann = PyList_GetItem(py_annlist, i); if (!PyList_Check(py_ann) || PyList_Size(py_ann) != 2) { srd_err("Protocol decoder module %s " @@ -388,6 +389,31 @@ SRD_API int srd_decoder_load(const char *module_name) } } + /* Convert binary class to GSList of char *. */ + d->binary = NULL; + if (PyObject_HasAttrString(d->py_dec, "binary")) { + py_bin_classes = PyObject_GetAttrString(d->py_dec, "binary"); + if (!PyTuple_Check(py_bin_classes)) { + srd_err("Protocol decoder module %s binary classes " + "should be a tuple.", module_name); + goto err_out; + } + len = PyTuple_Size(py_bin_classes); + for (i = 0; i < len; i++) { + py_bin_class = PyTuple_GetItem(py_bin_classes, i); + if (!PyUnicode_Check(py_bin_class)) { + srd_err("Protocol decoder module %s binary " + "class should be a string.", module_name); + goto err_out; + } + + if (py_str_as_str(py_bin_class, &bin) != SRD_OK) { + goto err_out; + } + d->binary = g_slist_append(d->binary, bin); + } + } + /* Append it to the list of supported/loaded decoders. */ pd_list = g_slist_append(pd_list, d); diff --git a/libsigrokdecode.h.in b/libsigrokdecode.h.in index a654373..b759428 100644 --- a/libsigrokdecode.h.in +++ b/libsigrokdecode.h.in @@ -202,6 +202,12 @@ struct srd_decoder { */ GSList *annotations; + /** + * List of NULL-terminated char[], containing descriptions of the + * supported binary output. + */ + GSList *binary; + /** List of decoder options. */ GSList *options; @@ -266,6 +272,11 @@ struct srd_proto_data_annotation { int ann_format; char **ann_text; }; +struct srd_proto_data_binary { + int bin_class; + uint64_t size; + const unsigned char *data; +}; typedef void (*srd_pd_output_callback_t)(struct srd_proto_data *pdata, void *cb_data); diff --git a/type_decoder.c b/type_decoder.c index 52f7ca0..38fa1ae 100644 --- a/type_decoder.c +++ b/type_decoder.c @@ -93,6 +93,74 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, return SRD_OK; } +static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, + struct srd_proto_data *pdata) +{ + struct srd_proto_data_binary *pdb; + PyObject *py_tmp; + Py_ssize_t size; + int bin_class; + char *class_name, *buf; + + /* Should be a tuple of (binary class, bytes). */ + if (!PyTuple_Check(obj)) { + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with " + "%s instead of tuple.", di->decoder->name, + obj->ob_type->tp_name); + return SRD_ERR_PYTHON; + } + + /* Should have 2 elements. */ + if (PyTuple_Size(obj) != 2) { + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple " + "with %d elements instead of 2", di->decoder->name, + PyList_Size(obj)); + return SRD_ERR_PYTHON; + } + + /* The first element should be an integer. */ + py_tmp = PyTuple_GetItem(obj, 0); + if (!PyLong_Check(py_tmp)) { + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple, " + "but first element was not an integer.", di->decoder->name); + return SRD_ERR_PYTHON; + } + 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); + return SRD_ERR_PYTHON; + } + + /* Second element should be bytes. */ + py_tmp = PyTuple_GetItem(obj, 1); + if (!PyBytes_Check(py_tmp)) { + srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY tuple, " + "but second element was not bytes.", di->decoder->name); + return SRD_ERR_PYTHON; + } + + /* 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); + return SRD_ERR_PYTHON; + } + + if (!(pdb = g_try_malloc(sizeof(struct srd_proto_data_binary)))) + return SRD_ERR_MALLOC; + if (PyBytes_AsStringAndSize(py_tmp, &buf, &size) == -1) + return SRD_ERR_PYTHON; + pdb->bin_class = bin_class; + pdb->size = size; + if (!(pdb->data = g_try_malloc(pdb->size))) + return SRD_ERR_MALLOC; + memcpy((void *)pdb->data, (const void *)buf, pdb->size); + pdata->data = pdb; + + return SRD_OK; +} + static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) { long long intvalue; @@ -173,7 +241,7 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) case SRD_OUTPUT_ANN: /* Annotations are only fed to callbacks. */ if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) { - /* Annotations need converting from PyObject. */ + /* Convert from PyDict to srd_proto_data_annotation. */ if (convert_annotation(di, py_data, pdata) != SRD_OK) { /* An error was already logged. */ break; @@ -199,7 +267,14 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) } break; case SRD_OUTPUT_BINARY: - srd_err("SRD_OUTPUT_BINARY not yet supported."); + if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) { + /* Convert from PyDict to srd_proto_data_binary. */ + if (convert_binary(di, py_data, pdata) != SRD_OK) { + /* An error was already logged. */ + break; + } + cb->cb(pdata, cb->cb_data); + } break; case SRD_OUTPUT_META: if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) {