- if (dec == NULL)
- return SRD_ERR_ARG; /* TODO: More specific error? */
- if (inbuf == NULL)
- return SRD_ERR_ARG; /* TODO: More specific error? */
- if (inbuflen == 0) /* No point in working on empty buffers. */
- return SRD_ERR_ARG; /* TODO: More specific error? */
-
- /* TODO: Error handling. */
- py_instance = dec->py_instance;
- Py_XINCREF(py_instance);
-
- if (!(py_res = PyObject_CallMethod(py_instance, "decode",
- "{s:i,s:i,s:s#}",
- "time", _timehack,
- "duration", 10,
- "data", inbuf, inbuflen))) { /* NEWREF */
- if (PyErr_Occurred())
- PyErr_Print(); /* Returns void. */
+ 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);
+ 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;
+}
+
+/** @private */
+SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di)
+{
+ GSList *l;
+ struct srd_pd_output *pdo;
+
+ srd_dbg("Freeing instance %s", di->inst_id);
+
+ Py_DecRef(di->py_inst);
+ g_free(di->inst_id);
+ g_free(di->dec_probemap);
+ g_slist_free(di->next_di);
+ for (l = di->pd_output; l; l = l->next) {
+ pdo = l->data;
+ g_free(pdo->proto_id);
+ g_free(pdo);
+ }
+ g_slist_free(di->pd_output);
+ g_free(di);
+}
+
+/** @private */
+SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack)
+{
+ GSList *l;
+ struct srd_decoder_inst *di;
+
+ if (session_is_valid(sess) != SRD_OK) {
+ srd_err("Invalid session.");
+ return;
+ }
+
+ di = NULL;
+ for (l = stack ? stack : sess->di_list; di == NULL && l != NULL; l = l->next) {
+ di = l->data;
+ if (di->next_di)
+ srd_inst_free_all(sess, di->next_di);
+ srd_inst_free(di);
+ }
+ if (!stack) {
+ g_slist_free(sess->di_list);
+ sess->di_list = NULL;
+ }
+}
+
+/** @} */
+
+/**
+ * @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_ARG;
+ }
+
+ if (!(*sess = g_try_malloc(sizeof(struct srd_session))))
+ return SRD_ERR_MALLOC;
+ (*sess)->session_id = ++max_session_id;
+ (*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.3.0
+ */
+SRD_API int srd_session_start(struct srd_session *sess)
+{
+ GSList *d;
+ struct srd_decoder_inst *di;
+ int ret;
+
+ if (session_is_valid(sess) != SRD_OK) {
+ srd_err("Invalid session pointer.");
+ return SRD_ERR;
+ }