/** * Add an additional search directory for the protocol decoders. * * The specified directory is prepended (not appended!) to Python's sys.path, * in order to search for sigrok protocol decoders in the specified * directories first, and in the generic Python module directories (and in * the current working directory) last. This avoids conflicts if there are * Python modules which have the same name as a sigrok protocol decoder in * sys.path or in the current working directory. * * @param path Path to the directory containing protocol decoders which shall * be added to the Python sys.path, or NULL. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @private * * @since 0.1.0 */ SRD_PRIV int srd_decoder_searchpath_add(const char *path) { PyObject *py_cur_path, *py_item; srd_dbg("Adding '%s' to module path.", path); py_cur_path = PySys_GetObject("path"); if (!py_cur_path) return SRD_ERR_PYTHON; py_item = PyUnicode_FromString(path); if (!py_item) { srd_exception_catch(NULL, "Failed to create Unicode object"); return SRD_ERR_PYTHON; } if (PyList_Insert(py_cur_path, 0, py_item) < 0) { srd_exception_catch(NULL, "Failed to insert path element"); Py_DECREF(py_item); return SRD_ERR_PYTHON; } Py_DECREF(py_item); searchpaths = g_slist_prepend(searchpaths, g_strdup(path)); return SRD_OK; }
/** * Get the value of a Python object's attribute, returned as a newly * allocated char *. * * @param py_obj The object to probe. * @param attr Name of the attribute to retrieve. * @param outstr ptr to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. * The 'outstr' argument points to a malloc()ed string upon success. * * @private */ SRD_PRIV int py_attr_as_str(const PyObject *py_obj, const char *attr, char **outstr) { PyObject *py_str; int ret; if (!PyObject_HasAttrString((PyObject *)py_obj, attr)) { srd_dbg("%s object has no attribute '%s'.", Py_TYPE(py_obj)->tp_name, attr); return SRD_ERR_PYTHON; } if (!(py_str = PyObject_GetAttrString((PyObject *)py_obj, attr))) { srd_exception_catch(""); return SRD_ERR_PYTHON; } if (!PyUnicode_Check(py_str)) { srd_dbg("%s attribute should be a string, but is a %s.", attr, Py_TYPE(py_str)->tp_name); Py_DecRef(py_str); return SRD_ERR_PYTHON; } ret = py_str_as_str(py_str, outstr); Py_DecRef(py_str); return ret; }
/** @private */ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di) { 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); if (!(py_res = PyObject_CallMethod(di->py_inst, "start", NULL))) { srd_exception_catch("Protocol decoder instance %s: ", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); /* Start all the PDs stacked on top of this one. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; if ((ret = srd_inst_start(next_di)) != SRD_OK) return ret; } return SRD_OK; }
/** * Run the specified decoder function. * * @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 inbuf The buffer to decode. Must not be NULL. * @param inbuflen Length of the buffer. Must be > 0. * * @return SRD_OK upon success, a (negative) error code otherwise. */ SRD_PRIV int srd_inst_decode(uint64_t start_samplenum, const struct srd_decoder_inst *di, 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); /* Return an error upon unusable input. */ if (!di) { srd_dbg("empty decoder instance"); return SRD_ERR_ARG; } if (!inbuf) { srd_dbg("NULL buffer pointer"); return SRD_ERR_ARG; } if (inbuflen == 0) { srd_dbg("empty buffer"); return SRD_ERR_ARG; } /* * Create new srd_logic object. Each iteration around the PD's loop * will fill one sample into this object. */ logic = PyObject_New(srd_logic, &srd_logic_type); Py_INCREF(logic); logic->di = (struct srd_decoder_inst *)di; logic->start_samplenum = start_samplenum; logic->itercnt = 0; logic->inbuf = (uint8_t *)inbuf; logic->inbuflen = inbuflen; logic->sample = PyList_New(2); 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); return SRD_ERR_PYTHON; /* TODO: More specific error? */ } Py_DecRef(py_res); return SRD_OK; }
SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di, PyObject *args) { PyObject *py_name, *py_res; GSList *l; struct srd_decoder_inst *next_di; srd_dbg("Calling start() method on protocol decoder instance %s.", di->inst_id); if (!(py_name = PyUnicode_FromString("start"))) { srd_err("Unable to build Python object for 'start'."); srd_exception_catch("Protocol decoder instance %s: ", 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. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; srd_inst_start(next_di, args); } return SRD_OK; }
/** * Get the value of a Python unicode string object, returned as a newly * allocated char *. * * @param py_str The unicode string object. * @param outstr ptr to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. * The 'outstr' argument points to a malloc()ed string upon success. * * @private */ SRD_PRIV int py_str_as_str(const PyObject *py_str, char **outstr) { PyObject *py_encstr; int ret; char *str; py_encstr = NULL; str = NULL; ret = SRD_OK; if (!PyUnicode_Check((PyObject *)py_str)) { srd_dbg("Object is a %s, not a string object.", Py_TYPE((PyObject *)py_str)->tp_name); ret = SRD_ERR_PYTHON; goto err_out; } if (!(py_encstr = PyUnicode_AsEncodedString((PyObject *)py_str, "utf-8", NULL))) { ret = SRD_ERR_PYTHON; goto err_out; } if (!(str = PyBytes_AS_STRING(py_encstr))) { ret = SRD_ERR_PYTHON; goto err_out; } if (!(*outstr = g_strdup(str))) { srd_dbg("Failed to g_malloc() outstr."); ret = SRD_ERR_MALLOC; goto err_out; } err_out: if (py_encstr) Py_XDECREF(py_encstr); if (PyErr_Occurred()) { srd_exception_catch("string conversion failed"); } return ret; }
/** * Return a protocol decoder's docstring. * * @param dec The loaded protocol decoder. * * @return A newly allocated buffer containing the protocol decoder's * documentation. The caller is responsible for free'ing the buffer. */ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) { PyObject *py_str; char *doc; if (!PyObject_HasAttrString(dec->py_mod, "__doc__")) return NULL; if (!(py_str = PyObject_GetAttrString(dec->py_mod, "__doc__"))) { srd_exception_catch(""); return NULL; } doc = NULL; if (py_str != Py_None) py_str_as_str(py_str, &doc); Py_DecRef(py_str); return doc; }
/** * Worker thread (per PD-stack). * * @param data Pointer to the lowest-level PD's device instance. * Must not be NULL. * * @return NULL if there was an error. */ static gpointer di_thread(gpointer data) { PyObject *py_res; struct srd_decoder_inst *di; if (!data) return NULL; di = data; /* Call self.decode(). Only returns if the PD throws an exception. */ Py_IncRef(di->py_inst); if (!(py_res = PyObject_CallMethod(di->py_inst, "decode", NULL))) { srd_exception_catch("Protocol decoder instance %s: ", di->inst_id); exit(1); /* TODO: Proper shutdown. This is a hack. */ return NULL; } Py_DecRef(py_res); return NULL; }
/** @private */ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di) { 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); /* Run self.start(). */ if (!(py_res = PyObject_CallMethod(di->py_inst, "start", NULL))) { srd_exception_catch("Protocol decoder instance %s", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); /* Set the initial pins based on self.initial_pins. */ set_initial_pin_values(di); /* Set self.samplenum to 0. */ PyObject_SetAttrString(di->py_inst, "samplenum", PyLong_FromLong(0)); /* Set self.matches to None. */ PyObject_SetAttrString(di->py_inst, "matches", Py_None); /* Start all the PDs stacked on top of this one. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; if ((ret = srd_inst_start(next_di)) != SRD_OK) return ret; } return SRD_OK; }
/** * Create a new protocol decoder instance. * * @param sess The session holding the protocol decoder instance. * @param decoder_id Decoder 'id' field. * @param options GHashtable of options which override the defaults set in * the decoder class. May be NULL. * * @return Pointer to a newly allocated struct srd_decoder_inst, or * NULL in case of failure. * * @since 0.3.0 */ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, const char *decoder_id, GHashTable *options) { int i; struct srd_decoder *dec; struct srd_decoder_inst *di; char *inst_id; i = 1; srd_dbg("Creating new %s instance.", decoder_id); if (session_is_valid(sess) != SRD_OK) { srd_err("Invalid session."); return NULL; } if (!(dec = srd_decoder_get_by_id(decoder_id))) { srd_err("Protocol decoder %s not found.", decoder_id); return NULL; } di = g_malloc0(sizeof(struct srd_decoder_inst)); di->decoder = dec; di->sess = sess; if (options) { inst_id = g_hash_table_lookup(options, "id"); if (inst_id) di->inst_id = g_strdup(inst_id); g_hash_table_remove(options, "id"); } /* Create a unique instance ID (as none was provided). */ if (!di->inst_id) { di->inst_id = g_strdup_printf("%s-%d", decoder_id, i++); while (srd_inst_find_by_id(sess, di->inst_id)) { g_free(di->inst_id); di->inst_id = g_strdup_printf("%s-%d", decoder_id, i++); } } /* * Prepare a default channel map, where samples come in the * order in which the decoder class defined them. */ di->dec_num_channels = g_slist_length(di->decoder->channels) + g_slist_length(di->decoder->opt_channels); if (di->dec_num_channels) { di->dec_channelmap = g_malloc(sizeof(int) * di->dec_num_channels); for (i = 0; i < di->dec_num_channels; i++) di->dec_channelmap[i] = i; /* * Will be used to prepare a sample at every iteration * of the instance's decode() method. */ di->channel_samples = g_malloc(di->dec_num_channels); } /* 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); g_free(di->dec_channelmap); g_free(di); return NULL; } if (options && srd_inst_option_set(di, options) != SRD_OK) { g_free(di->dec_channelmap); g_free(di); return NULL; } di->condition_list = NULL; di->match_array = NULL; di->abs_start_samplenum = 0; di->abs_end_samplenum = 0; di->inbuf = NULL; di->inbuflen = 0; di->abs_cur_samplenum = 0; di->old_pins_array = NULL; di->thread_handle = NULL; di->got_new_samples = FALSE; di->handled_all_samples = FALSE; /* Instance takes input from a frontend by default. */ sess->di_list = g_slist_append(sess->di_list, di); srd_dbg("Created new %s instance with ID %s.", decoder_id, di->inst_id); return di; }
/** * Set one or more options in a decoder instance. * * Handled options are removed from the hash. * * @param di Decoder instance. * @param options A GHashTable of options to set. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @since 0.1.0 */ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, GHashTable *options) { PyObject *py_dec_options, *py_dec_optkeys, *py_di_options, *py_optval; PyObject *py_optlist, *py_classval; Py_UNICODE *py_ustr; GVariant *value; unsigned long long int val_ull; gint64 val_int; int num_optkeys, ret, size, i; 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) { /* No options provided. */ return SRD_OK; } else { srd_err("Protocol decoder has no options."); return SRD_ERR_ARG; } return SRD_OK; } ret = SRD_ERR_PYTHON; key = NULL; py_dec_options = py_dec_optkeys = py_di_options = py_optval = NULL; py_optlist = py_classval = NULL; py_dec_options = PyObject_GetAttrString(di->decoder->py_dec, "options"); /* 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); if (!(py_optlist = PyDict_GetItemString(py_dec_options, key))) goto err_out; if (!(py_classval = PyList_GetItem(py_optlist, 1))) goto err_out; if (!PyUnicode_Check(py_classval) && !PyLong_Check(py_classval)) { srd_err("Options of type %s are not yet supported.", Py_TYPE(py_classval)->tp_name); goto err_out; } if ((value = g_hash_table_lookup(options, key))) { dbg = g_variant_print(value, TRUE); srd_dbg("got option '%s' = %s", key, dbg); g_free(dbg); /* An override for this option was provided. */ if (PyUnicode_Check(py_classval)) { if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { srd_err("Option '%s' requires a string value.", key); goto err_out; } val_str = g_variant_get_string(value, NULL); if (!(py_optval = PyUnicode_FromString(val_str))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); srd_err("Option '%s' requires a UTF-8 string value.", key); goto err_out; } } else if (PyLong_Check(py_classval)) { if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT64)) { srd_err("Option '%s' requires an integer value.", key); goto err_out; } val_int = g_variant_get_int64(value); if (!(py_optval = PyLong_FromLong(val_int))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option '%s' has invalid integer value.", key); goto err_out; } } g_hash_table_remove(options, key); } else { /* Use the class default for this option. */ if (PyUnicode_Check(py_classval)) { /* Make a brand new copy of the string. */ py_ustr = PyUnicode_AS_UNICODE(py_classval); size = PyUnicode_GET_SIZE(py_classval); py_optval = PyUnicode_FromUnicode(py_ustr, size); } else if (PyLong_Check(py_classval)) { /* Make a brand new copy of the integer. */ val_ull = PyLong_AsUnsignedLongLong(py_classval); if (val_ull == (unsigned long long)-1) { /* OverFlowError exception */ PyErr_Clear(); srd_err("Invalid integer value for %s: " "expected integer.", key); goto err_out; } if (!(py_optval = PyLong_FromUnsignedLongLong(val_ull))) goto err_out; } } /* * If we got here, py_optval holds a known good new reference * to the instance option to set. */ if (PyDict_SetItemString(py_di_options, key, py_optval) == -1) goto err_out; g_free(key); key = NULL; } ret = SRD_OK; err_out: Py_XDECREF(py_di_options); Py_XDECREF(py_dec_optkeys); Py_XDECREF(py_dec_options); g_free(key); if (PyErr_Occurred()) { srd_exception_catch("Stray exception in srd_inst_option_set()."); ret = SRD_ERR_PYTHON; } return ret; }
/** * Create a new protocol decoder instance. * * @param sess The session holding the protocol decoder instance. * @param decoder_id Decoder 'id' field. * @param options GHashtable of options which override the defaults set in * the decoder class. May be NULL. * * @return Pointer to a newly allocated struct srd_decoder_inst, or * NULL in case of failure. * * @since 0.3.0 */ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, const char *decoder_id, GHashTable *options) { int i; struct srd_decoder *dec; struct srd_decoder_inst *di; char *inst_id; srd_dbg("Creating new %s instance.", decoder_id); if (session_is_valid(sess) != SRD_OK) { srd_err("Invalid session."); return NULL; } if (!(dec = srd_decoder_get_by_id(decoder_id))) { srd_err("Protocol decoder %s not found.", decoder_id); return NULL; } if (!(di = g_try_malloc0(sizeof(struct srd_decoder_inst)))) { srd_err("Failed to g_malloc() instance."); return NULL; } di->decoder = dec; di->sess = sess; if (options) { inst_id = g_hash_table_lookup(options, "id"); di->inst_id = g_strdup(inst_id ? inst_id : decoder_id); g_hash_table_remove(options, "id"); } else di->inst_id = g_strdup(decoder_id); /* * Prepare a default probe map, where samples come in the * 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); if (di->dec_num_probes) { if (!(di->dec_probemap = g_try_malloc(sizeof(int) * di->dec_num_probes))) { srd_err("Failed to g_malloc() probe map."); g_free(di); return NULL; } for (i = 0; i < di->dec_num_probes; i++) di->dec_probemap[i] = i; di->data_unitsize = (di->dec_num_probes + 7) / 8; /* * Will be used to prepare a sample at every iteration * of the instance's decode() method. */ if (!(di->probe_samples = g_try_malloc(di->dec_num_probes))) { srd_err("Failed to g_malloc() sample buffer."); g_free(di->dec_probemap); g_free(di); return NULL; } } /* 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); g_free(di->dec_probemap); g_free(di); return NULL; } if (options && srd_inst_option_set(di, options) != SRD_OK) { g_free(di->dec_probemap); g_free(di); return NULL; } /* Instance takes input from a frontend by default. */ sess->di_list = g_slist_append(sess->di_list, di); return di; }
/** * Set one or more options in a decoder instance. * * Handled options are removed from the hash. * * @param di Decoder instance. * @param options A GHashTable of options to set. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @since 0.1.0 */ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, GHashTable *options) { struct srd_decoder_option *sdo; PyObject *py_di_options, *py_optval; GVariant *value; GSList *l; double val_double; gint64 val_int; int ret; const char *val_str; 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) { /* No options provided. */ return SRD_OK; } else { srd_err("Protocol decoder has no options."); return SRD_ERR_ARG; } return SRD_OK; } ret = SRD_ERR_PYTHON; py_optval = NULL; /* * The 'options' tuple 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 (l = di->decoder->options; l; l = l->next) { sdo = l->data; if ((value = g_hash_table_lookup(options, sdo->id))) { /* A value was supplied for this option. */ if (!g_variant_type_equal(g_variant_get_type(value), g_variant_get_type(sdo->def))) { srd_err("Option '%s' should have the same type " "as the default value.", sdo->id); goto err_out; } } else { /* Use default for this option. */ value = sdo->def; } if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { val_str = g_variant_get_string(value, NULL); if (!(py_optval = PyUnicode_FromString(val_str))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); srd_err("Option '%s' requires a UTF-8 string value.", sdo->id); goto err_out; } } else if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT64)) { val_int = g_variant_get_int64(value); if (!(py_optval = PyLong_FromLong(val_int))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option '%s' has invalid integer value.", sdo->id); goto err_out; } } else if (g_variant_is_of_type(value, G_VARIANT_TYPE_DOUBLE)) { val_double = g_variant_get_double(value); if (!(py_optval = PyFloat_FromDouble(val_double))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option '%s' has invalid float value.", sdo->id); goto err_out; } } if (PyDict_SetItemString(py_di_options, sdo->id, py_optval) == -1) goto err_out; /* Not harmful even if we used the default. */ g_hash_table_remove(options, sdo->id); } if (g_hash_table_size(options) != 0) srd_warn("Unknown options specified for '%s'", di->inst_id); ret = SRD_OK; err_out: Py_XDECREF(py_optval); if (PyErr_Occurred()) { srd_exception_catch("Stray exception in srd_inst_option_set()"); ret = SRD_ERR_PYTHON; } return ret; }
/** * Decode a chunk of samples. * * @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 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. * @param unitsize The number of bytes per sample. Must be > 0. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @private */ 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, uint64_t unitsize) { PyObject *py_res; srd_logic *logic; long apiver; /* Return an error upon unusable input. */ if (!di) { srd_dbg("empty decoder instance"); return SRD_ERR_ARG; } if (!inbuf) { srd_dbg("NULL buffer pointer"); return SRD_ERR_ARG; } if (inbuflen == 0) { srd_dbg("empty buffer"); return SRD_ERR_ARG; } if (unitsize == 0) { srd_dbg("unitsize 0"); return SRD_ERR_ARG; } ((struct srd_decoder_inst *)di)->data_unitsize = unitsize; srd_dbg("Decoding: start sample %" PRIu64 ", end sample %" PRIu64 " (%" PRIu64 " samples, %" PRIu64 " bytes, unitsize = " "%d), instance %s.", start_samplenum, end_samplenum, end_samplenum - start_samplenum, inbuflen, di->data_unitsize, di->inst_id); apiver = srd_decoder_apiver(di->decoder); if (apiver == 2) { /* * Create new srd_logic object. Each iteration around the PD's * loop will fill one sample into this object. */ logic = PyObject_New(srd_logic, (PyTypeObject *)srd_logic_type); Py_INCREF(logic); logic->di = (struct srd_decoder_inst *)di; logic->start_samplenum = start_samplenum; logic->itercnt = 0; logic->inbuf = (uint8_t *)inbuf; logic->inbuflen = inbuflen; logic->sample = PyList_New(2); Py_INCREF(logic->sample); Py_IncRef(di->py_inst); if (!(py_res = PyObject_CallMethod(di->py_inst, "decode", "KKO", start_samplenum, end_samplenum, logic))) { srd_exception_catch("Protocol decoder instance %s", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); } return SRD_OK; }
/** * 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. */ SRD_API int srd_decoder_load(const char *module_name) { PyObject *py_basedec, *py_method, *py_attr, *py_annlist, *py_ann; struct srd_decoder *d; int alen, ret, i; char **ann; struct srd_probe *p; GSList *l; srd_dbg("Loading protocol decoder '%s'.", module_name); py_basedec = py_method = py_attr = NULL; if (!(d = g_try_malloc0(sizeof(struct srd_decoder)))) { srd_dbg("Failed to g_malloc() struct srd_decoder."); ret = SRD_ERR_MALLOC; goto err_out; } ret = SRD_ERR_PYTHON; /* Import the Python module. */ if (!(d->py_mod = PyImport_ImportModule(module_name))) { srd_exception_catch("Import of '%s' failed.", module_name); goto err_out; } /* Get the 'Decoder' class as Python object. */ if (!(d->py_dec = PyObject_GetAttrString(d->py_mod, "Decoder"))) { /* This generated an AttributeError exception. */ PyErr_Clear(); srd_err("Decoder class not found in protocol decoder %s.", module_name); goto err_out; } if (!(py_basedec = PyObject_GetAttrString(mod_sigrokdecode, "Decoder"))) { srd_dbg("sigrokdecode module not loaded."); goto err_out; } if (!PyObject_IsSubclass(d->py_dec, py_basedec)) { srd_err("Decoder class in protocol decoder module %s is not " "a subclass of sigrokdecode.Decoder.", module_name); goto err_out; } Py_CLEAR(py_basedec); /* Check for a proper start() method. */ if (!PyObject_HasAttrString(d->py_dec, "start")) { srd_err("Protocol decoder %s has no start() method Decoder " "class.", module_name); goto err_out; } py_method = PyObject_GetAttrString(d->py_dec, "start"); if (!PyFunction_Check(py_method)) { srd_err("Protocol decoder %s Decoder class attribute 'start' " "is not a method.", module_name); goto err_out; } Py_CLEAR(py_method); /* Check for a proper decode() method. */ if (!PyObject_HasAttrString(d->py_dec, "decode")) { srd_err("Protocol decoder %s has no decode() method Decoder " "class.", module_name); goto err_out; } py_method = PyObject_GetAttrString(d->py_dec, "decode"); if (!PyFunction_Check(py_method)) { srd_err("Protocol decoder %s Decoder class attribute 'decode' " "is not a method.", module_name); goto err_out; } 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); } /* 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, "optional_probes", &d->opt_probes) != SRD_OK) goto err_out; /* * Fix order numbers for the optional probes. * * Example: * Required probes: r1, r2, r3. Optional: o1, o2, o3, o4. * 'order' fields in the d->probes list = 0, 1, 2. * 'order' fields in the d->opt_probes list = 3, 4, 5, 6. */ for (l = d->opt_probes; l; l = l->next) { p = l->data; p->order += g_slist_length(d->probes); } /* Store required fields in newly allocated strings. */ if (py_attr_as_str(d->py_dec, "id", &(d->id)) != SRD_OK) goto err_out; if (py_attr_as_str(d->py_dec, "name", &(d->name)) != SRD_OK) goto err_out; if (py_attr_as_str(d->py_dec, "longname", &(d->longname)) != SRD_OK) goto err_out; if (py_attr_as_str(d->py_dec, "desc", &(d->desc)) != SRD_OK) goto err_out; if (py_attr_as_str(d->py_dec, "license", &(d->license)) != SRD_OK) goto err_out; /* Convert class annotation attribute to GSList of **char. */ d->annotations = NULL; if (PyObject_HasAttrString(d->py_dec, "annotations")) { py_annlist = PyObject_GetAttrString(d->py_dec, "annotations"); if (!PyList_Check(py_annlist)) { srd_err("Protocol decoder module %s annotations " "should be a list.", module_name); goto err_out; } alen = PyList_Size(py_annlist); for (i = 0; i < alen; i++) { py_ann = PyList_GetItem(py_annlist, i); if (!PyList_Check(py_ann) || PyList_Size(py_ann) != 2) { srd_err("Protocol decoder module %s " "annotation %d should be a list with " "two elements.", module_name, i + 1); goto err_out; } if (py_strlist_to_char(py_ann, &ann) != SRD_OK) { goto err_out; } d->annotations = g_slist_append(d->annotations, ann); } } /* Append it to the list of supported/loaded decoders. */ pd_list = g_slist_append(pd_list, d); ret = SRD_OK; err_out: if (ret != SRD_OK) { Py_XDECREF(py_method); Py_XDECREF(py_basedec); Py_XDECREF(d->py_dec); Py_XDECREF(d->py_mod); g_free(d); } return ret; }
/** * Decode a chunk of samples. * * The calls to this function must provide the samples that shall be * used by the protocol decoder * - in the correct order ([...]5, 6, 4, 7, 8[...] is a bug), * - starting from sample zero (2, 3, 4, 5, 6[...] is a bug), * - consecutively, with no gaps (0, 1, 2, 4, 5[...] is a bug). * * The start- and end-sample numbers are absolute sample numbers (relative * to the start of the whole capture/file/stream), i.e. they are not relative * sample numbers within the chunk specified by 'inbuf' and 'inbuflen'. * * Correct example (4096 samples total, 4 chunks @ 1024 samples each): * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * srd_inst_decode(di, 1024, 2047, inbuf, 1024, 1); * srd_inst_decode(di, 2048, 3071, inbuf, 1024, 1); * srd_inst_decode(di, 3072, 4095, inbuf, 1024, 1); * * The chunk size ('inbuflen') can be arbitrary and can differ between calls. * * Correct example (4096 samples total, 7 chunks @ various samples each): * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * srd_inst_decode(di, 1024, 1123, inbuf, 100, 1); * srd_inst_decode(di, 1124, 1423, inbuf, 300, 1); * srd_inst_decode(di, 1424, 1642, inbuf, 219, 1); * srd_inst_decode(di, 1643, 2047, inbuf, 405, 1); * srd_inst_decode(di, 2048, 3071, inbuf, 1024, 1); * srd_inst_decode(di, 3072, 4095, inbuf, 1024, 1); * * INCORRECT example (4096 samples total, 4 chunks @ 1024 samples each, but * the start- and end-samplenumbers are not absolute): * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * srd_inst_decode(di, 0, 1023, inbuf, 1024, 1); * * @param di The decoder instance to call. Must not be NULL. * @param abs_start_samplenum The absolute starting sample number for the * buffer's sample set, relative to the start of capture. * @param abs_end_samplenum The absolute 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. * @param unitsize The number of bytes per sample. Must be > 0. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @private */ SRD_PRIV int srd_inst_decode(struct srd_decoder_inst *di, uint64_t abs_start_samplenum, uint64_t abs_end_samplenum, const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize) { PyObject *py_res; srd_logic *logic; long apiver; /* Return an error upon unusable input. */ if (!di) { srd_dbg("empty decoder instance"); return SRD_ERR_ARG; } if (!inbuf) { srd_dbg("NULL buffer pointer"); return SRD_ERR_ARG; } if (inbuflen == 0) { srd_dbg("empty buffer"); return SRD_ERR_ARG; } if (unitsize == 0) { srd_dbg("unitsize 0"); return SRD_ERR_ARG; } di->data_unitsize = unitsize; srd_dbg("Decoding: abs start sample %" PRIu64 ", abs end sample %" PRIu64 " (%" PRIu64 " samples, %" PRIu64 " bytes, unitsize = " "%d), instance %s.", abs_start_samplenum, abs_end_samplenum, abs_end_samplenum - abs_start_samplenum, inbuflen, di->data_unitsize, di->inst_id); apiver = srd_decoder_apiver(di->decoder); if (apiver == 2) { /* * Create new srd_logic object. Each iteration around the PD's * loop will fill one sample into this object. */ logic = PyObject_New(srd_logic, (PyTypeObject *)srd_logic_type); Py_INCREF(logic); logic->di = (struct srd_decoder_inst *)di; logic->abs_start_samplenum = abs_start_samplenum; logic->itercnt = 0; logic->inbuf = (uint8_t *)inbuf; logic->inbuflen = inbuflen; logic->sample = PyList_New(2); Py_INCREF(logic->sample); Py_IncRef(di->py_inst); if (!(py_res = PyObject_CallMethod(di->py_inst, "decode", "KKO", abs_start_samplenum, abs_end_samplenum, logic))) { srd_exception_catch("Protocol decoder instance %s", di->inst_id); return SRD_ERR_PYTHON; } Py_DecRef(py_res); } else { /* If this is the first call, start the worker thread. */ if (!di->thread_handle) di->thread_handle = g_thread_new("di_thread", di_thread, di); /* Push the new sample chunk to the worker thread. */ g_mutex_lock(&di->data_mutex); di->abs_start_samplenum = abs_start_samplenum; di->abs_end_samplenum = abs_end_samplenum; di->inbuf = inbuf; di->inbuflen = inbuflen; di->got_new_samples = TRUE; di->handled_all_samples = FALSE; /* Signal the thread that we have new data. */ g_cond_signal(&di->got_new_samples_cond); g_mutex_unlock(&di->data_mutex); /* When all samples in this chunk were handled, return. */ g_mutex_lock(&di->data_mutex); while (!di->handled_all_samples) g_cond_wait(&di->handled_all_samples_cond, &di->data_mutex); g_mutex_unlock(&di->data_mutex); } return SRD_OK; }
static PyObject *Decoder_put(PyObject *self, PyObject *args) { GSList *l; PyObject *py_data, *py_res; struct srd_decoder_inst *di, *next_di; struct srd_pd_output *pdo; struct srd_proto_data *pdata; uint64_t start_sample, end_sample; int output_id; struct srd_pd_callback *cb; if (!(di = srd_inst_find_by_obj(NULL, self))) { /* Shouldn't happen. */ srd_dbg("put(): self instance not found."); return NULL; } if (!PyArg_ParseTuple(args, "KKiO", &start_sample, &end_sample, &output_id, &py_data)) { /* * This throws an exception, but by returning NULL here we let * Python raise it. This results in a much better trace in * controller.c on the decode() method call. */ return NULL; } if (!(l = g_slist_nth(di->pd_output, output_id))) { srd_err("Protocol decoder %s submitted invalid output ID %d.", di->decoder->name, output_id); return NULL; } pdo = l->data; srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s on oid %d.", di->inst_id, start_sample, end_sample, OUTPUT_TYPES[pdo->output_type], output_id); if (!(pdata = g_try_malloc0(sizeof(struct srd_proto_data)))) { srd_err("Failed to g_malloc() struct srd_proto_data."); return NULL; } pdata->start_sample = start_sample; pdata->end_sample = end_sample; pdata->pdo = pdo; switch (pdo->output_type) { case SRD_OUTPUT_ANN: /* Annotations are only fed to callbacks. */ if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) { /* Convert from PyDict to srd_proto_data_annotation. */ if (convert_annotation(di, py_data, pdata) != SRD_OK) { /* An error was already logged. */ break; } cb->cb(pdata, cb->cb_data); } break; case SRD_OUTPUT_PYTHON: for (l = di->next_di; l; l = l->next) { next_di = l->data; srd_spew("Sending %d-%d to instance %s", start_sample, end_sample, next_di->inst_id); if (!(py_res = PyObject_CallMethod( next_di->py_inst, "decode", "KKO", start_sample, end_sample, py_data))) { srd_exception_catch("Calling %s decode(): ", next_di->inst_id); } Py_XDECREF(py_res); } if ((cb = srd_pd_output_callback_find(di->sess, pdo->output_type))) { /* Frontends aren't really supposed to get Python * callbacks, but it's useful for testing. */ pdata->data = py_data; cb->cb(pdata, cb->cb_data); } break; case SRD_OUTPUT_BINARY: 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))) { /* Annotations need converting from PyObject. */ if (convert_meta(pdata, py_data) != SRD_OK) { /* An exception was already set up. */ break; } cb->cb(pdata, cb->cb_data); } break; default: srd_err("Protocol decoder %s submitted invalid output type %d.", di->decoder->name, pdo->output_type); break; } g_free(pdata); Py_RETURN_NONE; }
static PyObject *Decoder_put(PyObject *self, PyObject *args) { GSList *l; PyObject *data, *py_res; struct srd_decoder_inst *di, *next_di; struct srd_pd_output *pdo; struct srd_proto_data *pdata; uint64_t start_sample, end_sample; int output_id; void (*cb)(); if (!(di = srd_inst_find_by_obj(NULL, self))) { /* Shouldn't happen. */ srd_dbg("put(): self instance not found."); return NULL; } if (!PyArg_ParseTuple(args, "KKiO", &start_sample, &end_sample, &output_id, &data)) { /* * This throws an exception, but by returning NULL here we let * Python raise it. This results in a much better trace in * controller.c on the decode() method call. */ return NULL; } if (!(l = g_slist_nth(di->pd_output, output_id))) { srd_err("Protocol decoder %s submitted invalid output ID %d.", di->decoder->name, output_id); return NULL; } pdo = l->data; srd_spew("Instance %s put %" PRIu64 "-%" PRIu64 " %s on oid %d.", di->inst_id, start_sample, end_sample, OUTPUT_TYPES[pdo->output_type], output_id); if (!(pdata = g_try_malloc0(sizeof(struct srd_proto_data)))) { srd_err("Failed to g_malloc() struct srd_proto_data."); return NULL; } pdata->start_sample = start_sample; pdata->end_sample = end_sample; pdata->pdo = pdo; switch (pdo->output_type) { case SRD_OUTPUT_ANN: /* Annotations are only fed to callbacks. */ if ((cb = srd_pd_output_callback_find(pdo->output_type))) { /* Annotations need converting from PyObject. */ if (convert_pyobj(di, data, &pdata->ann_format, (char ***)&pdata->data) != SRD_OK) { /* An error was already logged. */ break; } cb(pdata); } break; case SRD_OUTPUT_PROTO: for (l = di->next_di; l; l = l->next) { next_di = l->data; /* TODO: Is this needed? */ Py_XINCREF(next_di->py_inst); srd_spew("Sending %d-%d to instance %s", start_sample, end_sample, next_di->inst_id); if (!(py_res = PyObject_CallMethod( next_di->py_inst, "decode", "KKO", start_sample, end_sample, data))) { srd_exception_catch("Calling %s decode(): ", next_di->inst_id); } 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); break; } g_free(pdata); Py_RETURN_NONE; }
/** * Set one or more options in a decoder instance. * * Handled options are removed from the hash. * * @param di Decoder instance. * @param options A GHashTable of options to set. * * @return SRD_OK upon success, a (negative) error code otherwise. */ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, GHashTable *options) { PyObject *py_dec_options, *py_dec_optkeys, *py_di_options, *py_optval; PyObject *py_optlist, *py_classval; Py_UNICODE *py_ustr; unsigned long long int val_ull; int num_optkeys, ret, size, i; char *key, *value; if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ if (g_hash_table_size(options) == 0) { /* No options provided. */ return SRD_OK; } else { srd_err("Protocol decoder has no options."); return SRD_ERR_ARG; } return SRD_OK; } ret = SRD_ERR_PYTHON; key = NULL; py_dec_options = py_dec_optkeys = py_di_options = py_optval = NULL; py_optlist = py_classval = NULL; py_dec_options = PyObject_GetAttrString(di->decoder->py_dec, "options"); /* 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); if (!(py_di_options = PyObject_GetAttrString(di->py_inst, "options"))) goto err_out; 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); if (!(py_optlist = PyDict_GetItemString(py_dec_options, key))) goto err_out; if (!(py_classval = PyList_GetItem(py_optlist, 1))) goto err_out; if (!PyUnicode_Check(py_classval) && !PyLong_Check(py_classval)) { srd_err("Options of type %s are not yet supported.", Py_TYPE(py_classval)->tp_name); goto err_out; } if ((value = g_hash_table_lookup(options, key))) { /* An override for this option was provided. */ if (PyUnicode_Check(py_classval)) { if (!(py_optval = PyUnicode_FromString(value))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); goto err_out; } } else if (PyLong_Check(py_classval)) { if (!(py_optval = PyLong_FromString(value, NULL, 0))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option %s has invalid value " "%s: expected integer.", key, value); goto err_out; } } g_hash_table_remove(options, key); } else { /* Use the class default for this option. */ if (PyUnicode_Check(py_classval)) { /* Make a brand new copy of the string. */ py_ustr = PyUnicode_AS_UNICODE(py_classval); size = PyUnicode_GET_SIZE(py_classval); py_optval = PyUnicode_FromUnicode(py_ustr, size); } else if (PyLong_Check(py_classval)) { /* Make a brand new copy of the integer. */ val_ull = PyLong_AsUnsignedLongLong(py_classval); if (val_ull == (unsigned long long)-1) { /* OverFlowError exception */ PyErr_Clear(); srd_err("Invalid integer value for %s: " "expected integer.", key); goto err_out; } if (!(py_optval = PyLong_FromUnsignedLongLong(val_ull))) goto err_out; } } /* * If we got here, py_optval holds a known good new reference * to the instance option to set. */ if (PyDict_SetItemString(py_di_options, key, py_optval) == -1) goto err_out; } 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()) srd_exception_catch("Stray exception in srd_inst_option_set()."); return ret; }