]> sigrok.org Git - sigrok-test.git/blob - decoder/runtc.c
avr_isp: add test for ATmega328/P
[sigrok-test.git] / decoder / runtc.c
1 /*
2  * This file is part of the sigrok-test 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 <config.h>
21
22 #include <Python.h>
23 #include <libsigrokdecode/libsigrokdecode.h>
24 #include <libsigrok/libsigrok.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <time.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #include <dirent.h>
37 #include <glib.h>
38 #ifdef __LINUX__
39 #include <sched.h>
40 #endif
41
42 #define CHUNK_SIZE      (4 * 1024 * 1024)
43
44 static int debug = FALSE;
45 static int statistics = FALSE;
46 static char *coverage_report;
47 static struct sr_context *ctx;
48
49 struct channel {
50         char *name;
51         int channel;
52 };
53
54 struct option {
55         char *key;
56         GVariant *value;
57 };
58
59 struct initial_pin_info {
60         char *name;
61         int value;
62 };
63
64 struct pd {
65         const char *name;
66         GSList *channels;
67         GSList *options;
68         GSList *initial_pins;
69 };
70
71 struct input {
72         const char *filename;
73         const char *format;
74         GSList *opt_list;
75         GHashTable *opt_hash;
76 };
77
78 struct output {
79         const char *pd;
80         const char *pd_id;
81         int type;
82         const char *class_;
83         int class_idx;
84         const char *outfile;
85         int outfd;
86 };
87
88 struct cvg {
89         int num_lines;
90         int num_missed;
91         float coverage;
92         GSList *missed_lines;
93 };
94
95 static struct cvg *get_mod_cov(PyObject *py_cov, const char *module_name);
96 static void cvg_add(struct cvg *dst, const struct cvg *src);
97 static struct cvg *cvg_new(void);
98 static gboolean find_missed_line(struct cvg *cvg, const char *linespec);
99
100 static void logmsg(const char *prefix, FILE *out, const char *format, va_list args)
101 {
102         if (prefix)
103                 fprintf(out, "%s", prefix);
104         vfprintf(out, format, args);
105         fprintf(out, "\n");
106 }
107
108 static void DBG(const char *format, ...)
109 {
110         va_list args;
111
112         if (!debug)
113                 return;
114         va_start(args, format);
115         logmsg("DBG: runtc: ", stdout, format, args);
116         va_end(args);
117 }
118
119 static void ERR(const char *format, ...)
120 {
121         va_list args;
122
123         va_start(args, format);
124         logmsg("Error: ", stderr, format, args);
125         va_end(args);
126 }
127
128 static int sr_log(void *cb_data, int loglevel, const char *format, va_list args)
129 {
130         (void)cb_data;
131
132         if (loglevel == SR_LOG_ERR || loglevel == SR_LOG_WARN)
133                 logmsg("Error: sr: ", stderr, format, args);
134         else if (debug)
135                 logmsg("DBG: sr: ", stdout, format, args);
136
137         return SRD_OK;
138 }
139
140 static int srd_log(void *cb_data, int loglevel, const char *format, va_list args)
141 {
142         (void)cb_data;
143
144         if (loglevel == SRD_LOG_ERR || loglevel == SRD_LOG_WARN)
145                 logmsg("Error: srd: ", stderr, format, args);
146         else if (debug)
147                 logmsg("DBG: srd: ", stdout, format, args);
148
149         return SRD_OK;
150 }
151
152 static void usage(const char *msg)
153 {
154         if (msg)
155                 fprintf(stderr, "%s\n", msg);
156
157         printf("Usage: runtc [-dPpoiOfcS]\n");
158         printf("  -d  (enables debug output)\n");
159         printf("  -P <protocol decoder>\n");
160         printf("  -p <channelname=channelnum> (optional)\n");
161         printf("  -o <channeloption=value> (optional)\n");
162         printf("  -N <channelname=initial-pin-value> (optional)\n");
163         printf("  -i <input file>\n");
164         printf("  -I <input format> (optional)\n");
165         printf("  -O <output-pd:output-type[:output-class]>\n");
166         printf("  -f <output file> (optional)\n");
167         printf("  -c <coverage report> (optional)\n");
168         printf("  -S  (enables statistics)\n");
169         exit(msg ? 1 : 0);
170
171 }
172
173 /*
174  * This is a neutered version of libsigrokdecode's py_str_as_str(). It
175  * does no error checking, but then the only strings it processes are
176  * generated by Python's repr(), so are known good.
177  */
178 static char *py_str_as_str(const PyObject *py_str)
179 {
180         PyObject *py_encstr;
181         char *str, *outstr;
182
183         py_encstr = PyUnicode_AsEncodedString((PyObject *)py_str, "utf-8", NULL);
184         str = PyBytes_AS_STRING(py_encstr);
185         outstr = g_strdup(str);
186         Py_DecRef(py_encstr);
187
188         return outstr;
189 }
190
191 /*
192  * The following routines are callbacks for libsigrokdecode. They receive
193  * output from protocol decoders, optionally dropping data to only forward
194  * a selected decoder's or class' information. Output is written to either
195  * a specified file or stdout, an external process will compare captured
196  * output against expectations.
197  *
198  * Note that runtc(1) output emits the decoder "class" name instead of the
199  * instance name. So that generated output remains compatible with existing
200  * .output files which hold expected output of test cases. Without this
201  * approach, developers had to "anticipate" instance names from test.conf
202  * setups (and knowledge about internal implementation details of the srd
203  * library), and adjust .output files to reflect those names. Or specify
204  * instance names in each and every test.conf description (-o inst_id=ID).
205  *
206  * It's assumed that runtc(1) is used to check stacked decoders, but not
207  * multiple stacks in parallel and no stacks with multiple instances of
208  * decoders of the same type. When such configurations become desirable,
209  * runtc(1) needs to emit the instance name, and test configurations and
210  * output expectations need adjustment.
211  */
212
213 static void srd_cb_py(struct srd_proto_data *pdata, void *cb_data)
214 {
215         struct output *op;
216         PyObject *pydata, *pyrepr;
217         GString *out;
218         char *s;
219
220         DBG("Python output from %s", pdata->pdo->di->inst_id);
221         op = cb_data;
222         pydata = pdata->data;
223         DBG("ptr %p", pydata);
224
225         if (strcmp(pdata->pdo->di->inst_id, op->pd_id))
226                 /* This is not the PD selected for output. */
227                 return;
228
229         if (!(pyrepr = PyObject_Repr(pydata))) {
230                 ERR("Invalid Python object.");
231                 return;
232         }
233         s = py_str_as_str(pyrepr);
234         Py_DecRef(pyrepr);
235
236         /* Output format for testing is '<ss>-<es> <decoder-id>: <repr>\n'. */
237         out = g_string_sized_new(128);
238         g_string_printf(out, "%" PRIu64 "-%" PRIu64 " %s: %s\n",
239                         pdata->start_sample, pdata->end_sample,
240                         pdata->pdo->di->decoder->id, s);
241         g_free(s);
242         if (write(op->outfd, out->str, out->len) == -1)
243                 ERR("SRD_OUTPUT_PYTHON callback write failure!");
244         DBG("wrote '%s'", out->str);
245         g_string_free(out, TRUE);
246
247 }
248
249 static void srd_cb_bin(struct srd_proto_data *pdata, void *cb_data)
250 {
251         struct srd_proto_data_binary *pdb;
252         struct output *op;
253         GString *out;
254         unsigned int i;
255
256         DBG("Binary output from %s", pdata->pdo->di->inst_id);
257         op = cb_data;
258         pdb = pdata->data;
259
260         if (strcmp(pdata->pdo->di->inst_id, op->pd_id))
261                 /* This is not the PD selected for output. */
262                 return;
263
264         if (op->class_idx != -1 && op->class_idx != pdb->bin_class)
265                 /*
266                  * This output takes a specific binary class,
267                  * but not the one that just came in.
268                  */
269                 return;
270
271         out = g_string_sized_new(128);
272         g_string_printf(out, "%" PRIu64 "-%" PRIu64 " %s:",
273                         pdata->start_sample, pdata->end_sample,
274                         pdata->pdo->di->decoder->id);
275         for (i = 0; i < pdb->size; i++) {
276                 g_string_append_printf(out, " %.2x", pdb->data[i]);
277         }
278         g_string_append(out, "\n");
279         if (write(op->outfd, out->str, out->len) == -1)
280                 ERR("SRD_OUTPUT_BINARY callback write failure!");
281
282 }
283
284 static void srd_cb_ann(struct srd_proto_data *pdata, void *cb_data)
285 {
286         struct srd_decoder_inst *di;
287         struct srd_decoder *dec;
288         struct srd_proto_data_annotation *pda;
289         struct output *op;
290         GString *line;
291         int i;
292         char **dec_ann;
293
294         /*
295          * Only inspect received annotations when they originate from
296          * the selected protocol decoder, and an optionally specified
297          * annotation class matches the received data.
298          */
299         op = cb_data;
300         pda = pdata->data;
301         di = pdata->pdo->di;
302         dec = di->decoder;
303         DBG("Annotation output from %s", di->inst_id);
304         if (strcmp(di->inst_id, op->pd_id))
305                 /* This is not the PD selected for output. */
306                 return;
307
308         if (op->class_idx != -1 && op->class_idx != pda->ann_class)
309                 /*
310                  * This output takes a specific annotation class,
311                  * but not the one that just came in.
312                  */
313                 return;
314
315         /*
316          * Print the annotation information in textual representation
317          * to the specified output file. Prefix the annotation strings
318          * with the start and end sample number, the decoder name, and
319          * the annotation name.
320          */
321         dec_ann = g_slist_nth_data(dec->annotations, pda->ann_class);
322         line = g_string_sized_new(256);
323         g_string_printf(line, "%" PRIu64 "-%" PRIu64 " %s: %s:",
324                         pdata->start_sample, pdata->end_sample,
325                         dec->id, dec_ann[0]);
326         for (i = 0; pda->ann_text[i]; i++)
327                 g_string_append_printf(line, " \"%s\"", pda->ann_text[i]);
328         g_string_append(line, "\n");
329         if (write(op->outfd, line->str, line->len) == -1)
330                 ERR("SRD_OUTPUT_ANN callback write failure!");
331         g_string_free(line, TRUE);
332
333 }
334
335 static void sr_cb(const struct sr_dev_inst *sdi,
336                 const struct sr_datafeed_packet *packet, void *cb_data)
337 {
338         static int samplecnt = 0;
339         static gboolean start_sent;
340
341         const struct sr_datafeed_logic *logic;
342         struct srd_session *sess;
343         const struct sr_datafeed_meta *meta;
344         struct sr_config *src;
345         GSList *l;
346         GVariant *gvar;
347         uint64_t samplerate;
348         int ret;
349         int num_samples;
350         struct sr_dev_driver *driver;
351
352         sess = cb_data;
353
354         driver = sr_dev_inst_driver_get(sdi);
355
356         switch (packet->type) {
357         case SR_DF_META:
358                 DBG("Received SR_DF_META");
359                 meta = packet->payload;
360                 for (l = meta->config; l; l = l->next) {
361                         src = l->data;
362                         switch (src->key) {
363                         case SR_CONF_SAMPLERATE:
364                                 samplerate = g_variant_get_uint64(src->data);
365                                 ret = srd_session_metadata_set(sess,
366                                         SRD_CONF_SAMPLERATE,
367                                         g_variant_new_uint64(samplerate));
368                                 if (ret != SRD_OK)
369                                         ERR("Setting samplerate failed (meta)");
370                                 break;
371                         default:
372                                 /* EMPTY */
373                                 break;
374                         }
375                 }
376                 break;
377         case SR_DF_HEADER:
378                 DBG("Received SR_DF_HEADER");
379                 if (sr_config_get(driver, sdi, NULL, SR_CONF_SAMPLERATE,
380                                 &gvar) != SR_OK) {
381                         DBG("Getting samplerate failed (SR_DF_HEADER)");
382                         break;
383                 }
384                 samplerate = g_variant_get_uint64(gvar);
385                 g_variant_unref(gvar);
386                 ret = srd_session_metadata_set(sess, SRD_CONF_SAMPLERATE,
387                         g_variant_new_uint64(samplerate));
388                 if (ret != SRD_OK)
389                         ERR("Setting samplerate failed (header)");
390                 break;
391         case SR_DF_LOGIC:
392                 DBG("Received SR_DF_LOGIC");
393                 if (!start_sent) {
394                         if (srd_session_start(sess) != SRD_OK) {
395                                 ERR("Session start failed");
396                                 break;
397                         }
398                         start_sent = TRUE;
399                 }
400                 logic = packet->payload;
401                 num_samples = logic->length / logic->unitsize;
402                 DBG("Received SR_DF_LOGIC (%"PRIu64" bytes, unitsize = %d).",
403                         logic->length, logic->unitsize);
404                 srd_session_send(sess, samplecnt, samplecnt + num_samples,
405                                 logic->data, logic->length, logic->unitsize);
406                 samplecnt += num_samples;
407                 break;
408         case SR_DF_END:
409                 DBG("Received SR_DF_END");
410 #if defined HAVE_SRD_SESSION_SEND_EOF && HAVE_SRD_SESSION_SEND_EOF
411                 (void)srd_session_send_eof(sess);
412 #endif
413                 break;
414         }
415
416 }
417
418 static GHashTable *parse_input_options(const struct sr_option **pd_opts,
419         GSList *user_specs)
420 {
421         GHashTable *set_opts;
422         GVariant *pd_def, *gvar;
423         size_t idx;
424         GSList *l;
425         const char *pd_key;
426         const char *spec_text, *s;
427
428         set_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
429                 (GDestroyNotify)g_variant_unref);
430         for (idx = 0; pd_opts[idx]; idx++) {
431                 pd_key = pd_opts[idx]->id;
432                 /* Is the PD provided option in the set of input specs? */
433                 s = NULL;
434                 for (l = user_specs; l; l = l->next) {
435                         spec_text = l->data;
436                         if (strncmp(spec_text, pd_key, strlen(pd_key)) != 0)
437                                 continue;
438                         spec_text += strlen(pd_key);
439                         if (!*spec_text) {
440                                 /* Found 'key' up to end of text. */
441                                 s = spec_text;
442                                 break;
443                         }
444                         if (*spec_text == '=') {
445                                 /* Found 'key=...', position to RHS value. */
446                                 s = ++spec_text;
447                                 break;
448                         }
449                 }
450                 if (!s)
451                         continue;
452                 /*
453                  * Normalize the input text for the user specified value.
454                  * A key without an explicit value is useful for booleans.
455                  */
456                 if (!*s)
457                         s = "";
458                 /*
459                  * Convert the text to the PD default value's data type.
460                  * Store the resulting variable in the hash which gets
461                  * passed to the input module.
462                  */
463                 pd_def = pd_opts[idx]->def;
464                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_UINT32)) {
465                         gvar = g_variant_new_uint32(strtoul(s, NULL, 10));
466                         g_hash_table_insert(set_opts, g_strdup(pd_key),
467                                 g_variant_ref_sink(gvar));
468                         continue;
469                 }
470                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_INT32)) {
471                         gvar = g_variant_new_int32(strtol(s, NULL, 10));
472                         g_hash_table_insert(set_opts, g_strdup(pd_key),
473                                 g_variant_ref_sink(gvar));
474                         continue;
475                 }
476                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_UINT64)) {
477                         gvar = g_variant_new_uint64(strtoull(s, NULL, 10));
478                         g_hash_table_insert(set_opts, g_strdup(pd_key),
479                                 g_variant_ref_sink(gvar));
480                         continue;
481                 }
482                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_DOUBLE)) {
483                         gvar = g_variant_new_double(strtod(s, NULL));
484                         g_hash_table_insert(set_opts, g_strdup(pd_key),
485                                 g_variant_ref_sink(gvar));
486                         continue;
487                 }
488                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_STRING)) {
489                         gvar = g_variant_new_string(s);
490                         g_hash_table_insert(set_opts, g_strdup(pd_key),
491                                 g_variant_ref_sink(gvar));
492                         continue;
493                 }
494                 if (g_variant_is_of_type(pd_def, G_VARIANT_TYPE_BOOLEAN)) {
495                         gboolean b;
496                         if (strcmp(s, "false") == 0 || strcmp(s, "no") == 0) {
497                                 b = FALSE;
498                         } else if (strcmp(s, "true") == 0 || strcmp(s, "yes") == 0) {
499                                 b = TRUE;
500                         } else {
501                                 ERR("Cannot convert '%s' to boolean", s);
502                                 return NULL;
503                         }
504                         gvar = g_variant_new_boolean(b);
505                         g_hash_table_insert(set_opts, g_strdup(pd_key),
506                                 g_variant_ref_sink(gvar));
507                         continue;
508                 }
509                 ERR("Unsupported data type for option '%s'", pd_key);
510                 return NULL;
511         }
512
513         return set_opts;
514 }
515
516 static int run_testcase(struct input *inp, GSList *pdlist, struct output *op)
517 {
518         struct srd_session *sess;
519         struct srd_decoder *dec;
520         struct srd_decoder_inst *di, *prev_di;
521         srd_pd_output_callback cb;
522         struct pd *pd;
523         struct channel *channel;
524         struct option *option;
525         GVariant *gvar;
526         GHashTable *channels, *opts;
527         GSList *pdl, *l, *l2, *devices;
528         int ret, idx, i;
529         int max_channel;
530         char **decoder_class;
531         struct sr_session *sr_sess;
532         const struct sr_input *in;
533         const struct sr_input_module *imod;
534         const struct sr_option **options;
535         GHashTable *mod_opts;
536         gboolean is_number;
537         const char *s;
538         GArray *initial_pins;
539         struct initial_pin_info *initial_pin;
540
541         if (op->outfile) {
542                 if ((op->outfd = open(op->outfile, O_CREAT|O_WRONLY, 0600)) == -1) {
543                         ERR("Unable to open %s for writing: %s", op->outfile,
544                                         g_strerror(errno));
545                         return FALSE;
546                 }
547         }
548
549         /* Tell "session files" (.sr format) from other input modules. */
550         sr_sess = NULL;
551         in = NULL;
552         if (inp->format && strcmp(inp->format, "match") == 0) {
553                 /* Automatic format detection. */
554                 if (inp->opt_list) {
555                         ERR("Automatic file format won't take options");
556                         return FALSE;
557                 }
558                 ret = sr_input_scan_file(inp->filename, &in);
559                 if (ret != SR_OK || !in) {
560                         ERR("Cannot open input file (format match)");
561                         return FALSE;
562                 }
563                 sr_session_new(ctx, &sr_sess);
564                 ret = SR_OK;
565         } else if (inp->format) {
566                 /* Caller specified format, potentially with options. */
567                 imod = sr_input_find(inp->format);
568                 if (!imod) {
569                         ERR("Cannot find specified input module");
570                         return FALSE;
571                 }
572                 mod_opts = NULL;
573                 options = sr_input_options_get(imod);
574                 if (!options && inp->opt_list) {
575                         ERR("Input module does not support options");
576                         return FALSE;
577                 }
578                 if (inp->opt_list) {
579                         mod_opts = parse_input_options(options, inp->opt_list);
580                         if (!mod_opts) {
581                                 ERR("Cannot process input module options");
582                                 return FALSE;
583                         }
584                 }
585                 sr_input_options_free(options);
586                 in = sr_input_new(imod, mod_opts);
587                 if (!in) {
588                         ERR("Cannot create input module instance");
589                         return FALSE;
590                 }
591                 if (mod_opts)
592                         g_hash_table_destroy(mod_opts);
593                 sr_session_new(ctx, &sr_sess);
594                 ret = SR_OK;
595         } else {
596                 /* No caller's format spec, assume .sr session file. */
597                 ret = sr_session_load(ctx, inp->filename, &sr_sess);
598                 if (ret != SR_OK || !sr_sess) {
599                         ERR("Cannot open session file");
600                         return FALSE;
601                 }
602         }
603         if (ret != SR_OK || !sr_sess) {
604                 ERR("Failed to open input file");
605                 return FALSE;
606         }
607         if (in) {
608                 /* Check file access early for non-session files. */
609                 int fd;
610                 fd = open(inp->filename, O_RDONLY);
611                 if (fd < 0) {
612                         ERR("Cannot access input file (input module)");
613                         return FALSE;
614                 }
615                 close(fd);
616         }
617
618         sr_session_dev_list(sr_sess, &devices);
619
620         if (srd_session_new(&sess) != SRD_OK) {
621                 ERR("srd_session_new() failed");
622                 return FALSE;
623         }
624         sr_session_datafeed_callback_add(sr_sess, sr_cb, sess);
625         switch (op->type) {
626         case SRD_OUTPUT_ANN:
627                 cb = srd_cb_ann;
628                 break;
629         case SRD_OUTPUT_BINARY:
630                 cb = srd_cb_bin;
631                 break;
632         case SRD_OUTPUT_PYTHON:
633                 cb = srd_cb_py;
634                 break;
635         default:
636                 ERR("Invalid op->type");
637                 return FALSE;
638         }
639         srd_pd_output_callback_add(sess, op->type, cb, op);
640
641         prev_di = NULL;
642         pd = NULL;
643         for (pdl = pdlist; pdl; pdl = pdl->next) {
644                 pd = pdl->data;
645                 if (srd_decoder_load(pd->name) != SRD_OK) {
646                         ERR("srd_decoder_load() failed");
647                         return FALSE;
648                 }
649
650                 /* Instantiate decoder and pass in options. */
651                 opts = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
652                                 (GDestroyNotify)g_variant_unref);
653                 for (l = pd->options; l; l = l->next) {
654                         option = l->data;
655
656                         is_number = TRUE;
657                         s = g_variant_get_string(option->value, NULL);
658                         for (i = 0; i < (int)strlen(s); i++) {
659                                 if (!isdigit(s[i]))
660                                         is_number = FALSE;
661                         }
662
663                         if (is_number) {
664                                 /* Integer option value */
665                                 g_hash_table_insert(opts, option->key,
666                                   g_variant_new_int64(strtoull(s, NULL, 10)));
667                         } else {
668                                 /* String option value */
669                                 g_hash_table_insert(opts, option->key, option->value);
670                         }
671                 }
672                 if (!(di = srd_inst_new(sess, pd->name, opts))) {
673                         ERR("srd_inst_new() failed");
674                         return FALSE;
675                 }
676                 g_hash_table_destroy(opts);
677
678                 /*
679                  * Get (a reference to) the decoder instance's ID if we
680                  * are about to receive PD output from it. We need to
681                  * filter output that carries the decoder instance's name.
682                  */
683                 if (strcmp(pd->name, op->pd) == 0) {
684                         op->pd_id = di->inst_id;
685                         DBG("Decoder of type \"%s\" has instance ID \"%s\".",
686                             op->pd, op->pd_id);
687                 }
688
689                 /* Map channels. */
690                 if (pd->channels) {
691                         channels = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
692                                         (GDestroyNotify)g_variant_unref);
693                         max_channel = 0;
694                         for (l = pd->channels; l; l = l->next) {
695                                 channel = l->data;
696                                 if (channel->channel > max_channel)
697                                         max_channel = channel->channel;
698                                 gvar = g_variant_new_int32(channel->channel);
699                                 g_variant_ref_sink(gvar);
700                                 g_hash_table_insert(channels, channel->name, gvar);
701                         }
702
703                         if (srd_inst_channel_set_all(di, channels) != SRD_OK) {
704                                 ERR("srd_inst_channel_set_all() failed");
705                                 return FALSE;
706                         }
707                         g_hash_table_destroy(channels);
708                 }
709
710                 /* Set initial pins. */
711                 if (pd->initial_pins) {
712                         initial_pins = g_array_sized_new(FALSE, TRUE, sizeof(uint8_t),
713                                                 di->dec_num_channels);
714                         g_array_set_size(initial_pins, di->dec_num_channels);
715                         memset(initial_pins->data, SRD_INITIAL_PIN_SAME_AS_SAMPLE0,
716                                 di->dec_num_channels);
717
718                         for (l = pd->channels, idx = 0; l; l = l->next, idx++) {
719                                 channel = l->data;
720                                 for (l2 = pd->initial_pins; l2; l2 = l2->next) {
721                                         initial_pin = l2->data;
722                                         if (!strcmp(initial_pin->name, channel->name))
723                                                 initial_pins->data[idx] = initial_pin->value;
724                                 }
725                         }
726
727                         if (srd_inst_initial_pins_set_all(di, initial_pins) != SRD_OK) {
728                                 ERR("srd_inst_initial_pins_set_all() failed");
729                                 return FALSE;
730                         }
731                         g_array_free(initial_pins, TRUE);
732                 }
733
734                 /*
735                  * If this is not the first decoder in the list, stack it
736                  * on top of the previous one.
737                  */
738                 if (prev_di) {
739                         if (srd_inst_stack(sess, prev_di, di) != SRD_OK) {
740                                 ERR("Failed to stack decoder instances.");
741                                 return FALSE;
742                         }
743                 }
744                 prev_di = di;
745         }
746         /*
747          * Bail out if we haven't created an instance of the selected
748          * decoder type of which we shall grab output data from.
749          */
750         if (!op->pd_id) {
751                 ERR("No / invalid decoder");
752                 return FALSE;
753         }
754
755         /* Resolve selected decoder's class index, so we can match. */
756         dec = srd_decoder_get_by_id(pd->name);
757         if (op->class_) {
758                 if (op->type == SRD_OUTPUT_ANN)
759                         l = dec->annotations;
760                 else if (op->type == SRD_OUTPUT_BINARY)
761                         l = dec->binary;
762                 else {
763                         /* Only annotations and binary can have a class. */
764                         ERR("Invalid decoder class");
765                         return FALSE;
766                 }
767                 idx = 0;
768                 while (l) {
769                         decoder_class = l->data;
770                         if (!strcmp(decoder_class[0], op->class_)) {
771                                 op->class_idx = idx;
772                                 break;
773                         }
774                         idx++;
775                         l = l->next;
776                 }
777                 if (op->class_idx == -1) {
778                         ERR("Output class '%s' not found in decoder %s.",
779                                         op->class_, pd->name);
780                         return FALSE;
781                 }
782                 DBG("Class %s index is %d", op->class_, op->class_idx);
783         }
784
785         /*
786          * Run a convenience sequence for session files. Run a custom
787          * read loop for non-native file formats (import modules).
788          *
789          * TODO Ideally the libsigrok library would provide transparent
790          * access to either kind of file. Either wrap an input module
791          * similar to "session files", or turn the currently "special"
792          * session file into a regular input module. It's unfortunate
793          * that multiple applications need to re-invent this logic.
794          */
795         if (!in) {
796                 sr_session_start(sr_sess);
797                 sr_session_run(sr_sess);
798                 sr_session_stop(sr_sess);
799         } else if (in) {
800                 int fd;
801                 GString *buf;
802                 gboolean got_sdi;
803                 struct sr_dev_inst *sdi;
804                 ssize_t len;
805
806                 fd = open(inp->filename, O_RDONLY);
807                 if (fd < 0) {
808                         ERR("Cannot open input file (read loop)");
809                         return FALSE;
810                 }
811                 buf = g_string_sized_new(CHUNK_SIZE);
812                 got_sdi = FALSE;
813                 while (TRUE) {
814                         g_string_truncate(buf, 0);
815                         len = read(fd, buf->str, buf->allocated_len);
816                         if (len < 0) {
817                                 ERR("Cannot read from input file (read loop)");
818                                 return FALSE;
819                         }
820                         if (len == 0)
821                                 break;
822                         buf->len = len;
823                         ret = sr_input_send(in, buf);
824                         if (ret != SR_OK) {
825                                 ERR("Cannot process input file content");
826                                 break;
827                         }
828
829                         sdi = sr_input_dev_inst_get(in);
830                         if (!got_sdi && sdi) {
831                                 /* First time we got a valid sdi. */
832                                 if (sr_session_dev_add(sr_sess, sdi) != SR_OK) {
833                                         ERR("Cannot use device after sdi creation");
834                                         break;
835                                 }
836                                 got_sdi = TRUE;
837                         }
838                 }
839                 sr_input_end(in);
840                 sr_input_free(in);
841                 g_string_free(buf, TRUE);
842                 close(fd);
843                 sr_session_destroy(sr_sess);
844         }
845
846         srd_session_destroy(sess);
847
848         if (op->outfile)
849                 close(op->outfd);
850
851         return TRUE;
852 }
853
854 static PyObject *start_coverage(GSList *pdlist)
855 {
856         PyObject *py_mod, *py_pdlist, *py_pd, *py_func, *py_args, *py_kwargs, *py_cov;
857         GSList *l;
858         struct pd *pd;
859
860         DBG("Starting coverage.");
861
862         if (!(py_mod = PyImport_ImportModule("coverage")))
863                 return NULL;
864
865         if (!(py_pdlist = PyList_New(0)))
866                 return NULL;
867         for (l = pdlist; l; l = l->next) {
868                 pd = l->data;
869                 py_pd = PyUnicode_FromFormat("*/%s/*.py", pd->name);
870                 if (PyList_Append(py_pdlist, py_pd) < 0)
871                         return NULL;
872                 Py_DecRef(py_pd);
873         }
874         if (!(py_func = PyObject_GetAttrString(py_mod, "coverage")))
875                 return NULL;
876         if (!(py_args = PyTuple_New(0)))
877                 return NULL;
878         if (!(py_kwargs = Py_BuildValue("{sO}", "include", py_pdlist)))
879                 return NULL;
880         if (!(py_cov = PyObject_Call(py_func, py_args, py_kwargs)))
881                 return NULL;
882         if (!(PyObject_CallMethod(py_cov, "start", NULL)))
883                 return NULL;
884         Py_DecRef(py_pdlist);
885         Py_DecRef(py_args);
886         Py_DecRef(py_kwargs);
887         Py_DecRef(py_func);
888
889         return py_cov;
890 }
891
892 static struct cvg *get_mod_cov(PyObject *py_cov, const char *module_name)
893 {
894         PyObject *py_mod, *py_pathlist, *py_path, *py_func, *py_pd;
895         PyObject *py_result, *py_missed, *py_item;
896         DIR *d;
897         struct dirent *de;
898         struct cvg *cvg_mod;
899         int num_lines, num_missed, linenum, i, j;
900         char *path, *linespec;
901
902         if (!(py_mod = PyImport_ImportModule(module_name)))
903                 return NULL;
904
905         cvg_mod = NULL;
906         py_pathlist = PyObject_GetAttrString(py_mod, "__path__");
907         for (i = 0; i < PyList_Size(py_pathlist); i++) {
908                 py_path = PyList_GetItem(py_pathlist, i);
909                 PyUnicode_FSConverter(PyList_GetItem(py_pathlist, i), &py_path);
910                 path = PyBytes_AS_STRING(py_path);
911                 if (!(d = opendir(path))) {
912                         ERR("Invalid module path '%s'", path);
913                         return NULL;
914                 }
915                 while ((de = readdir(d))) {
916                         if (strncmp(de->d_name + strlen(de->d_name) - 3, ".py", 3))
917                                 continue;
918
919                         if (!(py_func = PyObject_GetAttrString(py_cov, "analysis2")))
920                                 return NULL;
921                         if (!(py_pd = PyUnicode_FromFormat("%s/%s", path, de->d_name)))
922                                 return NULL;
923                         if (!(py_result = PyObject_CallFunction(py_func, "O", py_pd)))
924                                 return NULL;
925                         Py_DecRef(py_pd);
926                         Py_DecRef(py_func);
927
928                         if (!cvg_mod)
929                                 cvg_mod = cvg_new();
930                         if (PyTuple_Size(py_result) != 5) {
931                                 ERR("Invalid result from coverage of '%s/%s'", path, de->d_name);
932                                 return NULL;
933                         }
934                         num_lines = PyList_Size(PyTuple_GetItem(py_result, 1));
935                         py_missed = PyTuple_GetItem(py_result, 3);
936                         num_missed = PyList_Size(py_missed);
937                         cvg_mod->num_lines += num_lines;
938                         cvg_mod->num_missed += num_missed;
939                         for (j = 0; j < num_missed; j++) {
940                                 py_item = PyList_GetItem(py_missed, j);
941                                 linenum = PyLong_AsLong(py_item);
942                                 linespec = g_strdup_printf("%s/%s:%d", module_name,
943                                                 de->d_name, linenum);
944                                 cvg_mod->missed_lines = g_slist_append(cvg_mod->missed_lines, linespec);
945                         }
946                         DBG("Coverage for %s/%s: %d lines, %d missed.",
947                                         module_name, de->d_name, num_lines, num_missed);
948                         Py_DecRef(py_result);
949                 }
950         }
951         if (cvg_mod->num_lines)
952                 cvg_mod->coverage = 100 - ((float)cvg_mod->num_missed / (float)cvg_mod->num_lines * 100);
953
954         Py_DecRef(py_mod);
955         Py_DecRef(py_path);
956
957         return cvg_mod;
958 }
959
960 static struct cvg *cvg_new(void)
961 {
962         struct cvg *cvg;
963
964         cvg = calloc(1, sizeof(struct cvg));
965
966         return cvg;
967 }
968
969 static gboolean find_missed_line(struct cvg *cvg, const char *linespec)
970 {
971         GSList *l;
972
973         for (l = cvg->missed_lines; l; l = l->next)
974                 if (!strcmp(l->data, linespec))
975                         return TRUE;
976
977         return FALSE;
978 }
979
980 static void cvg_add(struct cvg *dst, const struct cvg *src)
981 {
982         GSList *l;
983         char *linespec;
984
985         dst->num_lines += src->num_lines;
986         dst->num_missed += src->num_missed;
987         for (l = src->missed_lines; l; l = l->next) {
988                 linespec = l->data;
989                 if (!find_missed_line(dst, linespec))
990                         dst->missed_lines = g_slist_append(dst->missed_lines, linespec);
991         }
992
993 }
994
995 static int report_coverage(PyObject *py_cov, GSList *pdlist)
996 {
997         PyObject *py_func, *py_mod, *py_args, *py_kwargs, *py_outfile, *py_pct;
998         GSList *l, *ml;
999         struct pd *pd;
1000         struct cvg *cvg_mod, *cvg_all;
1001         float total_coverage;
1002         int lines, missed, cnt;
1003
1004         DBG("Making coverage report.");
1005
1006         /* Get coverage for each module in the stack. */
1007         lines = missed = 0;
1008         cvg_all = cvg_new();
1009         for (cnt = 0, l = pdlist; l; l = l->next, cnt++) {
1010                 pd = l->data;
1011                 if (!(cvg_mod = get_mod_cov(py_cov, pd->name)))
1012                         return FALSE;
1013                 printf("coverage: scope=%s coverage=%.0f%% lines=%d missed=%d "
1014                                 "missed_lines=", pd->name, cvg_mod->coverage,
1015                                 cvg_mod->num_lines, cvg_mod->num_missed);
1016                 for (ml = cvg_mod->missed_lines; ml; ml = ml->next) {
1017                         if (ml != cvg_mod->missed_lines)
1018                                 printf(",");
1019                         printf("%s", (char *)ml->data);
1020                 }
1021                 printf("\n");
1022                 lines += cvg_mod->num_lines;
1023                 missed += cvg_mod->num_missed;
1024                 cvg_add(cvg_all, cvg_mod);
1025                 DBG("Coverage for module %s: %d lines, %d missed", pd->name,
1026                                 cvg_mod->num_lines, cvg_mod->num_missed);
1027         }
1028         lines /= cnt;
1029         missed /= cnt;
1030         total_coverage = 100 - ((float)missed / (float)lines * 100);
1031
1032         /* Machine-readable stats on stdout. */
1033         printf("coverage: scope=all coverage=%.0f%% lines=%d missed=%d\n",
1034                         total_coverage, cvg_all->num_lines, cvg_all->num_missed);
1035
1036         /* Write text report to file. */
1037         /* io.open(coverage_report, "w") */
1038         if (!(py_mod = PyImport_ImportModule("io")))
1039                 return FALSE;
1040         if (!(py_func = PyObject_GetAttrString(py_mod, "open")))
1041                 return FALSE;
1042         if (!(py_args = PyTuple_New(0)))
1043                 return FALSE;
1044         if (!(py_kwargs = Py_BuildValue("{ssss}", "file", coverage_report,
1045                         "mode", "w")))
1046                 return FALSE;
1047         if (!(py_outfile = PyObject_Call(py_func, py_args, py_kwargs)))
1048                 return FALSE;
1049         Py_DecRef(py_kwargs);
1050         Py_DecRef(py_func);
1051
1052         /* py_cov.report(file=py_outfile) */
1053         if (!(py_func = PyObject_GetAttrString(py_cov, "report")))
1054                 return FALSE;
1055         if (!(py_kwargs = Py_BuildValue("{sO}", "file", py_outfile)))
1056                 return FALSE;
1057         if (!(py_pct = PyObject_Call(py_func, py_args, py_kwargs)))
1058                 return FALSE;
1059         Py_DecRef(py_pct);
1060         Py_DecRef(py_kwargs);
1061         Py_DecRef(py_func);
1062
1063         /* py_outfile.close() */
1064         if (!(py_func = PyObject_GetAttrString(py_outfile, "close")))
1065                 return FALSE;
1066         if (!PyObject_Call(py_func, py_args, NULL))
1067                 return FALSE;
1068         Py_DecRef(py_outfile);
1069         Py_DecRef(py_func);
1070         Py_DecRef(py_args);
1071         Py_DecRef(py_mod);
1072
1073         return TRUE;
1074 }
1075
1076 int main(int argc, char **argv)
1077 {
1078         PyObject *coverage;
1079         GSList *pdlist;
1080         struct pd *pd;
1081         struct channel *channel;
1082         struct option *option;
1083         struct input *inp;
1084         struct output *op;
1085         int ret, c;
1086         char **kv, **opstr;
1087         struct initial_pin_info *initial_pin;
1088
1089         inp = malloc(sizeof(*inp));
1090         inp->filename = NULL;
1091         inp->format = NULL;
1092         inp->opt_list = NULL;
1093         inp->opt_hash = NULL;
1094
1095         op = malloc(sizeof(struct output));
1096         op->pd = NULL;
1097         op->pd_id = NULL;
1098         op->type = -1;
1099         op->class_ = NULL;
1100         op->class_idx = -1;
1101         op->outfd = 1;
1102
1103         pdlist = NULL;
1104         pd = NULL;
1105         coverage = NULL;
1106         while ((c = getopt(argc, argv, "dP:p:o:N:i:I:O:f:c:S")) != -1) {
1107                 switch (c) {
1108                 case 'd':
1109                         debug = TRUE;
1110                         break;
1111                 case 'P':
1112                         pd = g_malloc(sizeof(struct pd));
1113                         pd->name = g_strdup(optarg);
1114                         pd->channels = pd->options = pd->initial_pins = NULL;
1115                         pdlist = g_slist_append(pdlist, pd);
1116                         break;
1117                 case 'p':
1118                 case 'o':
1119                 case 'N':
1120                         if (g_slist_length(pdlist) == 0) {
1121                                 /* No previous -P. */
1122                                 ERR("Syntax error at '%s'", optarg);
1123                                 usage(NULL);
1124                         }
1125                         kv = g_strsplit(optarg, "=", 0);
1126                         if (!kv[0] || (!kv[1] || kv[2])) {
1127                                 /* Need x=y. */
1128                                 ERR("Syntax error at '%s'", optarg);
1129                                 g_strfreev(kv);
1130                                 usage(NULL);
1131                         }
1132                         if (c == 'p') {
1133                                 channel = malloc(sizeof(struct channel));
1134                                 channel->name = g_strdup(kv[0]);
1135                                 channel->channel = strtoul(kv[1], NULL, 10);
1136                                 /* Apply to last PD. */
1137                                 pd->channels = g_slist_append(pd->channels, channel);
1138                         } else if (c == 'o') {
1139                                 option = malloc(sizeof(struct option));
1140                                 option->key = g_strdup(kv[0]);
1141                                 option->value = g_variant_new_string(kv[1]);
1142                                 g_variant_ref_sink(option->value);
1143                                 /* Apply to last PD. */
1144                                 pd->options = g_slist_append(pd->options, option);
1145                         } else {
1146                                 initial_pin = malloc(sizeof(struct initial_pin_info));
1147                                 initial_pin->name = g_strdup(kv[0]);
1148                                 initial_pin->value = strtoul(kv[1], NULL, 10);
1149                                 /* Apply to last PD. */
1150                                 pd->initial_pins = g_slist_append(pd->initial_pins, initial_pin);
1151                         }
1152                         break;
1153                 case 'i':
1154                         inp->filename = optarg;
1155                         break;
1156                 case 'I':
1157                         /* First arg is the format name, others are options. */
1158                         if (!inp->format) {
1159                                 inp->format = optarg;
1160                                 break;
1161                         }
1162                         inp->opt_list = g_slist_append(inp->opt_list, optarg);
1163                         break;
1164                 case 'O':
1165                         opstr = g_strsplit(optarg, ":", 0);
1166                         if (!opstr[0] || !opstr[1]) {
1167                                 /* Need at least abc:def. */
1168                                 ERR("Syntax error at '%s'", optarg);
1169                                 g_strfreev(opstr);
1170                                 usage(NULL);
1171                         }
1172                         op->pd = g_strdup(opstr[0]);
1173                         if (!strcmp(opstr[1], "annotation"))
1174                                 op->type = SRD_OUTPUT_ANN;
1175                         else if (!strcmp(opstr[1], "binary"))
1176                                 op->type = SRD_OUTPUT_BINARY;
1177                         else if (!strcmp(opstr[1], "python"))
1178                                 op->type = SRD_OUTPUT_PYTHON;
1179                         else if (!strcmp(opstr[1], "exception"))
1180                                 /* Doesn't matter, we just need it to bomb out. */
1181                                 op->type = SRD_OUTPUT_PYTHON;
1182                         else {
1183                                 ERR("Unknown output type '%s'", opstr[1]);
1184                                 g_strfreev(opstr);
1185                                 usage(NULL);
1186                         }
1187                         if (opstr[2])
1188                                 op->class_ = g_strdup(opstr[2]);
1189                         g_strfreev(opstr);
1190                         break;
1191                 case 'f':
1192                         op->outfile = g_strdup(optarg);
1193                         op->outfd = -1;
1194                         break;
1195                 case 'c':
1196                         coverage_report = optarg;
1197                         break;
1198                 case 'S':
1199                         statistics = TRUE;
1200                         break;
1201                 default:
1202                         usage(NULL);
1203                 }
1204         }
1205         if (argc > optind)
1206                 usage(NULL);
1207         if (g_slist_length(pdlist) == 0)
1208                 usage(NULL);
1209         if (!inp->filename)
1210                 usage(NULL);
1211         if (!op->pd || op->type == -1)
1212                 usage(NULL);
1213
1214         sr_log_callback_set(sr_log, NULL);
1215         if (sr_init(&ctx) != SR_OK)
1216                 return 1;
1217
1218         srd_log_callback_set(srd_log, NULL);
1219         if (srd_init(DECODERS_DIR) != SRD_OK)
1220                 return 1;
1221
1222         if (coverage_report) {
1223                 if (!(coverage = start_coverage(pdlist))) {
1224                         DBG("Failed to start coverage.");
1225                         if (PyErr_Occurred()) {
1226                                 PyErr_PrintEx(0);
1227                                 PyErr_Clear();
1228                         }
1229                 }
1230         }
1231
1232         ret = 0;
1233         if (!run_testcase(inp, pdlist, op))
1234                 ret = 1;
1235
1236         if (coverage) {
1237                 DBG("Stopping coverage.");
1238
1239                 if (!(PyObject_CallMethod(coverage, "stop", NULL)))
1240                         ERR("Failed to stop coverage.");
1241                 else if (!(report_coverage(coverage, pdlist)))
1242                         ERR("Failed to make coverage report.");
1243                 else
1244                         DBG("Coverage report in %s", coverage_report);
1245
1246                 if (PyErr_Occurred()) {
1247                         PyErr_PrintEx(0);
1248                         PyErr_Clear();
1249                 }
1250                 Py_DecRef(coverage);
1251         }
1252
1253         srd_exit();
1254         sr_exit(ctx);
1255
1256         return ret;
1257 }