]> sigrok.org Git - sigrok-cli.git/blob - session.c
Don't leak GVariant.
[sigrok-cli.git] / session.c
1 /*
2  * This file is part of the sigrok-cli project.
3  *
4  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "sigrok-cli.h"
21 #include "config.h"
22 #include <glib.h>
23 #include <glib/gstdio.h>
24
25 static struct sr_output_format *output_format = NULL;
26 static int default_output_format = FALSE;
27 static char *output_format_param = NULL;
28 static GByteArray *savebuf;
29 static uint64_t limit_samples = 0;
30 static uint64_t limit_frames = 0;
31
32 extern gchar *opt_output_file;
33 extern gchar *opt_output_format;
34 extern gchar *opt_pds;
35 extern gboolean opt_wait_trigger;
36 extern gchar *opt_time;
37 extern gchar *opt_samples;
38 extern gchar *opt_frames;
39 extern gchar *opt_continuous;
40 extern gchar *opt_config;
41 extern gchar *opt_triggers;
42 #ifdef HAVE_SRD
43 extern struct srd_session *srd_sess;
44 #endif
45
46
47 static GArray *get_enabled_logic_probes(const struct sr_dev_inst *sdi)
48 {
49         struct sr_probe *probe;
50         GArray *probes;
51         GSList *l;
52
53         probes = g_array_new(FALSE, FALSE, sizeof(int));
54         for (l = sdi->probes; l; l = l->next) {
55                 probe = l->data;
56                 if (probe->type != SR_PROBE_LOGIC)
57                         continue;
58                 if (probe->enabled != TRUE)
59                         continue;
60                 g_array_append_val(probes, probe->index);
61         }
62
63         return probes;
64 }
65
66 static int set_limit_time(const struct sr_dev_inst *sdi)
67 {
68         GVariant *gvar;
69         uint64_t time_msec;
70         uint64_t samplerate;
71
72         if (!(time_msec = sr_parse_timestring(opt_time))) {
73                 g_critical("Invalid time '%s'", opt_time);
74                 return SR_ERR;
75         }
76
77         if (sr_dev_has_option(sdi, SR_CONF_LIMIT_MSEC)) {
78                 gvar = g_variant_new_uint64(time_msec);
79                 if (sr_config_set(sdi, NULL, SR_CONF_LIMIT_MSEC, gvar) != SR_OK) {
80                         g_critical("Failed to configure time limit.");
81                         return SR_ERR;
82                 }
83         } else if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) {
84                 /* Convert to samples based on the samplerate.  */
85                 sr_config_get(sdi->driver, sdi, NULL, SR_CONF_SAMPLERATE, &gvar);
86                 samplerate = g_variant_get_uint64(gvar);
87                 g_variant_unref(gvar);
88                 limit_samples = (samplerate) * time_msec / (uint64_t)1000;
89                 if (limit_samples == 0) {
90                         g_critical("Not enough time at this samplerate.");
91                         return SR_ERR;
92                 }
93                 gvar = g_variant_new_uint64(limit_samples);
94                 if (sr_config_set(sdi, NULL, SR_CONF_LIMIT_SAMPLES, gvar) != SR_OK) {
95                         g_critical("Failed to configure time-based sample limit.");
96                         return SR_ERR;
97                 }
98         } else {
99                 g_critical("This device does not support time limits.");
100                 return SR_ERR;
101         }
102
103         return SR_OK;
104 }
105
106 int setup_output_format(void)
107 {
108         GHashTable *fmtargs;
109         GHashTableIter iter;
110         gpointer key, value;
111         struct sr_output_format **outputs;
112         int i;
113         char *fmtspec;
114
115         if (opt_output_format && !strcmp(opt_output_format, "sigrok")) {
116                 /* Doesn't really exist as an output module - this is
117                  * the session save mode. */
118                 g_free(opt_output_format);
119                 opt_output_format = NULL;
120         }
121
122         if (!opt_output_format) {
123                 opt_output_format = DEFAULT_OUTPUT_FORMAT;
124                 /* we'll need to remember this so when saving to a file
125                  * later, sigrok session format will be used.
126                  */
127                 default_output_format = TRUE;
128         }
129
130         fmtargs = parse_generic_arg(opt_output_format, TRUE);
131         fmtspec = g_hash_table_lookup(fmtargs, "sigrok_key");
132         if (!fmtspec) {
133                 g_critical("Invalid output format.");
134                 return 1;
135         }
136         outputs = sr_output_list();
137         for (i = 0; outputs[i]; i++) {
138                 if (strcmp(outputs[i]->id, fmtspec))
139                         continue;
140                 g_hash_table_remove(fmtargs, "sigrok_key");
141                 output_format = outputs[i];
142                 g_hash_table_iter_init(&iter, fmtargs);
143                 while (g_hash_table_iter_next(&iter, &key, &value)) {
144                         /* only supporting one parameter per output module
145                          * for now, and only its value */
146                         output_format_param = g_strdup(value);
147                         break;
148                 }
149                 break;
150         }
151         if (!output_format) {
152                 g_critical("Invalid output format %s.", opt_output_format);
153                 return 1;
154         }
155         g_hash_table_destroy(fmtargs);
156
157         return 0;
158 }
159
160 void datafeed_in(const struct sr_dev_inst *sdi,
161                 const struct sr_datafeed_packet *packet, void *cb_data)
162 {
163         const struct sr_datafeed_meta *meta;
164         const struct sr_datafeed_logic *logic;
165         const struct sr_datafeed_analog *analog;
166         struct sr_config *src;
167         static struct sr_output *o = NULL;
168         static GArray *logic_probelist = NULL;
169         static uint64_t received_samples = 0;
170         static int unitsize = 0;
171         static int triggered = 0;
172         static FILE *outfile = NULL;
173         GSList *l;
174         GString *out;
175         int sample_size, ret;
176         uint64_t samplerate, output_len, filter_out_len, end_sample;
177         uint8_t *output_buf, *filter_out;
178
179         (void) cb_data;
180
181         /* If the first packet to come in isn't a header, don't even try. */
182         if (packet->type != SR_DF_HEADER && o == NULL)
183                 return;
184
185         sample_size = -1;
186         switch (packet->type) {
187         case SR_DF_HEADER:
188                 g_debug("cli: Received SR_DF_HEADER");
189                 /* Initialize the output module. */
190                 if (!(o = g_try_malloc(sizeof(struct sr_output)))) {
191                         g_critical("Output module malloc failed.");
192                         exit(1);
193                 }
194                 o->format = output_format;
195                 o->sdi = (struct sr_dev_inst *)sdi;
196                 o->param = output_format_param;
197                 if (o->format->init) {
198                         if (o->format->init(o) != SR_OK) {
199                                 g_critical("Output format initialization failed.");
200                                 exit(1);
201                         }
202                 }
203
204                 /* Prepare non-stdout output. */
205                 outfile = stdout;
206                 if (opt_output_file) {
207                         if (default_output_format) {
208                                 /* output file is in session format, so we'll
209                                  * keep a copy of everything as it comes in
210                                  * and save from there after the session. */
211                                 outfile = NULL;
212                                 savebuf = g_byte_array_new();
213                         } else {
214                                 /* saving to a file in whatever format was set
215                                  * with --format, so all we need is a filehandle */
216                                 outfile = g_fopen(opt_output_file, "wb");
217                         }
218                 }
219
220                 /* Prepare for logic data. */
221                 logic_probelist = get_enabled_logic_probes(sdi);
222                 /* How many bytes we need to store the packed samples. */
223                 unitsize = (logic_probelist->len + 7) / 8;
224
225 #ifdef HAVE_SRD
226                 GVariant *gvar;
227                 if (opt_pds && logic_probelist->len) {
228                         if (sr_config_get(sdi->driver, sdi, NULL, SR_CONF_SAMPLERATE,
229                                         &gvar) == SR_OK) {
230                                 samplerate = g_variant_get_uint64(gvar);
231                                 g_variant_unref(gvar);
232                                 if (srd_session_metadata_set(srd_sess, SRD_CONF_SAMPLERATE,
233                                                 g_variant_new_uint64(samplerate)) != SRD_OK) {
234                                         g_critical("Failed to configure decode session.");
235                                         break;
236                                 }
237                         }
238                         if (srd_session_start(srd_sess) != SRD_OK) {
239                                 g_critical("Failed to start decode session.");
240                                 break;
241                         }
242                 }
243 #endif
244                 break;
245
246         case SR_DF_META:
247                 g_debug("cli: received SR_DF_META");
248                 meta = packet->payload;
249                 for (l = meta->config; l; l = l->next) {
250                         src = l->data;
251                         switch (src->key) {
252                         case SR_CONF_SAMPLERATE:
253                                 samplerate = g_variant_get_uint64(src->data);
254                                 g_debug("cli: got samplerate %"PRIu64" Hz", samplerate);
255 #ifdef HAVE_SRD
256                                 if (opt_pds) {
257                                         if (srd_session_metadata_set(srd_sess, SRD_CONF_SAMPLERATE,
258                                                         g_variant_new_uint64(samplerate)) != SRD_OK) {
259                                                 g_critical("Failed to pass samplerate to decoder.");
260                                         }
261                                 }
262 #endif
263                                 break;
264                         case SR_CONF_SAMPLE_INTERVAL:
265                                 samplerate = g_variant_get_uint64(src->data);
266                                 g_debug("cli: got sample interval %"PRIu64" ms", samplerate);
267                                 break;
268                         default:
269                                 /* Unknown metadata is not an error. */
270                                 break;
271                         }
272                 }
273                 break;
274
275         case SR_DF_TRIGGER:
276                 g_debug("cli: received SR_DF_TRIGGER");
277                 if (o->format->event)
278                         o->format->event(o, SR_DF_TRIGGER, &output_buf,
279                                          &output_len);
280                 triggered = 1;
281                 break;
282
283         case SR_DF_LOGIC:
284                 logic = packet->payload;
285                 g_message("cli: received SR_DF_LOGIC, %"PRIu64" bytes", logic->length);
286                 sample_size = logic->unitsize;
287                 if (logic->length == 0)
288                         break;
289
290                 /* Don't store any samples until triggered. */
291                 if (opt_wait_trigger && !triggered)
292                         break;
293
294                 if (limit_samples && received_samples >= limit_samples)
295                         break;
296
297                 ret = sr_filter_probes(sample_size, unitsize, logic_probelist,
298                                 logic->data, logic->length,
299                                 &filter_out, &filter_out_len);
300                 if (ret != SR_OK)
301                         break;
302
303                 /*
304                  * What comes out of the filter is guaranteed to be packed into the
305                  * minimum size needed to support the number of samples at this sample
306                  * size. however, the driver may have submitted too much. Cut off
307                  * the buffer of the last packet according to the sample limit.
308                  */
309                 if (limit_samples && (received_samples + logic->length / sample_size >
310                                 limit_samples * sample_size))
311                         filter_out_len = limit_samples * sample_size - received_samples;
312
313                 if (opt_output_file && default_output_format) {
314                         /* Saving to a session file. */
315                         g_byte_array_append(savebuf, filter_out, filter_out_len);
316                 } else {
317                         if (opt_pds) {
318 #ifdef HAVE_SRD
319                                 end_sample = received_samples + filter_out_len / unitsize;
320                                 if (srd_session_send(srd_sess, received_samples, end_sample,
321                                                 (uint8_t*)filter_out, filter_out_len) != SRD_OK)
322                                         sr_session_stop();
323 #endif
324                         } else {
325                                 output_len = 0;
326                                 if (o->format->data && packet->type == o->format->df_type)
327                                         o->format->data(o, filter_out, filter_out_len,
328                                                         &output_buf, &output_len);
329                                 if (output_len) {
330                                         fwrite(output_buf, 1, output_len, outfile);
331                                         fflush(outfile);
332                                         g_free(output_buf);
333                                 }
334                         }
335                 }
336                 g_free(filter_out);
337
338                 received_samples += logic->length / sample_size;
339                 break;
340
341         case SR_DF_ANALOG:
342                 analog = packet->payload;
343                 g_message("cli: received SR_DF_ANALOG, %d samples", analog->num_samples);
344                 if (analog->num_samples == 0)
345                         break;
346
347                 if (limit_samples && received_samples >= limit_samples)
348                         break;
349
350                 if (o->format->data && packet->type == o->format->df_type) {
351                         o->format->data(o, (const uint8_t *)analog->data,
352                                         analog->num_samples * sizeof(float),
353                                         &output_buf, &output_len);
354                         if (output_buf) {
355                                 fwrite(output_buf, 1, output_len, outfile);
356                                 fflush(outfile);
357                                 g_free(output_buf);
358                         }
359                 }
360
361                 received_samples += analog->num_samples;
362                 break;
363
364         case SR_DF_FRAME_BEGIN:
365                 g_debug("cli: received SR_DF_FRAME_BEGIN");
366                 if (o->format->event) {
367                         o->format->event(o, SR_DF_FRAME_BEGIN, &output_buf,
368                                          &output_len);
369                         if (output_buf) {
370                                 fwrite(output_buf, 1, output_len, outfile);
371                                 fflush(outfile);
372                                 g_free(output_buf);
373                         }
374                 }
375                 break;
376
377         case SR_DF_FRAME_END:
378                 g_debug("cli: received SR_DF_FRAME_END");
379                 if (o->format->event) {
380                         o->format->event(o, SR_DF_FRAME_END, &output_buf,
381                                          &output_len);
382                         if (output_buf) {
383                                 fwrite(output_buf, 1, output_len, outfile);
384                                 fflush(outfile);
385                                 g_free(output_buf);
386                         }
387                 }
388                 break;
389
390         default:
391                 break;
392         }
393
394         if (o && o->format->receive) {
395                 if (o->format->receive(o, sdi, packet, &out) == SR_OK && out) {
396                         fwrite(out->str, 1, out->len, outfile);
397                         fflush(outfile);
398                         g_string_free(out, TRUE);
399                 }
400         }
401
402         /* SR_DF_END needs to be handled after the output module's receive()
403          * is called, so it can properly clean up that module etc. */
404         if (packet->type == SR_DF_END) {
405                 g_debug("cli: Received SR_DF_END");
406
407                 if (o->format->event) {
408                         o->format->event(o, SR_DF_END, &output_buf, &output_len);
409                         if (output_buf) {
410                                 if (outfile)
411                                         fwrite(output_buf, 1, output_len, outfile);
412                                 g_free(output_buf);
413                                 output_len = 0;
414                         }
415                 }
416
417                 if (limit_samples && received_samples < limit_samples)
418                         g_warning("Device only sent %" PRIu64 " samples.",
419                                received_samples);
420
421                 if (opt_continuous)
422                         g_warning("Device stopped after %" PRIu64 " samples.",
423                                received_samples);
424
425                 g_array_free(logic_probelist, TRUE);
426
427                 if (o->format->cleanup)
428                         o->format->cleanup(o);
429                 g_free(o);
430                 o = NULL;
431
432                 if (outfile && outfile != stdout)
433                         fclose(outfile);
434
435                 if (opt_output_file && default_output_format && savebuf->len) {
436                         if (sr_session_save(opt_output_file, sdi, savebuf->data,
437                                         unitsize, savebuf->len / unitsize) != SR_OK)
438                                 g_critical("Failed to save session.");
439                         g_byte_array_free(savebuf, TRUE);
440                 }
441         }
442
443 }
444
445 int opt_to_gvar(char *key, char *value, struct sr_config *src)
446 {
447         const struct sr_config_info *srci;
448         double tmp_double;
449         uint64_t tmp_u64, p, q, low, high;
450         GVariant *rational[2], *range[2];
451         gboolean tmp_bool;
452         int ret;
453
454         if (!(srci = sr_config_info_name_get(key))) {
455                 g_critical("Unknown device option '%s'.", (char *) key);
456                 return -1;
457         }
458         src->key = srci->key;
459
460         if ((value == NULL) &&
461                 (srci->datatype != SR_T_BOOL)) {
462                 g_critical("Option '%s' needs a value.", (char *)key);
463                 return -1;
464         }
465
466         ret = 0;
467         switch (srci->datatype) {
468         case SR_T_UINT64:
469                 ret = sr_parse_sizestring(value, &tmp_u64);
470                 if (ret != 0)
471                         break;
472                 src->data = g_variant_new_uint64(tmp_u64);
473                 break;
474         case SR_T_INT32:
475                 ret = sr_parse_sizestring(value, &tmp_u64);
476                 if (ret != 0)
477                         break;
478                 src->data = g_variant_new_int32(tmp_u64);
479                 break;
480         case SR_T_CHAR:
481                 src->data = g_variant_new_string(value);
482                 break;
483         case SR_T_BOOL:
484                 if (!value)
485                         tmp_bool = TRUE;
486                 else
487                         tmp_bool = sr_parse_boolstring(value);
488                 src->data = g_variant_new_boolean(tmp_bool);
489                 break;
490         case SR_T_FLOAT:
491                 tmp_double = strtof(value, NULL);
492                 src->data = g_variant_new_double(tmp_double);
493                 break;
494         case SR_T_RATIONAL_PERIOD:
495                 if ((ret = sr_parse_period(value, &p, &q)) != SR_OK)
496                         break;
497                 rational[0] = g_variant_new_uint64(p);
498                 rational[1] = g_variant_new_uint64(q);
499                 src->data = g_variant_new_tuple(rational, 2);
500                 break;
501         case SR_T_RATIONAL_VOLT:
502                 if ((ret = sr_parse_voltage(value, &p, &q)) != SR_OK)
503                         break;
504                 rational[0] = g_variant_new_uint64(p);
505                 rational[1] = g_variant_new_uint64(q);
506                 src->data = g_variant_new_tuple(rational, 2);
507                 break;
508         case SR_T_UINT64_RANGE:
509                 if (sscanf(value, "%"PRIu64"-%"PRIu64, &low, &high) != 2) {
510                         ret = -1;
511                         break;
512                 } else {
513                         range[0] = g_variant_new_uint64(low);
514                         range[1] = g_variant_new_uint64(high);
515                         src->data = g_variant_new_tuple(range, 2);
516                 }
517                 break;
518         default:
519                 ret = -1;
520         }
521
522         return ret;
523 }
524
525 int set_dev_options(struct sr_dev_inst *sdi, GHashTable *args)
526 {
527         struct sr_config src;
528         struct sr_probe_group *pg;
529         GHashTableIter iter;
530         gpointer key, value;
531         int ret;
532
533         g_hash_table_iter_init(&iter, args);
534         while (g_hash_table_iter_next(&iter, &key, &value)) {
535                 if ((ret = opt_to_gvar(key, value, &src)) != 0)
536                         return ret;
537                 pg = select_probe_group(sdi);
538                 ret = sr_config_set(sdi, pg, src.key, src.data);
539                 if (ret != SR_OK) {
540                         g_critical("Failed to set device option '%s'.", (char *)key);
541                         return ret;
542                 }
543         }
544
545         return SR_OK;
546 }
547
548 void run_session(void)
549 {
550         GSList *devices;
551         GHashTable *devargs;
552         GVariant *gvar;
553         struct sr_dev_inst *sdi;
554         uint64_t max_samples;
555         int max_probes, i;
556         char **triggerlist;
557
558         devices = device_scan();
559         if (!devices) {
560                 g_critical("No devices found.");
561                 return;
562         }
563         if (g_slist_length(devices) > 1) {
564                 g_critical("sigrok-cli only supports one device for capturing.");
565                 return;
566         }
567         sdi = devices->data;
568
569         sr_session_new();
570         sr_session_datafeed_callback_add(datafeed_in, NULL);
571
572         if (sr_dev_open(sdi) != SR_OK) {
573                 g_critical("Failed to open device.");
574                 return;
575         }
576
577         if (sr_session_dev_add(sdi) != SR_OK) {
578                 g_critical("Failed to add device to session.");
579                 sr_session_destroy();
580                 return;
581         }
582
583         if (opt_config) {
584                 if ((devargs = parse_generic_arg(opt_config, FALSE))) {
585                         if (set_dev_options(sdi, devargs) != SR_OK)
586                                 return;
587                         g_hash_table_destroy(devargs);
588                 }
589         }
590
591         if (select_probes(sdi) != SR_OK) {
592                 g_critical("Failed to set probes.");
593                 sr_session_destroy();
594                 return;
595         }
596
597         if (opt_triggers) {
598                 if (!(triggerlist = sr_parse_triggerstring(sdi, opt_triggers))) {
599                         sr_session_destroy();
600                         return;
601                 }
602                 max_probes = g_slist_length(sdi->probes);
603                 for (i = 0; i < max_probes; i++) {
604                         if (triggerlist[i]) {
605                                 sr_dev_trigger_set(sdi, i, triggerlist[i]);
606                                 g_free(triggerlist[i]);
607                         }
608                 }
609                 g_free(triggerlist);
610         }
611
612         if (opt_continuous) {
613                 if (!sr_dev_has_option(sdi, SR_CONF_CONTINUOUS)) {
614                         g_critical("This device does not support continuous sampling.");
615                         sr_session_destroy();
616                         return;
617                 }
618         }
619
620         if (opt_time) {
621                 if (set_limit_time(sdi) != SR_OK) {
622                         sr_session_destroy();
623                         return;
624                 }
625         }
626
627         if (opt_samples) {
628                 if ((sr_parse_sizestring(opt_samples, &limit_samples) != SR_OK)) {
629                         g_critical("Invalid sample limit '%s'.", opt_samples);
630                         sr_session_destroy();
631                         return;
632                 }
633                 if (sr_config_get(sdi->driver, sdi, NULL,
634                                 SR_CONF_MAX_UNCOMPRESSED_SAMPLES, &gvar) == SR_OK) {
635                         /* The device has no compression, or compression is turned
636                          * off, and publishes its sample memory size. */
637                         max_samples = g_variant_get_uint64(gvar);
638                         g_variant_unref(gvar);
639                         if (limit_samples > max_samples) {
640                                 g_critical("The device can store only %"PRIu64
641                                                 " samples with the current settings.", max_samples);
642                         }
643                 }
644                 gvar = g_variant_new_uint64(limit_samples);
645                 if (sr_config_set(sdi, NULL, SR_CONF_LIMIT_SAMPLES, gvar) != SR_OK) {
646                         g_critical("Failed to configure sample limit.");
647                         sr_session_destroy();
648                         return;
649                 }
650         }
651
652         if (opt_frames) {
653                 if ((sr_parse_sizestring(opt_frames, &limit_frames) != SR_OK)) {
654                         g_critical("Invalid sample limit '%s'.", opt_samples);
655                         sr_session_destroy();
656                         return;
657                 }
658                 gvar = g_variant_new_uint64(limit_frames);
659                 if (sr_config_set(sdi, NULL, SR_CONF_LIMIT_FRAMES, gvar) != SR_OK) {
660                         g_critical("Failed to configure frame limit.");
661                         sr_session_destroy();
662                         return;
663                 }
664         }
665
666         if (sr_session_start() != SR_OK) {
667                 g_critical("Failed to start session.");
668                 sr_session_destroy();
669                 return;
670         }
671
672         if (opt_continuous)
673                 add_anykey();
674
675         sr_session_run();
676
677         if (opt_continuous)
678                 clear_anykey();
679
680         sr_session_datafeed_callback_remove_all();
681         sr_session_destroy();
682         g_slist_free(devices);
683
684 }
685