From: Gerhard S. <ger...@gm...> - 2016-10-16 16:26:56
|
Protocol decoders scan incoming samples in their decode() method, to derive higher level "frames" or "transactions" or similar, and send them to the output stream. Typically sample data from multiple decode() calls needs to get processed before sending a higher level annotation to the output. But protocol decoders cannot determine whether a decode() call carries the last available input data, or whether more calls will follow. Add support for an optional decode_end() method with no parameters. When the input stream for a decoder session was exhausted, this method gets called for all decoders which implement it. Execution order copes with decoder stacks. Add a new public srd_session_send_eof() call to the libsigrokdecode API. When invoked, it will call the decode_end() method of all protocol decoders which are involved in the specified session (when they implement the method, absence of the method is non-fatal). Strictly speaking a protocol decoder might question whether a "frame" was completed when its terminating condition was not observed (e.g. the deassertion of a select signal, or an idle line for a certain amount of bit times). In these cases, the decoder can flush the data which was accumulated so far, yet emit a warning that the last frame should be considered incomplete ("unterminated"). This change is related to, but does not resolve Bugs 292 and 749. Signed-off-by: Gerhard Sittig <ger...@gm...> --- instance.c | 43 +++++++++++++++++++++++++++++++++++++++++++ libsigrokdecode-internal.h | 1 + libsigrokdecode.h | 1 + session.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/instance.c b/instance.c index b1bfd81ce0bf..911eabd4411d 100644 --- a/instance.c +++ b/instance.c @@ -602,6 +602,49 @@ SRD_PRIV int srd_inst_decode(const struct srd_decoder_inst *di, } /** @private */ +SRD_PRIV int srd_inst_decode_end(struct srd_decoder_inst *di) +{ + const char *meth_name; + int has_meth; + PyObject *py_res; + GSList *l; + struct srd_decoder_inst *next_di; + int ret; + + /* + * Invoke the optional decode_end() method. Absence of the method + * is acceptable, failed execution of a present method is fatal. + */ + meth_name = "decode_end"; + has_meth = PyObject_HasAttrString(di->decoder->py_dec, meth_name); + if (has_meth) { + srd_dbg("Calling %s() method on protocol decoder instance %s.", + meth_name, di->inst_id); + Py_IncRef(di->py_inst); + py_res = PyObject_CallMethod(di->py_inst, meth_name, NULL); + if (!py_res) { + srd_exception_catch("Protocol decoder instance %s", + di->inst_id); + return SRD_ERR_PYTHON; + } + Py_DecRef(py_res); + } else { + srd_dbg("Skipping %s() method on protocol decoder instance %s.", + meth_name, di->inst_id); + } + + /* Recurse for all the PDs stacked on top of this one. */ + for (l = di->next_di; l; l = l->next) { + next_di = l->data; + ret = srd_inst_decode_end(next_di); + if (ret != SRD_OK) + return ret; + } + + return SRD_OK; +} + +/** @private */ SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di) { GSList *l; diff --git a/libsigrokdecode-internal.h b/libsigrokdecode-internal.h index 8259b97935a9..8ee6fb47940e 100644 --- a/libsigrokdecode-internal.h +++ b/libsigrokdecode-internal.h @@ -65,6 +65,7 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di); 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); +SRD_PRIV int srd_inst_decode_end(struct srd_decoder_inst *di); SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di); SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack); diff --git a/libsigrokdecode.h b/libsigrokdecode.h index 03a5de096b18..ce38941af263 100644 --- a/libsigrokdecode.h +++ b/libsigrokdecode.h @@ -278,6 +278,7 @@ SRD_API int srd_session_metadata_set(struct srd_session *sess, int key, SRD_API int srd_session_send(struct srd_session *sess, uint64_t start_samplenum, uint64_t end_samplenum, const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize); +SRD_API int srd_session_send_eof(struct srd_session *sess); SRD_API int srd_session_destroy(struct srd_session *sess); SRD_API int srd_pd_output_callback_add(struct srd_session *sess, int output_type, srd_pd_output_callback cb, void *cb_data); diff --git a/session.c b/session.c index e1bb4f9880d3..13f5c0cd14dd 100644 --- a/session.c +++ b/session.c @@ -257,6 +257,34 @@ SRD_API int srd_session_send(struct srd_session *sess, } /** + * Communicate "end of input" within the running decoder session. + * + * @param sess The session to use. Must not be NULL. + * + * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.5.0 + */ +SRD_API int srd_session_send_eof(struct srd_session *sess) +{ + GSList *d; + int ret; + + if (session_is_valid(sess) != SRD_OK) { + srd_err("Invalid session."); + return SRD_ERR_ARG; + } + + for (d = sess->di_list; d; d = d->next) { + ret = srd_inst_decode_end(d->data); + if (ret != SRD_OK) + return ret; + } + + return SRD_OK; +} + +/** * Destroy a decoding session. * * All decoder instances and output callbacks are properly released. -- 1.9.1 |