Stacked protocol decoders implementation.
authorBert Vermeulen <bert@biot.com>
Mon, 9 Jan 2012 23:25:16 +0000 (00:25 +0100)
committerBert Vermeulen <bert@biot.com>
Mon, 9 Jan 2012 23:25:16 +0000 (00:25 +0100)
The DDC decoder takes input from the I2C PD.

controller.c
decoder.c
decoders/Makefile.am
decoders/ddc.py [new file with mode: 0644]
decoders/i2c.py
module_sigrokdecode.c
sigrokdecode.h

index a0e8bfe8d13b240a16dee82c66b4d564d58c323d..dbc4eb0fa5dcef5c8298c657e5694f8bfd463799 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "config.h"
 #include "sigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
+#include "sigrokdecode-internal.h"
+#include "config.h"
 #include <glib.h>
 #include <inttypes.h>
 
 
+static GSList *di_list = NULL;
 static GSList *callbacks = NULL;
 
-/* TODO
-static GSList *pipelines = NULL;
-struct srd_pipeline {
-       int id;
-       GSList *decoders;
-};
-*/
-
 /* lives in decoder.c */
 extern GSList *pd_list;
-extern GSList *di_list;
 
 /* lives in module_sigrokdecode.c */
 extern PyMODINIT_FUNC PyInit_sigrokdecode(void);
@@ -59,7 +52,7 @@ extern PyTypeObject srd_logic_type;
  * The caller is responsible for calling the clean-up function srd_exit(),
  * which will properly shut down libsigrokdecode and free its allocated memory.
  *
- * Multiple calls to srd_init(), without calling srd_exit() inbetween,
+ * Multiple calls to srd_init(), without calling srd_exit() in between,
  * are not allowed.
  *
  * @return SRD_OK upon success, a (negative) error code otherwise.
@@ -98,7 +91,7 @@ int srd_init(void)
  *
  * This function should only be called if there was a (successful!) invocation
  * of srd_init() before. Calling this function multiple times in a row, without
- * any successful srd_init() calls inbetween, is not allowed.
+ * any successful srd_init() calls in between, is not allowed.
  *
  * @return SRD_OK upon success, a (negative) error code otherwise.
  */
@@ -132,37 +125,58 @@ int set_modulepath(void)
 }
 
 
-struct srd_decoder_instance *srd_instance_new(const char *id)
+/**
+ * Create a new protocol decoder instance.
+ *
+ * TODO: this should be a decoder name, as decoder ids will disappear.
+ * @param id Decoder 'id' field.
+ * @param instance_id optional unique identifier for this instance. If NULL,
+ * the id parameter is used.
+ *
+ * @returns Pointer to a newly allocated struct srd_decoder_instance, or
+ * NULL in case of failure.
+ */
+struct srd_decoder_instance *srd_instance_new(const char *id,
+               const char *instance_id)
 {
        struct srd_decoder *dec;
        struct srd_decoder_instance *di;
        PyObject *py_args;
 
+       srd_dbg("%s: creating new %s instance", __func__, id);
+
        if (!(dec = srd_get_decoder_by_id(id)))
                return NULL;
 
-       /* TODO: Error handling. Use g_try_malloc(). */
-       di = g_malloc(sizeof(*di));
+       if (!(di = g_try_malloc(sizeof(*di)))) {
+               srd_err("failed to malloc instance");
+               return NULL;
+       }
        di->decoder = dec;
+       di->instance_id = g_strdup(instance_id ? instance_id : id);
        di->pd_output = NULL;
+       di->num_probes = 0;
        di->unitsize = 0;
+       di->samplerate = 0;
+       di->next_di = NULL;
 
        /* Create an empty Python tuple. */
        if (!(py_args = PyTuple_New(0))) { /* NEWREF */
                if (PyErr_Occurred())
-                       PyErr_Print(); /* Returns void. */
-
-               return NULL; /* TODO: More specific error? */
+                       PyErr_Print();
+               return NULL;
        }
 
        /* Create an instance of the 'Decoder' class. */
        di->py_instance = PyObject_Call(dec->py_decobj, py_args, NULL);
        if (!di->py_instance) {
                if (PyErr_Occurred())
-                       PyErr_Print(); /* Returns void. */
+                       PyErr_Print();
                Py_XDECREF(py_args);
-               return NULL; /* TODO: More specific error? */
+               return NULL;
        }
+
+       /* Instance takes input from a frontend by default. */
        di_list = g_slist_append(di_list, di);
 
        Py_XDECREF(py_args);
@@ -170,6 +184,29 @@ struct srd_decoder_instance *srd_instance_new(const char *id)
        return di;
 }
 
+int srd_instance_stack(struct srd_decoder_instance *di_from,
+               struct srd_decoder_instance *di_to)
+{
+
+       if (!di_from || !di_to) {
+               srd_err("invalid from/to instance pair");
+               return SRD_ERR_ARG;
+       }
+
+       if (!g_slist_find(di_list, di_from)) {
+               srd_err("unstacked instance not found");
+               return SRD_ERR_ARG;
+       }
+
+       /* Remove from the unstacked list. */
+       di_list = g_slist_remove(di_list, di_to);
+
+       /* Stack on top of source di. */
+       di_from->next_di = g_slist_append(di_from->next_di, di_to);
+
+       return SRD_OK;
+}
+
 
 int srd_instance_set_probe(struct srd_decoder_instance *di,
                           const char *probename, int num)
@@ -193,33 +230,49 @@ int srd_instance_set_probe(struct srd_decoder_instance *di,
        return SRD_OK;
 }
 
+struct srd_decoder_instance *srd_instance_find(char *instance_id)
+{
+       GSList *l;
+       struct srd_decoder_instance *tmp, *di;
 
-int srd_session_start(int num_probes, int unitsize, uint64_t samplerate)
+       di = NULL;
+       for (l = di_list; l; l = l->next) {
+               tmp = l->data;
+               if (!strcmp(tmp->instance_id, instance_id)) {
+                       di = tmp;
+                       break;
+               }
+       }
+
+       return di;
+}
+
+int srd_instance_start(struct srd_decoder_instance *di, PyObject *args)
 {
-       PyObject *py_res;
-       GSList *d;
-       struct srd_decoder_instance *di;
+       PyObject *py_name, *py_res;
 
-       for (d = di_list; d; d = d->next) {
-               di = d->data;
-               di->num_probes = num_probes;
-               di->unitsize = unitsize;
-               di->samplerate = samplerate;
-               if (!(py_res = PyObject_CallMethod(di->py_instance, "start",
-                                   "{s:l}",
-                                       "samplerate", (long)samplerate))) {
-                       if (PyErr_Occurred())
-                               PyErr_Print(); /* Returns void. */
+       srd_dbg("calling start() method on protocol decoder instance %s", di->instance_id);
 
-                       return SRD_ERR_PYTHON; /* TODO: More specific error? */
-               }
-               Py_XDECREF(py_res);
+       if (!(py_name = PyUnicode_FromString("start"))) {
+               srd_err("unable to build python object for 'start'");
+               if (PyErr_Occurred())
+                       PyErr_Print();
+               return SRD_ERR_PYTHON;
+       }
+
+       if (!(py_res = PyObject_CallMethodObjArgs(di->py_instance,
+                       py_name, args, NULL))) {
+               if (PyErr_Occurred())
+                       PyErr_Print();
+               return SRD_ERR_PYTHON;
        }
 
+       Py_XDECREF(py_res);
+       Py_DECREF(py_name);
+
        return SRD_OK;
 }
 
-
 /**
  * Run the specified decoder function.
  *
@@ -229,7 +282,7 @@ int srd_session_start(int num_probes, int unitsize, uint64_t samplerate)
  *
  * @return SRD_OK upon success, a (negative) error code otherwise.
  */
-int srd_run_decoder(uint64_t timeoffset, uint64_t duration,
+int srd_instance_decode(uint64_t timeoffset, uint64_t duration,
                struct srd_decoder_instance *di, uint8_t *inbuf, uint64_t inbuflen)
 {
        PyObject *py_instance, *py_res;
@@ -270,6 +323,41 @@ int srd_run_decoder(uint64_t timeoffset, uint64_t duration,
 }
 
 
+int srd_session_start(int num_probes, int unitsize, uint64_t samplerate)
+{
+       PyObject *args;
+       GSList *d, *s;
+       struct srd_decoder_instance *di;
+       int ret;
+
+       if (!(args = Py_BuildValue("{s:l}", "samplerate", (long)samplerate))) {
+               srd_err("unable to build python object for metadata");
+               return SRD_ERR_PYTHON;
+       }
+
+       /* Run the start() method on all decoders receiving frontend data. */
+       for (d = di_list; d; d = d->next) {
+               di = d->data;
+               di->num_probes = num_probes;
+               di->unitsize = unitsize;
+               di->samplerate = samplerate;
+               if ((ret = srd_instance_start(di, args) != SRD_OK))
+                       return ret;
+
+               /* Run the start() method on all decoders up the stack from this one. */
+               for (s = di->next_di; s; s = s->next) {
+                       /* These don't need probes, unitsize and samplerate. */
+                       di = s->data;
+                       if ((ret = srd_instance_start(di, args) != SRD_OK))
+                               return ret;
+               }
+       }
+
+       Py_DECREF(args);
+
+       return SRD_OK;
+}
+
 /* Feed logic samples to decoder session. */
 int srd_session_feed(uint64_t timeoffset, uint64_t duration, uint8_t *inbuf,
                uint64_t inbuflen)
@@ -278,7 +366,7 @@ int srd_session_feed(uint64_t timeoffset, uint64_t duration, uint8_t *inbuf,
        int ret;
 
        for (d = di_list; d; d = d->next) {
-               if ((ret = srd_run_decoder(timeoffset, duration, d->data, inbuf,
+               if ((ret = srd_instance_decode(timeoffset, duration, d->data, inbuf,
                                inbuflen)) != SRD_OK)
                        return ret;
        }
@@ -307,13 +395,19 @@ int pd_add(struct srd_decoder_instance *di, int output_type,
 
 struct srd_decoder_instance *get_di_by_decobject(void *decobject)
 {
-       GSList *l;
+       GSList *l, *s;
        struct srd_decoder_instance *di;
 
        for (l = di_list; l; l = l->next) {
                di = l->data;
                if (decobject == di->py_instance)
                        return di;
+               /* Check decoders stacked on top of this one. */
+               for (s = di->next_di; s; s = s->next) {
+                       di = s->data;
+                       if (decobject == di->py_instance)
+                               return di;
+               }
        }
 
        return NULL;
@@ -351,12 +445,3 @@ void *srd_find_callback(int output_type)
        return cb;
 }
 
-//int srd_pipeline_new(int plid)
-//{
-//
-//
-//}
-
-
-
-
index 788d2e840c6650639407564f08949717fb01a64d..d626bd39db3aae063a6f58502c0df1349fce7ced 100644 (file)
--- a/decoder.c
+++ b/decoder.c
@@ -25,7 +25,6 @@
 
 /* The list of protocol decoders. */
 GSList *pd_list = NULL;
-GSList *di_list = NULL;
 
 
 /**
index 72987f44d604dd7dc1690124f4e8477feabc647a..c27d69fd4dd81d5d3a6ade576c97734957367d09 100644 (file)
@@ -28,7 +28,8 @@ dist_pkgdata_DATA = \
        spi.py \
        srd_usb.py \
        transitioncounter.py \
-       uart.py
+       uart.py \
+       ddc.py
 
 CLEANFILES = *.pyc
 
diff --git a/decoders/ddc.py b/decoders/ddc.py
new file mode 100644 (file)
index 0000000..09f6844
--- /dev/null
@@ -0,0 +1,74 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, If not, see <http://www.gnu.org/licenses/>.
+##
+
+#
+# DDC protocol decoder
+#
+# This decoder extracts a DDC stream from an I2C session between a computer
+# and a display device. The stream is output as plain bytes.
+#
+
+import sigrokdecode
+
+
+class Decoder(sigrokdecode.Decoder):
+    id = 'ddc'
+    name = 'DDC'
+    longname = 'Display Data Channel'
+    desc = 'DDC is a protocol for communication between computers and displays.'
+    longdesc = ''
+    author = 'Bert Vermeulen <bert@biot.com>'
+    license = 'gplv3+'
+    inputs = ['i2c']
+    outputs = ['ddc']
+    annotation = [
+        ["Byte stream", "DDC byte stream as read from display."],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = None
+
+    def start(self, metadata):
+        self.output_annotation = self.add(sigrokdecode.SRD_OUTPUT_ANNOTATION, 'ddc')
+
+    def decode(self, start_sample, end_sample, i2c_data):
+        try:
+            cmd, data, ack_bit = i2c_data
+        except Exception as e:
+            raise Exception("malformed I2C input: %s" % str(e)) from e
+
+        if self.state is None:
+            # waiting for the DDC session to start
+            if cmd in ('START', 'START_REPEAT'):
+                self.state = 'start'
+        elif self.state == 'start':
+            if cmd == 'ADDRESS_READ' and data == 80:
+                # 80 is the I2C slave address of a connected display,
+                # so this marks the start of the DDC data transfer.
+                self.state = 'transfer'
+            elif cmd == 'STOP':
+                # back to idle
+                self.state = None
+        elif self.state == 'transfer':
+            if cmd == 'DATA_READ':
+                # there shouldn't be anything but data reads on this
+                # address, so ignore everything else
+                self.put(start_sample, end_sample, self.output_annotation,
+                         [0, ["0x%.2x" % data]])
+
index f098affcbbe966af5d208c85d4fc99c92ca51eaf..08d005301301371760ae816024f2a13d4c8024f6 100644 (file)
 # TODO: Implement support for 7bit and 10bit slave addresses.
 # TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0).
 # TODO: Implement support for detecting various bus errors.
-
-#
-# I2C output format:
-#
-# The output consists of a (Python) list of I2C "packets", each of which
-# has an (implicit) index number (its index in the list).
-# Each packet consists of a Python dict with certain key/value pairs.
-#
-# TODO: Make this a list later instead of a dict?
-#
-# 'type': (string)
-#   - 'S' (START condition)
-#   - 'Sr' (Repeated START)
-#   - 'AR' (Address, read)
-#   - 'AW' (Address, write)
-#   - 'DR' (Data, read)
-#   - 'DW' (Data, write)
-#   - 'P' (STOP condition)
-# 'range': (tuple of 2 integers, the min/max samplenumber of this range)
-#   - (min, max)
-#   - min/max can also be identical.
-# 'data': (actual data as integer ???) TODO: This can be very variable...
-# 'ann': (string; additional annotations / comments)
-#
 # TODO: I2C address of slaves.
 # TODO: Handle multiple different I2C devices on same bus
 #       -> we need to decode multiple protocols at the same time.
-#
 
 #
-# I2C input format:
+# I2C protocol output format:
+#
+# The protocol output consists of a (Python) list of I2C "packets", each of
+# which is of the form
+#
+#        [ _i2c_command_, _data_, _ack_bit_ ]
+#
+# _i2c_command_ is one of:
+#   - 'START' (START condition)
+#   - 'START_REPEAT' (Repeated START)
+#   - 'ADDRESS_READ' (Address, read)
+#   - 'ADDRESS_WRITE' (Address, write)
+#   - 'DATA_READ' (Data, read)
+#   - 'DATA_WRITE' (Data, write)
+#   - 'STOP' (STOP condition)
 #
-# signals:
-# [[id, channel, description], ...] # TODO
+# _data_ is the data or address byte associated with the ADDRESS_* and DATA_*
+# command. For START, START_REPEAT and STOP, this is None.
 #
-# Example:
-# {'id': 'SCL', 'ch': 5, 'desc': 'Serial clock line'}
-# {'id': 'SDA', 'ch': 7, 'desc': 'Serial data line'}
-# ...
+# _ack_bit_ is either 'ACK' or 'NACK', but may also be None.
 #
-# {'inbuf': [...],
-#  'signals': [{'SCL': }]}
 #
 
 import sigrokdecode
 
+# annotation feed formats
+ANN_SHIFTED       = 0
+ANN_SHIFTED_SHORT = 1
+ANN_RAW           = 2
+
 # values are verbose and short annotation, respectively
 protocol = {
     'START':           ['START',        'S'],
@@ -123,19 +112,12 @@ protocol = {
     'DATA_READ':       ['DATA READ',    'DR'],
     'DATA_WRITE':      ['DATA WRITE',   'DW'],
 }
-# export protocol keys as symbols for i2c decoders up the stack
-EXPORT = [ protocol.keys() ]
 
 # States
 FIND_START = 0
 FIND_ADDRESS = 1
 FIND_DATA = 2
 
-# annotation feed formats
-ANN_SHIFTED       = 0
-ANN_SHIFTED_SHORT = 1
-ANN_RAW           = 2
-
 
 class Decoder(sigrokdecode.Decoder):
     id = 'i2c'
@@ -209,7 +191,7 @@ class Decoder(sigrokdecode.Decoder):
             cmd = 'START_REPEAT'
         else:
             cmd = 'START'
-        self.put(self.output_protocol, [ cmd ])
+        self.put(self.output_protocol, [ cmd, None, None ])
         self.put(self.output_annotation, [ ANN_SHIFTED, [protocol[cmd][0]] ])
         self.put(self.output_annotation, [ ANN_SHIFTED_SHORT, [protocol[cmd][1]] ])
 
@@ -269,7 +251,7 @@ class Decoder(sigrokdecode.Decoder):
             cmd = 'DATA_WRITE'
         elif self.state == FIND_DATA and self.wr == 0:
             cmd = 'DATA_READ'
-        self.put(self.output_protocol, [ [cmd, d], [ack_bit] ] )
+        self.put(self.output_protocol, [ cmd, d, ack_bit ] )
         self.put(self.output_annotation, [ANN_SHIFTED, [
                 "%s" % protocol[cmd][0],
                 "0x%02x" % d,
@@ -292,7 +274,7 @@ class Decoder(sigrokdecode.Decoder):
             pass
 
     def found_stop(self, scl, sda):
-        self.put(self.output_protocol, [ 'STOP' ])
+        self.put(self.output_protocol, [ 'STOP', None, None ])
         self.put(self.output_annotation, [ ANN_SHIFTED, [protocol['STOP'][0]] ])
         self.put(self.output_annotation, [ ANN_SHIFTED_SHORT, [protocol['STOP'][1]] ])
 
index 720bfd3a99975f316c829f74fd9c9760e6fbe261..6b636ad466c01638584a156f104da931e6d128f8 100644 (file)
@@ -82,8 +82,8 @@ static int convert_pyobj(struct srd_decoder_instance *di, PyObject *obj,
 static PyObject *Decoder_put(PyObject *self, PyObject *args)
 {
        GSList *l;
-       PyObject *data;
-       struct srd_decoder_instance *di;
+       PyObject *data, *py_res;
+       struct srd_decoder_instance *di, *next_di;
        struct srd_pd_output *pdo;
        struct srd_protocol_data *pdata;
        uint64_t start_sample, end_sample;
@@ -103,36 +103,48 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args)
        }
        pdo = l->data;
 
+       if (!(pdata = g_try_malloc0(sizeof(struct srd_protocol_data))))
+               return NULL;
+       pdata->start_sample = start_sample;
+       pdata->end_sample = end_sample;
+       pdata->pdo = pdo;
+
        switch (pdo->output_type) {
        case SRD_OUTPUT_ANNOTATION:
+               /* Annotations are only fed to callbacks. */
+               if ((cb = srd_find_callback(pdo->output_type))) {
+                       /* Annotations need converting from PyObject. */
+                       if (convert_pyobj(di, data, &pdata->annotation_format,
+                                       (char ***)&pdata->data) != SRD_OK) {
+                               /* An error was already logged. */
+                               break;
+                       }
+                       cb(pdata);
+               }
+               break;
        case SRD_OUTPUT_PROTOCOL:
+               for (l = di->next_di; l; l = l->next) {
+                       next_di = l->data;
+                       /* TODO: is this needed? */
+                       Py_XINCREF(next_di->py_instance);
+                       if (!(py_res = PyObject_CallMethod(next_di->py_instance, "decode",
+                                       "KKO", start_sample, end_sample, data))) {
+                               if (PyErr_Occurred())
+                                       PyErr_Print();
+                       }
+                       Py_XDECREF(py_res);
+               }
+               break;
        case SRD_OUTPUT_BINARY:
+               srd_err("SRD_OUTPUT_BINARY not yet supported");
                break;
        default:
                srd_err("Protocol decoder %s submitted invalid output type %d",
                                di->decoder->name, pdo->output_type);
-               return NULL;
                break;
        }
 
-       if ((cb = srd_find_callback(pdo->output_type))) {
-               /* Something registered an interest in this output type. */
-               if (!(pdata = g_try_malloc0(sizeof(struct srd_protocol_data))))
-                       return NULL;
-               pdata->start_sample = start_sample;
-               pdata->end_sample = end_sample;
-               pdata->pdo = pdo;
-               if (pdo->output_type == SRD_OUTPUT_ANNOTATION) {
-                       /* annotations need converting from PyObject */
-                       if (convert_pyobj(di, data, &pdata->annotation_format,
-                                       (char ***)&pdata->data) != SRD_OK)
-                               return NULL;
-               } else {
-                       /* annotation_format is unused, data is an opaque blob. */
-                       pdata->data = data;
-               }
-               cb(pdata);
-       }
+       g_free(pdata);
 
        Py_RETURN_NONE;
 }
@@ -145,11 +157,17 @@ static PyObject *Decoder_add(PyObject *self, PyObject *args)
        char *protocol_id;
        int output_type, pdo_id;
 
-       if (!(di = get_di_by_decobject(self)))
+       if (!(di = get_di_by_decobject(self))) {
+               srd_err("%s():%d decoder instance not found", __func__, __LINE__);
+               PyErr_SetString(PyExc_Exception, "decoder instance not found");
                return NULL;
+       }
 
-       if (!PyArg_ParseTuple(args, "is", &output_type, &protocol_id))
+       if (!PyArg_ParseTuple(args, "is", &output_type, &protocol_id)) {
+               if (PyErr_Occurred())
+                       PyErr_Print();
                return NULL;
+       }
 
        pdo_id = pd_add(di, output_type, protocol_id);
        if (pdo_id < 0)
index 42749d330c846ed7022ebfa93606265ca7eb02ba..cf52264493052b5600aaa16719f28dfac13f3a44 100644 (file)
@@ -123,10 +123,12 @@ struct srd_decoder {
 struct srd_decoder_instance {
        struct srd_decoder *decoder;
        PyObject *py_instance;
+       char *instance_id;
        GSList *pd_output;
        int num_probes;
        int unitsize;
        uint64_t samplerate;
+       GSList *next_di;
 };
 
 struct srd_pd_output {
@@ -164,12 +166,17 @@ struct srd_pd_callback {
 int srd_init(void);
 int srd_exit(void);
 int set_modulepath(void);
-struct srd_decoder_instance *srd_instance_new(const char *id);
+struct srd_decoder_instance *srd_instance_new(const char *id,
+               const char *instance_id);
+int srd_instance_stack(struct srd_decoder_instance *di_from,
+               struct srd_decoder_instance *di_to);
 int srd_instance_set_probe(struct srd_decoder_instance *di,
                                const char *probename, int num);
-int srd_session_start(int num_probes, int unitsize, uint64_t samplerate);
-int srd_run_decoder(uint64_t timeoffset, uint64_t duration,
+struct srd_decoder_instance *srd_instance_find(char *instance_id);
+int srd_instance_start(struct srd_decoder_instance *di, PyObject *args);
+int srd_instance_decode(uint64_t timeoffset, uint64_t duration,
                struct srd_decoder_instance *dec, uint8_t *inbuf, uint64_t inbuflen);
+int srd_session_start(int num_probes, int unitsize, uint64_t samplerate);
 int srd_session_feed(uint64_t timeoffset, uint64_t duration, uint8_t *inbuf,
                uint64_t inbuflen);
 int pd_add(struct srd_decoder_instance *di, int output_type,