X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=blobdiff_plain;f=controller.c;h=1c94d7a29a0e43a3c76496c11ba28e1099876828;hp=c6347c0a93b3d7f826ce1172a1d6413d6ec381a9;hb=fe9d91a88a8896ef04d12682720943b237c0a295;hpb=32cfb920625182c03eb4a4564ffdfa9d2b08f15c diff --git a/controller.c b/controller.c index c6347c0..1c94d7a 100644 --- a/controller.c +++ b/controller.c @@ -89,10 +89,8 @@ /** @cond PRIVATE */ -SRD_PRIV GSList *sessions = NULL; -static int max_session_id = -1; - -static int session_is_valid(struct srd_session *sess); +extern GSList *sessions; +extern int max_session_id; /* decoder.c */ extern SRD_PRIV GSList *pd_list; @@ -305,6 +303,16 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, const char *val_str; char *dbg, *key; + if (!di) { + srd_err("Invalid decoder instance."); + return SRD_ERR_ARG; + } + + if (!options) { + srd_err("Invalid options GHashTable."); + return SRD_ERR_ARG; + } + if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ if (g_hash_table_size(options) == 0) { @@ -326,8 +334,18 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, /* All of these are synthesized objects, so they're good. */ py_dec_optkeys = PyDict_Keys(py_dec_options); num_optkeys = PyList_Size(py_dec_optkeys); + + /* + * The 'options' dictionary is a class variable, but we need to + * change it. Changing it directly will affect the entire class, + * so we need to create a new object for it, and populate that + * instead. + */ if (!(py_di_options = PyObject_GetAttrString(di->py_inst, "options"))) goto err_out; + Py_DECREF(py_di_options); + py_di_options = PyDict_New(); + PyObject_SetAttrString(di->py_inst, "options", py_di_options); for (i = 0; i < num_optkeys; i++) { /* Get the default class value for this option. */ py_str_as_str(PyList_GetItem(py_dec_optkeys, i), &key); @@ -407,13 +425,14 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, ret = SRD_OK; err_out: - Py_XDECREF(py_optlist); Py_XDECREF(py_di_options); Py_XDECREF(py_dec_optkeys); Py_XDECREF(py_dec_options); g_free(key); - if (PyErr_Occurred()) + if (PyErr_Occurred()) { srd_exception_catch("Stray exception in srd_inst_option_set()."); + ret = SRD_ERR_PYTHON; + } return ret; } @@ -446,9 +465,8 @@ SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, GList *l; GSList *sl; struct srd_probe *p; - int *new_probemap, new_probenum; + int *new_probemap, new_probenum, num_required_probes, num_probes, i; char *probe_id; - int i, num_required_probes; srd_dbg("set probes called for instance %s with list of %d probes", di->inst_id, g_hash_table_size(new_probes)); @@ -478,9 +496,10 @@ SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, for (i = 0; i < di->dec_num_probes; i++) new_probemap[i] = -1; + num_probes = 0; for (l = g_hash_table_get_keys(new_probes); l; l = l->next) { probe_id = l->data; - probe_val= g_hash_table_lookup(new_probes, probe_id); + probe_val = g_hash_table_lookup(new_probes, probe_id); if (!g_variant_is_of_type(probe_val, G_VARIANT_TYPE_INT32)) { /* Probe name was specified without a value. */ srd_err("No probe number was specified for %s.", @@ -504,7 +523,9 @@ SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, new_probemap[p->order] = new_probenum; srd_dbg("Setting probe mapping: %s (index %d) = probe %d.", p->id, p->order, new_probenum); + num_probes++; } + di->data_unitsize = (num_probes + 7) / 8; srd_dbg("Final probe map:"); num_required_probes = g_slist_length(di->decoder->probes); @@ -530,7 +551,7 @@ SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, * @return Pointer to a newly allocated struct srd_decoder_inst, or * NULL in case of failure. * - * @since 0.1.0 + * @since 0.3.0 */ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, const char *decoder_id, GHashTable *options) @@ -571,10 +592,10 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, * order in which the decoder class defined them. */ di->dec_num_probes = g_slist_length(di->decoder->probes) + - g_slist_length(di->decoder->opt_probes); + g_slist_length(di->decoder->opt_probes); if (di->dec_num_probes) { if (!(di->dec_probemap = - g_try_malloc(sizeof(int) * di->dec_num_probes))) { + g_try_malloc(sizeof(int) * di->dec_num_probes))) { srd_err("Failed to g_malloc() probe map."); g_free(di); return NULL; @@ -582,12 +603,13 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, for (i = 0; i < di->dec_num_probes; i++) di->dec_probemap[i] = i; } + di->data_unitsize = (di->dec_num_probes + 7) / 8; /* Create a new instance of this decoder class. */ if (!(di->py_inst = PyObject_CallObject(dec->py_dec, NULL))) { if (PyErr_Occurred()) srd_exception_catch("failed to create %s instance: ", - decoder_id); + decoder_id); g_free(di->dec_probemap); g_free(di); return NULL; @@ -614,7 +636,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, * * @return SRD_OK upon success, a (negative) error code otherwise. * - * @since 0.1.0 + * @since 0.3.0 */ SRD_API int srd_inst_stack(struct srd_session *sess, struct srd_decoder_inst *di_from, struct srd_decoder_inst *di_to) @@ -652,7 +674,7 @@ SRD_API int srd_inst_stack(struct srd_session *sess, * * @return Pointer to struct srd_decoder_inst, or NULL if not found. * - * @since 0.1.0 + * @since 0.3.0 */ SRD_API struct srd_decoder_inst *srd_inst_find_by_id(struct srd_session *sess, const char *inst_id) @@ -736,40 +758,28 @@ SRD_PRIV struct srd_decoder_inst *srd_inst_find_by_obj(const GSList *stack, } /** @private */ -SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, PyObject *args) +SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di) { - PyObject *py_name, *py_res; + PyObject *py_res; GSList *l; struct srd_decoder_inst *next_di; + int ret; srd_dbg("Calling start() method on protocol decoder instance %s.", - di->inst_id); + di->inst_id); - if (!(py_name = PyUnicode_FromString("start"))) { - srd_err("Unable to build Python object for 'start'."); + if (!(py_res = PyObject_CallMethod(di->py_inst, "start", NULL))) { srd_exception_catch("Protocol decoder instance %s: ", - di->inst_id); + di->inst_id); return SRD_ERR_PYTHON; } - - if (!(py_res = PyObject_CallMethodObjArgs(di->py_inst, - py_name, args, NULL))) { - srd_exception_catch("Protocol decoder instance %s: ", - di->inst_id); - return SRD_ERR_PYTHON; - } - Py_DecRef(py_res); - Py_DecRef(py_name); - /* - * Start all the PDs stacked on top of this one. Pass along the - * metadata all the way from the bottom PD, even though it's only - * applicable to logic data for now. - */ + /* Start all the PDs stacked on top of this one. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; - srd_inst_start(next_di, args); + if ((ret = srd_inst_start(next_di)) != SRD_OK) + return ret; } return SRD_OK; @@ -778,9 +788,11 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, PyObject *args) /** * Run the specified decoder function. * + * @param di The decoder instance to call. Must not be NULL. * @param start_samplenum The starting sample number for the buffer's sample * set, relative to the start of capture. - * @param di The decoder instance to call. Must not be NULL. + * @param end_samplenum The ending sample number for the buffer's sample + * set, relative to the start of capture. * @param inbuf The buffer to decode. Must not be NULL. * @param inbuflen Length of the buffer. Must be > 0. * @@ -790,16 +802,16 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, PyObject *args) * * @since 0.1.0 */ -SRD_PRIV int srd_inst_decode(uint64_t start_samplenum, - const struct srd_decoder_inst *di, const uint8_t *inbuf, - uint64_t inbuflen) +SRD_PRIV int srd_inst_decode(const struct srd_decoder_inst *di, + uint64_t start_samplenum, uint64_t end_samplenum, + const uint8_t *inbuf, uint64_t inbuflen) { PyObject *py_res; srd_logic *logic; - uint64_t end_samplenum; - srd_dbg("Calling decode() on instance %s with %d bytes starting " - "at sample %d.", di->inst_id, inbuflen, start_samplenum); + srd_dbg("Calling decode() on instance %s with %" PRIu64 " bytes " + "starting at sample %" PRIu64 ".", di->inst_id, inbuflen, + start_samplenum); /* Return an error upon unusable input. */ if (!di) { @@ -830,12 +842,9 @@ SRD_PRIV int srd_inst_decode(uint64_t start_samplenum, Py_INCREF(logic->sample); Py_IncRef(di->py_inst); - end_samplenum = start_samplenum + inbuflen / di->data_unitsize; if (!(py_res = PyObject_CallMethod(di->py_inst, "decode", - "KKO", logic->start_samplenum, - end_samplenum, logic))) { - srd_exception_catch("Protocol decoder instance %s: ", - di->inst_id); + "KKO", start_samplenum, end_samplenum, logic))) { + srd_exception_catch("Protocol decoder instance %s: ", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); @@ -890,319 +899,3 @@ SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack) /** @} */ -/** - * @defgroup grp_session Session handling - * - * Starting and handling decoding sessions. - * - * @{ - */ - -static int session_is_valid(struct srd_session *sess) -{ - - if (!sess || sess->session_id < 1) - return SRD_ERR; - - return SRD_OK; -} - -/** - * Create a decoding session. - * - * A session holds all decoder instances, their stack relationships and - * output callbacks. - * - * @param sess. A pointer which will hold a pointer to a newly - * initialized session on return. - * - * @return SRD_OK upon success, a (negative) error code otherwise. - * - * @since 0.3.0 - */ -SRD_API int srd_session_new(struct srd_session **sess) -{ - - if (!sess) { - srd_err("Invalid session pointer."); - return SRD_ERR; - } - - if (!(*sess = g_try_malloc(sizeof(struct srd_session)))) - return SRD_ERR_MALLOC; - (*sess)->session_id = ++max_session_id; - (*sess)->num_probes = (*sess)->unitsize = (*sess)->samplerate = 0; - (*sess)->di_list = (*sess)->callbacks = NULL; - - /* Keep a list of all sessions, so we can clean up as needed. */ - sessions = g_slist_append(sessions, *sess); - - srd_dbg("Created session %d.", (*sess)->session_id); - - return SRD_OK; -} - -/** - * Start a decoding session. - * - * Decoders, instances and stack must have been prepared beforehand, - * and all SRD_CONF parameters set. - * - * @param sess The session to start. - * - * @return SRD_OK upon success, a (negative) error code otherwise. - * - * @since 0.1.0 - */ -SRD_API int srd_session_start(struct srd_session *sess) -{ - PyObject *args; - GSList *d; - struct srd_decoder_inst *di; - int ret; - - if (session_is_valid(sess) != SRD_OK) { - srd_err("Invalid session pointer."); - return SRD_ERR; - } - if (sess->num_probes == 0) { - srd_err("Session has invalid number of probes."); - return SRD_ERR; - } - if (sess->unitsize == 0) { - srd_err("Session has invalid unitsize."); - return SRD_ERR; - } - if (sess->samplerate == 0) { - srd_err("Session has invalid samplerate."); - return SRD_ERR; - } - - ret = SRD_OK; - - srd_dbg("Calling start() on all instances in session %d with " - "%d probes, unitsize %d samplerate %d.", sess->session_id, - sess->num_probes, sess->unitsize, sess->samplerate); - - /* - * Currently only one item of metadata is passed along to decoders, - * samplerate. This can be extended as needed. - */ - if (!(args = Py_BuildValue("{s:l}", "samplerate", (long)sess->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 = sess->di_list; d; d = d->next) { - di = d->data; - di->data_num_probes = sess->num_probes; - di->data_unitsize = sess->unitsize; - di->data_samplerate = sess->samplerate; - if ((ret = srd_inst_start(di, args)) != SRD_OK) - break; - } - - Py_DecRef(args); - - return ret; -} - -/** - * Set a configuration key in a session. - * - * @param sess The session to configure. - * @param key The configuration key (SRD_CONF_*). - * @param data The new value for the key, as a GVariant with GVariantType - * appropriate to that key. A floating reference can be passed - * in; its refcount will be sunk and unreferenced after use. - * - * @return SRD_OK upon success, a (negative) error code otherwise. - * - * @since 0.3.0 - */ -SRD_API int srd_session_config_set(struct srd_session *sess, int key, - GVariant *data) -{ - - if (session_is_valid(sess) != SRD_OK) { - srd_err("Invalid session."); - return SRD_ERR_ARG; - } - - if (!g_variant_is_of_type(data, G_VARIANT_TYPE_UINT64)) { - srd_err("Value for key %d should be of type uint64."); - return SRD_ERR_ARG; - } - - switch (key) { - case SRD_CONF_NUM_PROBES: - sess->num_probes = g_variant_get_uint64(data); - break; - case SRD_CONF_UNITSIZE: - sess->unitsize = g_variant_get_uint64(data); - break; - case SRD_CONF_SAMPLERATE: - sess->samplerate = g_variant_get_uint64(data); - break; - } - - g_variant_unref(data); - - return SRD_OK; -} - -/** - * Send a chunk of logic sample data to a running decoder session. - * - * @param sess The session to use. - * @param start_samplenum The sample number of the first sample in this chunk. - * @param inbuf Pointer to sample data. - * @param inbuflen Length in bytes of the buffer. - * - * @return SRD_OK upon success, a (negative) error code otherwise. - * - * @since 0.1.0 - */ -SRD_API int srd_session_send(struct srd_session *sess, uint64_t start_samplenum, - const uint8_t *inbuf, uint64_t inbuflen) -{ - GSList *d; - int ret; - - if (session_is_valid(sess) != SRD_OK) { - srd_err("Invalid session."); - return SRD_ERR_ARG; - } - - srd_dbg("Calling decode() on all instances with starting sample " - "number %" PRIu64 ", %" PRIu64 " bytes at 0x%p", - start_samplenum, inbuflen, inbuf); - - for (d = sess->di_list; d; d = d->next) { - if ((ret = srd_inst_decode(start_samplenum, d->data, inbuf, - inbuflen)) != SRD_OK) - return ret; - } - - return SRD_OK; -} - -/** - * Destroy a decoding session. - * - * All decoder instances and output callbacks are properly released. - * - * @param sess. The session to be destroyed. - * - * @return SRD_OK upon success, a (negative) error code otherwise. - * - * @since 0.1.0 - */ -SRD_API int srd_session_destroy(struct srd_session *sess) -{ - int session_id; - - session_id = sess->session_id; - if (sess->di_list) - srd_inst_free_all(sess, NULL); - if (sess->callbacks) - g_slist_free_full(sess->callbacks, g_free); - sessions = g_slist_remove(sessions, sess); - g_free(sess); - - srd_dbg("Destroyed session %d.", session_id); - - return SRD_OK; -} - -/** - * Register/add a decoder output callback function. - * - * The function will be called when a protocol decoder sends output back - * to the PD controller (except for Python objects, which only go up the - * stack). - * - * @param sess The output session in which to register the callback. - * @param output_type The output type this callback will receive. Only one - * callback per output type can be registered. - * @param cb The function to call. Must not be NULL. - * @param cb_data Private data for the callback function. Can be NULL. - * - * @since 0.1.0 - */ -SRD_API int srd_pd_output_callback_add(struct srd_session *sess, - int output_type, srd_pd_output_callback_t cb, void *cb_data) -{ - struct srd_pd_callback *pd_cb; - - if (session_is_valid(sess) != SRD_OK) { - srd_err("Invalid session."); - return SRD_ERR_ARG; - } - - srd_dbg("Registering new callback for output type %d.", output_type); - - if (!(pd_cb = g_try_malloc(sizeof(struct srd_pd_callback)))) { - srd_err("Failed to g_malloc() struct srd_pd_callback."); - return SRD_ERR_MALLOC; - } - - pd_cb->output_type = output_type; - pd_cb->cb = cb; - pd_cb->cb_data = cb_data; - sess->callbacks = g_slist_append(sess->callbacks, pd_cb); - - return SRD_OK; -} - -/** @private */ -SRD_PRIV struct srd_pd_callback *srd_pd_output_callback_find( - struct srd_session *sess, int output_type) -{ - GSList *l; - struct srd_pd_callback *tmp, *pd_cb; - - if (session_is_valid(sess) != SRD_OK) { - srd_err("Invalid session."); - return NULL; - } - - pd_cb = NULL; - for (l = sess->callbacks; l; l = l->next) { - tmp = l->data; - if (tmp->output_type == output_type) { - pd_cb = tmp; - break; - } - } - - return pd_cb; -} - -/* This is the backend function to Python sigrokdecode.add() call. */ -/** @private */ -SRD_PRIV int srd_inst_pd_output_add(struct srd_decoder_inst *di, - int output_type, const char *proto_id) -{ - struct srd_pd_output *pdo; - - srd_dbg("Instance %s creating new output type %d for %s.", - di->inst_id, output_type, proto_id); - - if (!(pdo = g_try_malloc(sizeof(struct srd_pd_output)))) { - srd_err("Failed to g_malloc() struct srd_pd_output."); - return -1; - } - - /* pdo_id is just a simple index, nothing is deleted from this list anyway. */ - pdo->pdo_id = g_slist_length(di->pd_output); - pdo->output_type = output_type; - pdo->di = di; - pdo->proto_id = g_strdup(proto_id); - di->pd_output = g_slist_append(di->pd_output, pdo); - - return pdo->pdo_id; -} - -/** @} */