X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=blobdiff_plain;f=decoder.c;h=01dcf0a823b6da56a798d646750e355bfdd3de52;hp=cbca0b840376c60de504dcc1bd91cdd449c6bef4;hb=0169f19c53e195df2f96c4df731ad3214c59e20a;hpb=42515b0f25613499167b66c1d8a659526fb46b8d diff --git a/decoder.c b/decoder.c index cbca0b8..01dcf0a 100644 --- a/decoder.c +++ b/decoder.c @@ -1,5 +1,5 @@ /* - * This file is part of the sigrok project. + * This file is part of the libsigrokdecode project. * * Copyright (C) 2010 Uwe Hermann * Copyright (C) 2012 Bert Vermeulen @@ -19,22 +19,44 @@ */ #include "config.h" -#include "sigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ -#include "sigrokdecode-internal.h" +#include "libsigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */ +#include "libsigrokdecode-internal.h" #include +/** + * @file + * + * Listing, loading, unloading, and handling protocol decoders. + */ + +/** + * @defgroup grp_decoder Protocol decoders + * + * Handling protocol decoders. + * + * @{ + */ + +/** @cond PRIVATE */ + /* The list of protocol decoders. */ SRD_PRIV GSList *pd_list = NULL; +extern GSList *sessions; + /* module_sigrokdecode.c */ extern SRD_PRIV PyObject *mod_sigrokdecode; +/** @endcond */ + /** * Returns the list of supported/loaded protocol decoders. * * This is a GSList containing the names of the decoders as strings. * * @return List of decoders, NULL if none are supported or loaded. + * + * @since 0.1.0 (but the API changed in 0.2.0) */ SRD_API const GSList *srd_decoder_list(void) { @@ -47,6 +69,8 @@ SRD_API const GSList *srd_decoder_list(void) * @param id The ID string of the decoder to return. * * @return The decoder with the specified ID, or NULL if not found. + * + * @since 0.1.0 */ SRD_API struct srd_decoder *srd_decoder_get_by_id(const char *id) { @@ -121,12 +145,103 @@ err_out: return ret; } +static int get_options(struct srd_decoder *d) +{ + PyObject *py_opts, *py_keys, *py_values, *py_val, *py_desc, *py_default; + Py_ssize_t i; + struct srd_decoder_option *o; + gint64 def_long; + int num_keys, overflow, ret; + char *key, *def_str; + + ret = SRD_ERR_PYTHON; + key = NULL; + + if (!PyObject_HasAttrString(d->py_dec, "options")) + /* That's fine. */ + return SRD_OK; + + /* If present, options must be a dictionary. */ + py_opts = PyObject_GetAttrString(d->py_dec, "options"); + if (!PyDict_Check(py_opts)) { + srd_err("Protocol decoder %s options attribute is not " + "a dictionary.", d->name); + goto err_out; + } + + py_keys = PyDict_Keys(py_opts); + py_values = PyDict_Values(py_opts); + num_keys = PyList_Size(py_keys); + for (i = 0; i < num_keys; i++) { + py_str_as_str(PyList_GetItem(py_keys, i), &key); + srd_dbg("option '%s'", key); + py_val = PyList_GetItem(py_values, i); + if (!PyList_Check(py_val) || PyList_Size(py_val) != 2) { + srd_err("Protocol decoder %s option '%s' value must be " + "a list with two elements.", d->name, key); + goto err_out; + } + py_desc = PyList_GetItem(py_val, 0); + if (!PyUnicode_Check(py_desc)) { + srd_err("Protocol decoder %s option '%s' has no " + "description.", d->name, key); + goto err_out; + } + py_default = PyList_GetItem(py_val, 1); + if (!PyUnicode_Check(py_default) && !PyLong_Check(py_default)) { + srd_err("Protocol decoder %s option '%s' has default " + "of unsupported type '%s'.", d->name, key, + Py_TYPE(py_default)->tp_name); + goto err_out; + } + if (!(o = g_try_malloc(sizeof(struct srd_decoder_option)))) { + srd_err("option malloc failed"); + goto err_out; + } + o->id = g_strdup(key); + py_str_as_str(py_desc, &o->desc); + if (PyUnicode_Check(py_default)) { + /* UTF-8 string */ + py_str_as_str(py_default, &def_str); + o->def = g_variant_new_string(def_str); + g_free(def_str); + } else { + /* Long */ + def_long = PyLong_AsLongAndOverflow(py_default, &overflow); + if (overflow) { + /* Value is < LONG_MIN or > LONG_MAX */ + PyErr_Clear(); + srd_err("Protocol decoder %s option '%s' has " + "invalid default value.", d->name, key); + goto err_out; + } + o->def = g_variant_new_int64(def_long); + } + g_variant_ref_sink(o->def); + d->options = g_slist_append(d->options, o); + g_free(key); + key = NULL; + } + Py_DecRef(py_keys); + Py_DecRef(py_values); + + ret = SRD_OK; + +err_out: + Py_XDECREF(py_opts); + g_free(key); + + return ret; +} + /** * Load a protocol decoder module into the embedded Python interpreter. * * @param module_name The module name to be loaded. * * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.1.0 */ SRD_API int srd_decoder_load(const char *module_name) { @@ -137,6 +252,9 @@ SRD_API int srd_decoder_load(const char *module_name) struct srd_probe *p; GSList *l; + if (!module_name) + return SRD_ERR_ARG; + srd_dbg("Loading protocol decoder '%s'.", module_name); py_basedec = py_method = py_attr = NULL; @@ -204,17 +322,8 @@ SRD_API int srd_decoder_load(const char *module_name) } Py_CLEAR(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); - Py_DecRef(py_attr); - goto err_out; - } - Py_DecRef(py_attr); - } + if (get_options(d) != SRD_OK) + goto err_out; /* Check and import required probes. */ if (get_probes(d, "probes", &d->probes) != SRD_OK) @@ -303,6 +412,8 @@ err_out: * * @return A newly allocated buffer containing the protocol decoder's * documentation. The caller is responsible for free'ing the buffer. + * + * @since 0.1.0 */ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) { @@ -344,14 +455,20 @@ static void free_probes(GSList *probelist) } /** - * Unload decoder module. + * Unload the specified protocol decoder. * * @param dec The struct srd_decoder to be unloaded. * * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.1.0 */ SRD_API int srd_decoder_unload(struct srd_decoder *dec) { + struct srd_decoder_option *o; + struct srd_session *sess; + GSList *l; + srd_dbg("Unloading protocol decoder '%s'.", dec->name); /* @@ -360,7 +477,19 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) * stack. A frontend reloading a decoder thus has to restart all * instances, and rebuild the stack. */ - srd_inst_free_all(NULL); + for (l = sessions; l; l = l->next) { + sess = l->data; + srd_inst_free_all(sess, NULL); + } + + for (l = dec->options; l; l = l->next) { + o = l->data; + g_free(o->id); + g_free(o->desc); + g_variant_unref(o->def); + g_free(o); + } + g_slist_free(dec->options); free_probes(dec->probes); free_probes(dec->opt_probes); @@ -375,7 +504,7 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) /* The module itself. */ Py_XDECREF(dec->py_mod); - /* TODO: (g_)free dec itself? */ + g_free(dec); return SRD_OK; } @@ -384,6 +513,8 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) * Load all installed protocol decoders. * * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.1.0 */ SRD_API int srd_decoder_load_all(void) { @@ -409,6 +540,8 @@ SRD_API int srd_decoder_load_all(void) * Unload all loaded protocol decoders. * * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.1.0 */ SRD_API int srd_decoder_unload_all(void) { @@ -422,3 +555,5 @@ SRD_API int srd_decoder_unload_all(void) return SRD_OK; } + +/** @} */