]> sigrok.org Git - libsigrokdecode.git/blob - session.c
srd_exit(): Fix a -Wcast-function-type compiler warning.
[libsigrokdecode.git] / session.c
1 /*
2  * This file is part of the libsigrokdecode project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
23 #include "libsigrokdecode.h"
24 #include <inttypes.h>
25 #include <glib.h>
26
27 /**
28  * @file
29  *
30  * Session handling.
31  */
32
33 /**
34  * @defgroup grp_session Session handling
35  *
36  * Starting and handling decoding sessions.
37  *
38  * @{
39  */
40
41 /** @cond PRIVATE */
42
43 SRD_PRIV GSList *sessions = NULL;
44 SRD_PRIV int max_session_id = -1;
45
46 /** @endcond */
47
48 /**
49  * Create a decoding session.
50  *
51  * A session holds all decoder instances, their stack relationships and
52  * output callbacks.
53  *
54  * @param sess A pointer which will hold a pointer to a newly
55  *             initialized session on return. Must not be NULL.
56  *
57  * @return SRD_OK upon success, a (negative) error code otherwise.
58  *
59  * @since 0.3.0
60  */
61 SRD_API int srd_session_new(struct srd_session **sess)
62 {
63         if (!sess)
64                 return SRD_ERR_ARG;
65
66         *sess = g_malloc(sizeof(struct srd_session));
67         (*sess)->session_id = ++max_session_id;
68         (*sess)->di_list = (*sess)->callbacks = NULL;
69
70         /* Keep a list of all sessions, so we can clean up as needed. */
71         sessions = g_slist_append(sessions, *sess);
72
73         srd_dbg("Created session %d.", (*sess)->session_id);
74
75         return SRD_OK;
76 }
77
78 /**
79  * Start a decoding session.
80  *
81  * Decoders, instances and stack must have been prepared beforehand,
82  * and all SRD_CONF parameters set.
83  *
84  * @param sess The session to start. Must not be NULL.
85  *
86  * @return SRD_OK upon success, a (negative) error code otherwise.
87  *
88  * @since 0.3.0
89  */
90 SRD_API int srd_session_start(struct srd_session *sess)
91 {
92         GSList *d;
93         struct srd_decoder_inst *di;
94         int ret;
95
96         if (!sess)
97                 return SRD_ERR_ARG;
98
99         srd_dbg("Calling start() on all instances in session %d.", sess->session_id);
100
101         /* Run the start() method on all decoders receiving frontend data. */
102         ret = SRD_OK;
103         for (d = sess->di_list; d; d = d->next) {
104                 di = d->data;
105                 if ((ret = srd_inst_start(di)) != SRD_OK)
106                         break;
107         }
108
109         return ret;
110 }
111
112 static int srd_inst_send_meta(struct srd_decoder_inst *di, int key,
113                 GVariant *data)
114 {
115         PyObject *py_ret;
116         GSList *l;
117         struct srd_decoder_inst *next_di;
118         int ret;
119         PyGILState_STATE gstate;
120
121         if (key != SRD_CONF_SAMPLERATE)
122                 /* This is the only key we pass on to the decoder for now. */
123                 return SRD_OK;
124
125         gstate = PyGILState_Ensure();
126
127         if (PyObject_HasAttrString(di->py_inst, "metadata")) {
128                 py_ret = PyObject_CallMethod(di->py_inst, "metadata", "lK",
129                                 (long)SRD_CONF_SAMPLERATE,
130                                 (unsigned long long)g_variant_get_uint64(data));
131                 Py_XDECREF(py_ret);
132         }
133
134         PyGILState_Release(gstate);
135
136         /* Push metadata to all the PDs stacked on top of this one. */
137         for (l = di->next_di; l; l = l->next) {
138                 next_di = l->data;
139                 if ((ret = srd_inst_send_meta(next_di, key, data)) != SRD_OK)
140                         return ret;
141         }
142
143         return SRD_OK;
144 }
145
146 /**
147  * Set a metadata configuration key in a session.
148  *
149  * @param sess The session to configure. Must not be NULL.
150  * @param key The configuration key (SRD_CONF_*).
151  * @param data The new value for the key, as a GVariant with GVariantType
152  *             appropriate to that key. A floating reference can be passed
153  *             in; its refcount will be sunk and unreferenced after use.
154  *
155  * @return SRD_OK upon success, a (negative) error code otherwise.
156  *
157  * @since 0.3.0
158  */
159 SRD_API int srd_session_metadata_set(struct srd_session *sess, int key,
160                 GVariant *data)
161 {
162         GSList *l;
163         int ret;
164
165         if (!sess)
166                 return SRD_ERR_ARG;
167
168         if (!key) {
169                 srd_err("Invalid key.");
170                 return SRD_ERR_ARG;
171         }
172
173         if (!data) {
174                 srd_err("Invalid value.");
175                 return SRD_ERR_ARG;
176         }
177
178         /* Hardcoded to samplerate/uint64 for now. */
179
180         if (key != SRD_CONF_SAMPLERATE) {
181                 srd_err("Unknown config key %d.", key);
182                 return SRD_ERR_ARG;
183         }
184         if (!g_variant_is_of_type(data, G_VARIANT_TYPE_UINT64)) {
185                 srd_err("Invalid value type: expected uint64, got %s",
186                                 g_variant_get_type_string(data));
187                 return SRD_ERR_ARG;
188         }
189
190         srd_dbg("Setting session %d samplerate to %"G_GUINT64_FORMAT".",
191                         sess->session_id, g_variant_get_uint64(data));
192
193         ret = SRD_OK;
194         for (l = sess->di_list; l; l = l->next) {
195                 if ((ret = srd_inst_send_meta(l->data, key, data)) != SRD_OK)
196                         break;
197         }
198
199         g_variant_unref(data);
200
201         return ret;
202 }
203
204 /**
205  * Send a chunk of logic sample data to a running decoder session.
206  *
207  * If no channel map has been set up, the logic samples must be arranged
208  * in channel order, in the least amount of space possible. The default
209  * channel set consists of all required channels + all optional channels.
210  *
211  * The size of a sample in inbuf is 'unitsize' bytes. If no channel map
212  * has been configured, it is the minimum number of bytes needed to store
213  * the default channels.
214  *
215  * The calls to this function must provide the samples that shall be
216  * used by the protocol decoder
217  *  - in the correct order ([...]5, 6, 4, 7, 8[...] is a bug),
218  *  - starting from sample zero (2, 3, 4, 5, 6[...] is a bug),
219  *  - consecutively, with no gaps (0, 1, 2, 4, 5[...] is a bug).
220  *
221  * The start- and end-sample numbers are absolute sample numbers (relative
222  * to the start of the whole capture/file/stream), i.e. they are not relative
223  * sample numbers within the chunk specified by 'inbuf' and 'inbuflen'.
224  *
225  * Correct example (4096 samples total, 4 chunks @ 1024 samples each):
226  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
227  *   srd_session_send(s, 1024, 2047, inbuf, 1024, 1);
228  *   srd_session_send(s, 2048, 3071, inbuf, 1024, 1);
229  *   srd_session_send(s, 3072, 4095, inbuf, 1024, 1);
230  *
231  * The chunk size ('inbuflen') can be arbitrary and can differ between calls.
232  *
233  * Correct example (4096 samples total, 7 chunks @ various samples each):
234  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
235  *   srd_session_send(s, 1024, 1123, inbuf,  100, 1);
236  *   srd_session_send(s, 1124, 1423, inbuf,  300, 1);
237  *   srd_session_send(s, 1424, 1642, inbuf,  219, 1);
238  *   srd_session_send(s, 1643, 2047, inbuf,  405, 1);
239  *   srd_session_send(s, 2048, 3071, inbuf, 1024, 1);
240  *   srd_session_send(s, 3072, 4095, inbuf, 1024, 1);
241  *
242  * INCORRECT example (4096 samples total, 4 chunks @ 1024 samples each, but
243  * the start- and end-samplenumbers are not absolute):
244  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
245  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
246  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
247  *   srd_session_send(s, 0,    1023, inbuf, 1024, 1);
248  *
249  * @param sess The session to use. Must not be NULL.
250  * @param abs_start_samplenum The absolute starting sample number for the
251  *              buffer's sample set, relative to the start of capture.
252  * @param abs_end_samplenum The absolute ending sample number for the
253  *              buffer's sample set, relative to the start of capture.
254  * @param inbuf Pointer to sample data. Must not be NULL.
255  * @param inbuflen Length in bytes of the buffer. Must be > 0.
256  * @param unitsize The number of bytes per sample. Must be > 0.
257  *
258  * @return SRD_OK upon success, a (negative) error code otherwise.
259  *
260  * @since 0.4.0
261  */
262 SRD_API int srd_session_send(struct srd_session *sess,
263                 uint64_t abs_start_samplenum, uint64_t abs_end_samplenum,
264                 const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize)
265 {
266         GSList *d;
267         int ret;
268
269         if (!sess)
270                 return SRD_ERR_ARG;
271
272         for (d = sess->di_list; d; d = d->next) {
273                 if ((ret = srd_inst_decode(d->data, abs_start_samplenum,
274                                 abs_end_samplenum, inbuf, inbuflen, unitsize)) != SRD_OK)
275                         return ret;
276         }
277
278         return SRD_OK;
279 }
280
281 /**
282  * Terminate currently executing decoders in a session, reset internal state.
283  *
284  * All decoder instances have their .wait() method terminated, which
285  * shall terminate .decode() as well. Afterwards the decoders' optional
286  * .reset() method gets executed.
287  *
288  * This routine allows callers to abort pending expensive operations,
289  * when they are no longer interested in the decoders' results. Note
290  * that the decoder state is lost and aborted work cannot resume.
291  *
292  * This routine also allows callers to re-use previously created decoder
293  * stacks to process new input data which is not related to previously
294  * processed input data. This avoids the necessity to re-construct the
295  * decoder stack.
296  *
297  * @param sess The session in which to terminate decoders. Must not be NULL.
298  *
299  * @return SRD_OK upon success, a (negative) error code otherwise.
300  *
301  * @since 0.6.0
302  */
303 SRD_API int srd_session_terminate_reset(struct srd_session *sess)
304 {
305         GSList *d;
306         int ret;
307
308         if (!sess)
309                 return SRD_ERR_ARG;
310
311         for (d = sess->di_list; d; d = d->next) {
312                 ret = srd_inst_terminate_reset(d->data);
313                 if (ret != SRD_OK)
314                         return ret;
315         }
316
317         return SRD_OK;
318 }
319
320 /**
321  * Destroy a decoding session.
322  *
323  * All decoder instances and output callbacks are properly released.
324  *
325  * @param sess The session to be destroyed. Must not be NULL.
326  *
327  * @return SRD_OK upon success, a (negative) error code otherwise.
328  *
329  * @since 0.3.0
330  */
331 SRD_API int srd_session_destroy(struct srd_session *sess)
332 {
333         int session_id;
334
335         if (!sess)
336                 return SRD_ERR_ARG;
337
338         session_id = sess->session_id;
339         if (sess->di_list)
340                 srd_inst_free_all(sess);
341         if (sess->callbacks)
342                 g_slist_free_full(sess->callbacks, g_free);
343         sessions = g_slist_remove(sessions, sess);
344         g_free(sess);
345
346         srd_dbg("Destroyed session %d.", session_id);
347
348         return SRD_OK;
349 }
350
351 /**
352  * Register/add a decoder output callback function.
353  *
354  * The function will be called when a protocol decoder sends output back
355  * to the PD controller (except for Python objects, which only go up the
356  * stack).
357  *
358  * @param sess The output session in which to register the callback.
359  *             Must not be NULL.
360  * @param output_type The output type this callback will receive. Only one
361  *                    callback per output type can be registered.
362  * @param cb The function to call. Must not be NULL.
363  * @param cb_data Private data for the callback function. Can be NULL.
364  *
365  * @since 0.3.0
366  */
367 SRD_API int srd_pd_output_callback_add(struct srd_session *sess,
368                 int output_type, srd_pd_output_callback cb, void *cb_data)
369 {
370         struct srd_pd_callback *pd_cb;
371
372         if (!sess)
373                 return SRD_ERR_ARG;
374
375         srd_dbg("Registering new callback for output type %d.", output_type);
376
377         pd_cb = g_malloc(sizeof(struct srd_pd_callback));
378         pd_cb->output_type = output_type;
379         pd_cb->cb = cb;
380         pd_cb->cb_data = cb_data;
381         sess->callbacks = g_slist_append(sess->callbacks, pd_cb);
382
383         return SRD_OK;
384 }
385
386 /** @private */
387 SRD_PRIV struct srd_pd_callback *srd_pd_output_callback_find(
388                 struct srd_session *sess, int output_type)
389 {
390         GSList *l;
391         struct srd_pd_callback *tmp, *pd_cb;
392
393         if (!sess)
394                 return NULL;
395
396         pd_cb = NULL;
397         for (l = sess->callbacks; l; l = l->next) {
398                 tmp = l->data;
399                 if (tmp->output_type == output_type) {
400                         pd_cb = tmp;
401                         break;
402                 }
403         }
404
405         return pd_cb;
406 }
407
408 /** @} */