]> sigrok.org Git - libsigrokdecode.git/blobdiff - decoder.c
srd: support for mapping probes
[libsigrokdecode.git] / decoder.c
index 7dd1e968da23c88e0d936f4f31217d13b24635c1..d0e5734a14971058d1e27224afa2dad30b68418e 100644 (file)
--- a/decoder.c
+++ b/decoder.c
@@ -21,7 +21,7 @@
 #include "config.h"
 #include "sigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
 #include "sigrokdecode-internal.h"
-#include <dirent.h>
+#include <glib.h>
 
 /* The list of protocol decoders. */
 GSList *pd_list = NULL;
@@ -65,6 +65,63 @@ struct srd_decoder *srd_get_decoder_by_id(const char *id)
 }
 
 
+static int get_probes(struct srd_decoder *d, char *attr, GSList **pl)
+{
+       PyObject *py_probelist, *py_entry;
+       struct srd_probe *p;
+       int ret, num_probes, i;
+
+       if (!PyObject_HasAttrString(d->py_dec, attr))
+               /* No probes of this type specified. */
+               return SRD_OK;
+
+       ret = SRD_ERR_PYTHON;
+       py_probelist = py_entry = NULL;
+
+       py_probelist = PyObject_GetAttrString(d->py_dec, attr);
+       if (!PyList_Check(py_probelist)) {
+               srd_err("Protocol decoder %s %s attribute is not "
+                               "a list.", d->name, attr);
+               goto err_out;
+       }
+
+       num_probes = PyList_Size(py_probelist);
+       if (num_probes == 0)
+               /* Empty probelist. */
+               return SRD_OK;
+
+       for (i = 0; i < num_probes; i++) {
+               py_entry = PyList_GetItem(py_probelist, i);
+               if (!PyDict_Check(py_entry)) {
+                       srd_err("Protocol decoder %s %s attribute is not "
+                                       "a list with dict elements.", d->name, attr);
+                       goto err_out;
+               }
+
+               if (!(p = g_try_malloc(sizeof(struct srd_probe)))) {
+                       ret = SRD_ERR_MALLOC;
+                       goto err_out;
+               }
+
+               if ((py_dictitem_as_str(py_entry, "id", &p->id)) != SRD_OK)
+                       goto err_out;
+               if ((py_dictitem_as_str(py_entry, "name", &p->name)) != SRD_OK)
+                       goto err_out;
+               if ((py_dictitem_as_str(py_entry, "desc", &p->desc)) != SRD_OK)
+                       goto err_out;
+               p->order = i;
+
+               *pl = g_slist_append(*pl, p);
+       }
+       ret = SRD_OK;
+
+err_out:
+       Py_DecRef(py_entry);
+       Py_DecRef(py_probelist);
+
+       return ret;
+}
+
 /**
  * Load a protocol decoder module into the embedded Python interpreter.
  *
@@ -75,12 +132,12 @@ struct srd_decoder *srd_get_decoder_by_id(const char *id)
  */
 int srd_load_decoder(const char *name, struct srd_decoder **dec)
 {
-       PyObject *py_basedec, *py_method, *py_annlist, *py_ann;
+       PyObject *py_basedec, *py_method, *py_attr, *py_annlist, *py_ann;
        struct srd_decoder *d;
        int alen, ret, i;
        char **ann;
 
-       py_basedec = py_method = NULL;
+       py_basedec = py_method = py_attr = NULL;
 
        srd_dbg("decoder: %s: loading module '%s'", __func__, name);
 
@@ -150,6 +207,26 @@ int srd_load_decoder(const char *name, struct srd_decoder **dec)
        }
        Py_DecRef(py_method);
 
+       /* If present, options must be a dictionary. */
+       if (PyObject_HasAttrString(d->py_dec, "options")) {
+               py_attr = PyObject_GetAttrString(d->py_dec, "options");
+               if (!PyDict_Check(py_attr)) {
+                       srd_err("Protocol decoder %s options attribute is not "
+                                       "a dictionary.", d->name);
+                       goto err_out;
+               }
+               Py_DecRef(py_attr);
+       }
+
+       /* Check and import required probes. */
+       if (get_probes(d, "probes", &d->probes) != SRD_OK)
+               goto err_out;
+
+       /* Check and import optional probes. */
+       if (get_probes(d, "extra_probes", &d->extra_probes) != SRD_OK)
+               goto err_out;
+
+       /* Store required fields in newly allocated strings. */
        if (py_attr_as_str(d->py_dec, "id", &(d->id)) != SRD_OK)
                goto err_out;
 
@@ -262,24 +339,20 @@ int srd_unload_decoder(struct srd_decoder *dec)
 
 int srd_load_all_decoders(void)
 {
-       DIR *dir;
-       struct dirent *dp;
+       GDir *dir;
+       GError *error;
+       struct srd_decoder *dec;
        int ret;
+       const gchar *direntry;
        char *decodername;
-       struct srd_decoder *dec;
 
-       if (!(dir = opendir(DECODERS_DIR))) {
-               Py_Finalize(); /* Returns void. */
+       if (!(dir = g_dir_open(DECODERS_DIR, 0, &error))) {
                return SRD_ERR_DECODERS_DIR;
        }
 
-       while ((dp = readdir(dir)) != NULL) {
-               /* Ignore filenames which don't end with ".py". */
-               if (!g_str_has_suffix(dp->d_name, ".py"))
-                       continue;
-
+       while ((direntry = g_dir_read_name(dir)) != NULL) {
                /* The decoder name is the PD directory name (e.g. "i2c"). */
-               decodername = g_strndup(dp->d_name, strlen(dp->d_name) - 3);
+               decodername = g_strdup(direntry);
 
                /* TODO: Error handling. Use g_try_malloc(). */
                if (!(dec = malloc(sizeof(struct srd_decoder)))) {
@@ -294,7 +367,7 @@ int srd_load_all_decoders(void)
                        pd_list = g_slist_append(pd_list, dec);
                }
        }
-       closedir(dir);
+       g_dir_close(dir);
 
        return SRD_OK;
 }