add show device detail mode
[sigrok:sigrok.git] / frontend / cli / sigrok-cli.c
1 /*
2  *   sigrok - sigrok-cli.c
3  *
4  *   Copyright (C) 2010 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 <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <termios.h>
24 #include <string.h>
25 #include <poll.h>
26 #include <time.h>
27 #include <glib.h>
28
29 #include "config.h"
30 #include "sigrok.h"
31 #include "backend.h"
32 #include "hwplugin.h"
33 #include "device.h"
34 #include "session.h"
35
36 #include <libusb.h>
37 #include <sys/time.h>
38
39 #define SIGROK_CLI_VERSION "0.1"
40
41 extern struct hwcap_option hwcap_options[];
42
43 gboolean debug = FALSE;
44 GMainContext *gmaincontext = NULL;
45 GMainLoop *gmainloop = NULL;
46 struct termios term_orig = {0};
47 int format_bpl = 64;
48 char format_base = 'b';
49 int limit_samples = 0;
50
51 static gboolean opt_version = FALSE;
52 static gboolean opt_list_hwplugins = FALSE;
53 static gboolean opt_list_devices = FALSE;
54 static gboolean opt_list_analyzers = FALSE;
55 static gchar *load_session_filename = NULL;
56 static gchar *save_session_filename = NULL;
57 static int opt_device = -1;
58 static gchar *opt_probes = NULL;
59 static gchar **opt_devoption = NULL;
60 static gchar *opt_analyzers = NULL;
61 static gchar *opt_format = NULL;
62 static gchar *opt_seconds = NULL;
63 static gchar *opt_samples = NULL;
64 static GOptionEntry optargs[] =
65 {
66         { "version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, "Show version", NULL },
67         { "list-hardware-plugins", 'H', 0, G_OPTION_ARG_NONE, &opt_list_hwplugins, "List hardware plugins", NULL },
68         { "list-devices", 'D', 0, G_OPTION_ARG_NONE, &opt_list_devices, "List devices", NULL },
69         { "list-analyzer-plugins", 'A', 0, G_OPTION_ARG_NONE, &opt_list_analyzers, "List analyzer plugins", NULL },
70
71         { "load-session-file", 'L', 0, G_OPTION_ARG_FILENAME, &load_session_filename, "Load session from file", NULL },
72         { "save-session-file", 'S', 0, G_OPTION_ARG_FILENAME, &save_session_filename, "Save session to file", NULL },
73         { "device", 'd', 0, G_OPTION_ARG_INT, &opt_device, "Use device id", NULL },
74         { "probes", 'p', 0, G_OPTION_ARG_STRING, &opt_probes, "Probes to use", NULL },
75         { "device-option", 'o', 0, G_OPTION_ARG_STRING_ARRAY, &opt_devoption, "Device-specific option", NULL },
76         { "analyzers", 'a', 0, G_OPTION_ARG_STRING, &opt_analyzers, "Protocol analyzer sequence", NULL },
77         { "format", 'f', 0, G_OPTION_ARG_STRING, &opt_format, "Output format", NULL },
78
79         { "seconds", 0, 0, G_OPTION_ARG_STRING, &opt_seconds, "Number of seconds to sample", NULL },
80         { "samples", 0, 0, G_OPTION_ARG_STRING, &opt_samples, "Number of samples to acquire", NULL },
81
82         { NULL }
83
84 };
85
86 void show_version(void)
87 {
88
89         printf("Sigrok version %s\nCLI version %s\n", VERSION, SIGROK_CLI_VERSION);
90
91 }
92
93
94 void show_hwplugin_list(void)
95 {
96         GSList *plugins, *p;
97         struct device_plugin *plugin;
98
99         printf("Plugins for the following devices are installed:\n");
100         plugins = list_hwplugins();
101         for(p = plugins; p; p = p->next)
102         {
103                 plugin = p->data;
104                 printf(" %s\n", plugin->name);
105         }
106
107 }
108
109
110 void print_device_line(struct device *device)
111 {
112         char *idstring;
113
114         idstring = device->plugin->get_device_info(device->plugin_index, DI_IDENTIFIER);
115         printf("%s %s", device->plugin->name, idstring);
116         g_free(idstring);
117         if(device->probes)
118                 printf(" with %d probes", g_slist_length(device->probes));
119         printf("\n");
120
121 }
122
123
124 void show_device_list(void)
125 {
126         struct device *device;
127         GSList *devices, *l;
128         int devcnt;
129
130         devcnt = 0;
131         device_scan();
132         devices = device_list();
133         if(g_slist_length(devices) > 0)
134         {
135                 printf("The following devices were found:\nID  Device\n");
136                 for(l = devices; l; l = l->next)
137                 {
138                         device = l->data;
139                         printf("%-3d ", devcnt);
140                         print_device_line(device);
141                         devcnt++;
142                 }
143         }
144
145 }
146
147
148 void show_device_detail(void)
149 {
150         struct device *device;
151         struct hwcap_option *hwo;
152         GSList *devices;
153         float *sample_rates;
154         int cap, *capabilities, i;
155         char *title;
156
157         device_scan();
158         devices = device_list();
159         device = g_slist_nth_data(devices, opt_device);
160         if(device == NULL)
161         {
162                 printf("No such device. Use -D to list all devices.\n");
163                 return;
164         }
165
166         print_device_line(device);
167
168         title = "Supported options:\n";
169         capabilities = device->plugin->get_capabilities();
170         for(cap = 0; capabilities[cap]; cap++)
171         {
172                 hwo = find_hwcap_option(capabilities[cap]);
173                 if(hwo)
174                 {
175                         if(title)
176                         {
177                                 printf("%s", title);
178                                 title = NULL;
179                         }
180                         if(hwo->capability == HWCAP_SAMPLERATE)
181                         {
182                                 printf("    %s", hwo->shortname);
183                                 /* supported sample rates */
184                                 sample_rates = (float *) device->plugin->get_device_info(device->plugin_index, DI_SAMPLE_RATES);
185                                 if(sample_rates)
186                                 {
187                                         printf(" - supported sample rates:\n");
188                                         for(i = 0; sample_rates[i]; i++)
189                                                 printf("        %7.3f\n", sample_rates[i]);
190                                 }
191                                 else
192                                         printf("\n");
193                         }
194                         else
195                                 printf("      %s\n", hwo->shortname);
196                 }
197         }
198
199 }
200
201
202 void show_analyzer_list()
203 {
204
205         /* TODO: implement */
206
207 }
208
209
210 void flush_linebufs(GSList *probes, char *linebuf, int linebuf_len)
211 {
212         static int num_probes = 0;
213         static int max_probename_len = 0;
214
215         struct probe *probe;
216         int len, p;
217
218         if(linebuf[0])
219         {
220                 if(num_probes == 0)
221                 {
222                         /* first time through */
223                         num_probes = g_slist_length(probes);
224                         for(p = 0; p < num_probes; p++)
225                         {
226                                 probe = g_slist_nth_data(probes, p);
227                                 if(probe->enabled)
228                                 {
229                                         len = strlen(probe->name);
230                                         if(len > max_probename_len)
231                                                 max_probename_len = len;
232                                 }
233                         }
234                 }
235
236                 for(p = 0; p < num_probes; p++)
237                 {
238                         probe = g_slist_nth_data(probes, p);
239                         if(probe->enabled)
240                                 printf("%*s:%s\n", max_probename_len, probe->name, linebuf + p * linebuf_len);
241                 }
242                 memset(linebuf, 0, num_probes * linebuf_len);
243         }
244
245 }
246
247
248 void datafeed_callback(struct device *device, struct datafeed_packet *packet)
249 {
250         static int num_probes = 0;
251         static int received_samples = 0;
252         static int linebuf_len = 0;
253         static char *linebuf = NULL;
254
255         struct probe *probe;
256         struct datafeed_header *header;
257         int num_enabled_probes, offset, p, buf_offset, bpl_cnt, i;
258         unsigned int sample;
259
260         /* if the first packet to come in isn't a header, don't even try */
261         if(packet->type != DF_HEADER && linebuf == NULL)
262                 return;
263
264         if(packet->type == DF_HEADER)
265         {
266                 header = (struct datafeed_header *) packet->payload;
267                 num_enabled_probes = 0;
268                 for(i = 0; i < header->num_probes; i++)
269                 {
270                         probe = g_slist_nth_data(device->probes, i);
271                         if(probe->enabled)
272                                 num_enabled_probes++;
273                 }
274                 printf("Acquisition with %d/%d probes at %.3f Mhz starting at %s",
275                                 num_enabled_probes, header->num_probes, header->rate,
276                                 ctime(&header->starttime.tv_sec));
277                 num_probes = header->num_probes;
278
279                 linebuf_len = format_bpl * 2;
280                 linebuf = g_malloc0(num_probes * linebuf_len);
281         }
282         else if(packet->type == DF_END)
283         {
284                 flush_linebufs(device->probes, linebuf, linebuf_len);
285                 g_main_loop_quit(gmainloop);
286         }
287         else if(packet->type == DF_LOGIC8)
288         {
289                 /* every byte represents a complete sample set, with num_probes being the
290                  * number of bits that are relevant. we're handling all probes here, not
291                  * checking whether they're enabled or not. flush_linebufs() will skip them.
292                  */
293                 if(format_base == 'b')
294                 {
295                         buf_offset = bpl_cnt = 0;
296                         for(offset = 0; received_samples < limit_samples && offset < packet->length; offset++)
297                         {
298                                 sample = packet->payload[offset];
299                                 for(p = 0; p < num_probes; p++)
300                                 {
301                                         if(sample & (1 << p))
302                                                 linebuf[p * linebuf_len + buf_offset] = '1';
303                                         else
304                                                 linebuf[p * linebuf_len + buf_offset] = '0';
305                                 }
306                                 buf_offset++;
307                                 bpl_cnt++;
308
309                                 /* space every 8th bit */
310                                 if((bpl_cnt & 7) == 0)
311                                 {
312                                         for(p = 0; p < num_probes; p++)
313                                                 linebuf[p * linebuf_len + buf_offset] = ' ';
314                                         buf_offset++;
315                                 }
316
317                                 /* end of line */
318                                 if(bpl_cnt >= format_bpl)
319                                 {
320                                         flush_linebufs(device->probes, linebuf, linebuf_len);
321                                         buf_offset = bpl_cnt = 0;
322                                 }
323                                 received_samples++;
324                         }
325                 }
326                 else
327                 {
328                         /* TODO: implement */
329                 }
330         }
331
332 }
333
334
335 gboolean stdin_prepare(GSource *source, int *timeout)
336 {
337
338         *timeout = -1;
339
340         return FALSE;
341 }
342
343
344 gboolean stdin_check(GSource *source)
345 {
346         struct pollfd pfd;
347
348         pfd.fd = STDIN_FILENO;
349         pfd.events = POLLIN;
350         if(poll(&pfd, 1, 0))
351                 return TRUE;
352
353         return FALSE;
354 }
355
356
357 gboolean stdin_dispatch(GSource *source, GSourceFunc callback, gpointer data)
358 {
359
360         g_main_loop_quit(gmainloop);
361
362         return TRUE;
363 }
364
365
366 GSourceFuncs stdin_funcs = {
367         stdin_prepare,
368         stdin_check,
369         stdin_dispatch,
370         NULL
371 };
372
373
374 char **parse_probestring(int max_probes, char *probestring)
375 {
376         int tmp, b, e, i;
377         char **tokens, **range, **probelist, *name, str[8];
378         gboolean error;
379
380         error = FALSE;
381         range = NULL;
382         probelist = g_malloc0(max_probes * sizeof(char *));
383         tokens = g_strsplit(probestring, ",", max_probes);
384         for(i = 0; tokens[i]; i++)
385         {
386                 if(strchr(tokens[i], '-'))
387                 {
388                         /* a range of probes in the form 1-5 */
389                         range = g_strsplit(tokens[i], "-", 2);
390                         if(!range[0] || !range[1] || range[2])
391                         {
392                                 /* need exactly two arguments */
393                                 printf("Invalid probe syntax '%s'.\n", tokens[i]);
394                                 error = TRUE;
395                                 break;
396                         }
397
398                         b = atoi(range[0]);
399                         e = atoi(range[1]);
400                         if(b < 1 || e > max_probes || b >= e)
401                         {
402                                 printf("Invalid probe range '%s'.\n", tokens[i]);
403                                 error = TRUE;
404                                 break;
405                         }
406
407                         while(b <= e)
408                         {
409                                 snprintf(str, 7, "%d", b);
410                                 probelist[b-1] = g_strdup(str);
411                                 b++;
412                         }
413                 }
414                 else
415                 {
416                         tmp = atoi(tokens[i]);
417                         if(tmp < 1 || tmp > max_probes)
418                         {
419                                 printf("Invalid probe %d.\n", tmp);
420                                 error = TRUE;
421                                 break;
422                         }
423
424                         if( (name=strchr(tokens[i], '=')) )
425                                 probelist[tmp-1] = g_strdup(++name);
426                         else
427                         {
428                                 snprintf(str, 7, "%d", tmp);
429                                 probelist[tmp-1] = g_strdup(str);
430                         }
431                 }
432         }
433
434         if(error)
435         {
436                 for(i = 0; i < max_probes; i++)
437                         if(probelist[i])
438                                 g_free(probelist[i]);
439                 g_free(probelist);
440                 probelist = NULL;
441         }
442
443         g_strfreev(tokens);
444         if(range)
445                 g_strfreev(range);
446
447         if(debug && probelist)
448                 for(i = 0; i < max_probes; i++)
449                 {
450                         if(probelist[i])
451                                 g_message("Probe %d: '%s'", i+1, probelist[i]);
452                 }
453
454         return probelist;
455 }
456
457
458 void run_session(void)
459 {
460         struct device *device;
461         struct probe *probe;
462         struct termios term;
463         GSource *stdin_source;
464         GPollFD stdin_pfd;
465         GSList *devices;
466         int num_devices, max_probes, ret, i, j;
467         char **probelist, *val;
468
469         device_scan();
470         devices = device_list();
471         num_devices = g_slist_length(devices);
472         if(num_devices == 0)
473         {
474                 g_warning("No devices found.");
475                 return;
476         }
477         if(opt_device == -1)
478         {
479                 if(num_devices == 1)
480                         /* no device specified, but there is only one */
481                         opt_device = 0;
482                 else
483                 {
484                         g_warning("%d devices found, please select one.", num_devices);
485                         return;
486                 }
487         }
488         else
489         {
490                 if(opt_device >= num_devices)
491                 {
492                         g_warning("Device not found.");
493                         return;
494                 }
495         }
496
497         session_new();
498         session_output_add_callback(datafeed_callback);
499
500         device = g_slist_nth_data(devices, opt_device);
501         if(session_device_add(device) != SIGROK_OK)
502         {
503                 printf("Failed to use device.\n");
504                 session_destroy();
505                 return;
506         }
507
508         if(opt_probes)
509         {
510                 /* this only works because a device by default initializes and enables all its probes */
511                 max_probes = g_slist_length(device->probes);
512                 probelist = parse_probestring(max_probes, opt_probes);
513                 if(!probelist)
514                 {
515                         session_destroy();
516                         return;
517                 }
518
519                 for(i = 0; i < max_probes; i++)
520                 {
521                         if(probelist[i])
522                         {
523                                 device_probe_name(device, i+1, probelist[i]);
524                                 g_free(probelist[i]);
525                         }
526                         else
527                         {
528                                 probe = probe_find(device, i+1);
529                                 probe->enabled = FALSE;
530                         }
531                 }
532                 g_free(probelist);
533         }
534
535         if(opt_seconds)
536         {
537                 device->plugin->set_configuration(device->plugin_index, HWCAP_LIMIT_SECONDS, opt_seconds);
538         }
539         if(opt_samples)
540         {
541                 limit_samples = atoi(opt_samples);
542                 device->plugin->set_configuration(device->plugin_index, HWCAP_LIMIT_SAMPLES, opt_samples);
543         }
544
545         if(opt_devoption)
546         {
547                 for(i = 0; opt_devoption[i]; i++)
548                 {
549                         if( (val = strchr(opt_devoption[i], '=')) )
550                         {
551                                 *val = 0;
552                                 for(j = 0; hwcap_options[j].capability; j++)
553                                 {
554                                         if(!strcmp(hwcap_options[i].shortname, opt_devoption[i]))
555                                         {
556                                                 ret = device->plugin->set_configuration(device->plugin_index, hwcap_options[j].capability, ++val);
557                                                 if(ret != SIGROK_OK)
558                                                 {
559                                                         printf("Failed to set device option '%s'.\n", opt_devoption[i]);
560                                                         session_destroy();
561                                                         return;
562                                                 }
563                                         }
564                                 }
565                         }
566                         else
567                         {
568                                 printf("Invalid device option '%s'.\n", opt_devoption[i]);
569                                 session_destroy();
570                                 return;
571                         }
572                 }
573         }
574
575         if(session_start() != SIGROK_OK)
576         {
577                 printf("Failed to start session.\n");
578                 session_destroy();
579                 return;
580         }
581
582         gmaincontext = g_main_context_default();
583
584         if(!opt_seconds && !opt_samples)
585         {
586                 /* monitor stdin along with the device's I/O */
587                 tcgetattr(STDIN_FILENO, &term);
588                 memcpy(&term_orig, &term, sizeof(struct termios));
589                 term.c_lflag &= ~(ECHO | ICANON | ISIG);
590                 tcsetattr(STDIN_FILENO, TCSADRAIN, &term);
591
592                 stdin_source = g_source_new(&stdin_funcs, sizeof(GSource));
593                 stdin_pfd.fd = STDIN_FILENO;
594                 stdin_pfd.events =  G_IO_IN | G_IO_HUP | G_IO_ERR;
595                 g_main_context_add_poll(gmaincontext, &stdin_pfd, G_PRIORITY_DEFAULT);
596                 g_source_add_poll(stdin_source, &stdin_pfd);
597                 ret = g_source_attach(stdin_source, gmaincontext);
598
599                 printf("press any key to stop\n");
600         }
601
602         gmainloop = g_main_loop_new(gmaincontext, FALSE);
603         g_main_loop_run(gmainloop);
604
605         if(!opt_seconds && !opt_samples)
606         {
607                 tcflush(STDIN_FILENO, TCIFLUSH);
608                 tcsetattr(STDIN_FILENO, TCSANOW, &term_orig);
609         }
610         session_stop();
611
612         session_destroy();
613
614 }
615
616
617 void logger(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
618 {
619
620         if(log_level & (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING))
621         {
622                 fprintf(stderr, "Warning: %s\n", message);
623                 fflush(stderr);
624         }
625         else
626         {
627                 if(debug)
628                 {
629                         printf("* %s\n", message);
630                         fflush(stdout);
631                 }
632         }
633
634 }
635
636
637 int main(int argc, char **argv)
638 {
639         GOptionContext *context;
640         GError *error;
641         int val, i;
642
643         printf("Sigrok version %s\n", PACKAGE_VERSION);
644         g_log_set_default_handler(logger, NULL);
645         if(getenv("SIGROK_DEBUG"))
646                 debug = TRUE;
647
648         error = NULL;
649         context = g_option_context_new(NULL);
650         g_option_context_add_main_entries(context, optargs, NULL);
651         if(!g_option_context_parse(context, &argc, &argv, &error))
652         {
653                 g_warning("%s", error->message);
654                 return 1;
655         }
656
657         if(sigrok_init() != SIGROK_OK)
658                 return 1;
659
660         if(opt_format)
661         {
662                 val = atoi(opt_format);
663                 if(val > 0)
664                         format_bpl = val;
665                 for(i = 0; opt_format[i]; i++)
666                         if(opt_format[i] == 'b' || opt_format[i] == 'h')
667                         {
668                                 format_base = opt_format[i];
669                                 break;
670                         }
671         }
672
673         if(opt_version)
674                 show_version();
675         else if(opt_list_hwplugins)
676                 show_hwplugin_list();
677         else if(opt_list_devices)
678                 show_device_list();
679         else if(opt_list_analyzers)
680                 show_analyzer_list();
681         else if(opt_samples || opt_seconds)
682                 run_session();
683         else if(opt_device != -1)
684                 show_device_detail();
685         else
686                 printf("%s", g_option_context_get_help(context, TRUE, NULL));
687
688         sigrok_cleanup();
689
690         return 0;
691 }
692
693