vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / sis33 / test / sis33test.c
blobf003c99cf4890222e072af04e6109d6e4812d607
1 /*
2 * sis33test.c
3 * sis33 interactive test-program
5 * Copyright (c) 2009-2010 Emilio G. Cota <cota@braap.org>
6 * Released under the GPL v2. (and only v2, not any later version)
7 */
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <time.h>
12 #include <general_usr.h> /* for handy definitions (mperr etc..) */
13 #include <extest.h>
14 #include <sis33.h>
16 #include "sis33acq.h"
17 #include "sis33dev.h"
19 #define SIS33T_MAX_NR_SEGMENTS 8
21 int use_builtin_cmds = 0;
22 char xmlfile[128] = "cvorg.xml";
24 static uint32_t channel_nr = 0;
25 static uint32_t nr_events[SIS33T_MAX_NR_SEGMENTS];
26 static uint32_t nr_samples[SIS33T_MAX_NR_SEGMENTS];
27 static struct sis33_acq_list acq_list[SIS33T_MAX_NR_SEGMENTS];
28 static int sis33fd = -1;
29 static int curr_index;
30 static int curr_segment;
31 static char gnuplot[4096];
33 static struct timespec my_us_to_timespec(const unsigned int us)
35 struct timespec ts;
37 if (!us)
38 return (struct timespec) {0, 0};
39 ts.tv_sec = us / 1000000;
40 ts.tv_nsec = (us % 1000000) * 1000;
41 return ts;
44 static int round_uint(int index, const char *name, unsigned int *roundme, enum sis33_round round)
46 unsigned int *array;
47 int ret;
48 int n;
50 n = sis33dev_get_nr_items(index, name);
51 if (n <= 0)
52 return -1;
53 array = calloc(n, sizeof(*array));
54 if (array == NULL)
55 return -1;
57 ret = sis33dev_get_items_uint(index, name, array, n);
58 if (ret)
59 goto out;
60 *roundme = sis33dev_round_uint(array, n, *roundme, round);
61 out:
62 free(array);
63 return ret;
66 #define MY_FILE_LEN 64
68 static char *write_file(const char *prefix, struct sis33_acq_list *list, int segment, int event)
70 FILE *filp;
71 struct sis33_acq *acq = &list->acqs[event];
72 static char filename[MY_FILE_LEN];
73 int i;
75 snprintf(filename, MY_FILE_LEN - 1, "/tmp/%s.ch%d.seg%d.ev%d.dat",
76 prefix, list->channel, segment, event);
77 filename[MY_FILE_LEN - 1] = '\0';
78 filp = fopen(filename, "w");
79 if (filp == NULL) {
80 mperr("fopen");
81 return NULL;
83 fprintf(filp, "# segment %d event %d\n", segment, event);
84 for (i = 0; i < acq->nr_samples; i++)
85 fprintf(filp, "0x%x\n", acq->data[i]);
86 if (fclose(filp) < 0)
87 return NULL;
88 printf("Data written to %s.\n", filename);
89 return filename;
92 static int h_attr(const struct atom *atoms, const char *param)
94 int val;
95 int ret;
97 ++atoms;
98 if (atoms->type == Numeric) {
99 ret = sis33dev_set_attr_int(curr_index, param, atoms->val);
100 if (ret < 0) {
101 mperr("set_attr");
102 return -TST_ERR_SYSCALL;
105 ret = sis33dev_get_attr_int(curr_index, param, &val);
106 if (ret < 0) {
107 mperr("get_attr");
108 return ret;
110 printf("%d\n", val);
111 return 1;
114 static int h_uattr(const struct atom *atoms, const char *param)
116 unsigned int val;
117 int ret;
119 ++atoms;
120 if (atoms->type == Numeric) {
121 val = atoms->val;
122 ret = sis33dev_set_attr_uint(curr_index, param, val);
123 if (ret < 0) {
124 mperr("set_attr_uint");
125 return -TST_ERR_SYSCALL;
128 ret = sis33dev_get_attr_uint(curr_index, param, &val);
129 if (ret < 0) {
130 mperr("get_attr_uint");
131 return ret;
133 printf("%u\n", val);
134 return 1;
137 int h_start_auto(struct cmd_desc *cmdd, struct atom *atoms)
139 if (atoms == (struct atom *)VERBOSE_HELP) {
140 printf("%s - Get/set Autostart\n"
141 "%s bool\n",
142 cmdd->name, cmdd->name);
143 return 1;
145 return h_attr(atoms, "start_auto");
148 int h_trig_ext(struct cmd_desc *cmdd, struct atom *atoms)
150 if (atoms == (struct atom *)VERBOSE_HELP) {
151 printf("%s - Enable/Disable external trigger\n"
152 "%s bool\n",
153 cmdd->name, cmdd->name);
154 return 1;
156 return h_attr(atoms, "trigger_external_enable");
159 int h_start_delay(struct cmd_desc *cmdd, struct atom *atoms)
161 if (atoms == (struct atom *)VERBOSE_HELP) {
162 printf("%s - Get/Set Start delay\n"
163 "%s n\n"
164 "\tdelay: start input delay of n clock ticks\n"
165 "\tNote: this has no effect on software-driven start\n"
166 "\t(valid range for the sis3320: [0-8K]\n",
167 cmdd->name, cmdd->name);
168 return 1;
170 return h_attr(atoms, "start_delay");
174 int h_stop_delay(struct cmd_desc *cmdd, struct atom *atoms)
176 if (atoms == (struct atom *)VERBOSE_HELP) {
177 printf("%s - Get/Set Stop delay\n"
178 "%s n\n"
179 "\tdelay: stop input delay of n clock ticks\n"
180 "\tNote: this has no effect on software-driven stop\n"
181 "\t(valid range for the sis3320: [0-8K]\n",
182 cmdd->name, cmdd->name);
183 return 1;
185 return h_attr(atoms, "stop_delay");
188 static int show_chan_offset_all(void)
190 char attr[SIS33_PATH_MAX];
191 int n_channels;
192 unsigned int val;
193 int ret;
194 int i;
196 n_channels = sis33dev_get_nr_subattrs(curr_index, "channels");
197 if (n_channels < 0)
198 return n_channels;
200 for (i = 0; i < n_channels; i++) {
201 snprintf(attr, sizeof(attr) - 1, "channels/channel%d/offset", i);
202 attr[sizeof(attr) - 1] = '\0';
203 ret = sis33dev_get_attr_uint(curr_index, attr, &val);
204 if (ret < 0)
205 continue;
206 printf("%d\t0x%-8x (%d)\n", i, val, val);
208 return 1;
211 static int set_offset(int offset, int channel)
213 char attr[SIS33_PATH_MAX];
214 int n_channels;
215 int init, end;
216 int ret;
217 int i;
219 n_channels = sis33dev_get_nr_subattrs(curr_index, "channels");
220 if (n_channels < 0)
221 return n_channels;
222 if (channel == -1) {
223 init = 0;
224 end = n_channels;
225 } else {
226 init = channel;
227 end = channel + 1;
229 for (i = init; i < end; i++) {
230 snprintf(attr, sizeof(attr) - 1, "channels/channel%d/offset", i);
231 attr[sizeof(attr) - 1] = '\0';
232 ret = sis33dev_set_attr_int(curr_index, attr, offset);
233 if (ret < 0) {
234 mperr("set_offset");
235 return -TST_ERR_SYSCALL;
238 return 0;
241 int h_offset(struct cmd_desc *cmdd, struct atom *atoms)
243 int n_channels;
244 int channel;
245 int ret;
247 n_channels = sis33dev_get_nr_subattrs(curr_index, "channels");
248 if (n_channels < 0)
249 return n_channels;
251 if (atoms == (struct atom *)VERBOSE_HELP) {
252 printf("%s - Configure Input Offset\n"
253 "%s channel_nr value\n"
254 "\tchannel_nr: [0-%d]. -1 to select all channels\n"
255 "\value: 16 bits (max. 0xffff.)\n",
256 cmdd->name, cmdd->name, n_channels - 1);
257 return 1;
260 ++atoms;
261 if (atoms->type == Terminator)
262 return show_chan_offset_all();
264 if (atoms->type != Numeric)
265 return -TST_ERR_WRONG_ARG;
266 if (!WITHIN_RANGE(-1, atoms->val, n_channels - 1))
267 return -TST_ERR_WRONG_ARG;
268 channel = atoms->val;
270 ++atoms;
271 if (atoms->type != Numeric)
272 return -TST_ERR_WRONG_ARG;
273 ret = set_offset(atoms->val, channel);
274 if (ret)
275 return ret;
277 printf("Updated:\n");
278 return show_chan_offset_all();
281 int h_clksrc(struct cmd_desc *cmdd, struct atom *atoms)
283 int clksrc;
284 int ret;
286 if (atoms == (struct atom *)VERBOSE_HELP) {
287 printf("%s - Configure Clock Source\n"
288 "%s [source]\n"
289 "\tsource: 0 (internal), 1 (external)\n",
290 cmdd->name, cmdd->name);
291 return 1;
294 ++atoms;
295 if (atoms->type == Numeric) {
296 ret = sis33dev_set_attr_int(curr_index, "clock_source", atoms->val);
297 if (ret < 0) {
298 mperr("set_attr clock_source");
299 return -TST_ERR_SYSCALL;
302 ret = sis33dev_get_attr_int(curr_index, "clock_source", &clksrc);
303 if (ret < 0) {
304 mperr("get_attr clock_source");
305 return ret;
307 if (clksrc == SIS33_CLKSRC_INTERNAL)
308 printf("internal");
309 else if (clksrc == SIS33_CLKSRC_EXTERNAL)
310 printf("external");
311 else
312 printf("unknown");
313 printf("\n");
314 return 1;
317 int h_clkfreq(struct cmd_desc *cmdd, struct atom *atoms)
319 int show_available = 0;
320 unsigned int val;
321 int ret;
323 if (atoms == (struct atom *)VERBOSE_HELP) {
324 printf("%s - Get/Set Clock Frequency\n"
325 "%s [Hz]\n"
326 "\tHz: clock frequency, in Hz.\n",
327 cmdd->name, cmdd->name);
328 return 1;
330 ++atoms;
331 if (atoms->type == Terminator)
332 show_available++;
333 else if (atoms->type == Numeric) {
334 val = atoms->val;
335 if (round_uint(curr_index, "available_clock_frequencies", &val, SIS33_ROUND_NEAREST) < 0)
336 return -TST_ERR_SYSCALL;
337 ret = sis33dev_set_attr_int(curr_index, "clock_frequency", val);
338 if (ret < 0) {
339 mperr("set_attr");
340 return -TST_ERR_SYSCALL;
343 ret = sis33dev_get_attr_uint(curr_index, "clock_frequency", &val);
344 if (ret < 0) {
345 mperr("get_attr");
346 return ret;
348 printf("%u\n", val);
349 if (show_available) {
350 char clkfreqs[256];
352 ret = sis33dev_get_attr(curr_index, "available_clock_frequencies", clkfreqs, sizeof(clkfreqs));
353 if (ret < 0) {
354 mperr("get_attr available_clock_frequencies");
355 return ret;
357 printf("Available clock frequencies: %s\n", clkfreqs);
359 return 1;
362 int h_stop_auto(struct cmd_desc *cmdd, struct atom *atoms)
364 if (atoms == (struct atom *)VERBOSE_HELP) {
365 printf("%s - Get/Set Autostop\n"
366 "%s bool\n"
367 "Stop sampling for each event after the "
368 "specified number of samples have been collected.\n",
369 cmdd->name, cmdd->name);
370 return 1;
372 return h_attr(atoms, "stop_auto");
375 int h_ch(struct cmd_desc *cmdd, struct atom *atoms)
377 int n_channels;
379 n_channels = sis33dev_get_nr_subattrs(curr_index, "channels");
380 if (n_channels < 0)
381 return n_channels;
383 if (atoms == (struct atom *)VERBOSE_HELP) {
384 printf("%s - Get/Set Channel\n"
385 "%s [channel_nr]\n"
386 "\tchannel_nr: 0-%d\n",
387 cmdd->name, cmdd->name, n_channels - 1);
388 return 1;
391 ++atoms;
392 if (atoms->type == Terminator) {
393 printf("%d\n", channel_nr);
394 goto out;
397 if (atoms->type != Numeric || !WITHIN_RANGE(0, atoms->val, n_channels - 1))
398 return -TST_ERR_WRONG_ARG;
400 channel_nr = atoms->val;
401 out:
402 return 1;
405 int h_ch_next(struct cmd_desc *cmdd, struct atom *atoms)
407 int n_channels;
409 if (atoms == (struct atom *)VERBOSE_HELP) {
410 printf("%s - Select Next Channel\n", cmdd->name);
411 return 1;
413 n_channels = sis33dev_get_nr_subattrs(curr_index, "channels");
414 if (n_channels < 0)
415 return n_channels;
416 if (channel_nr + 1 < n_channels)
417 channel_nr++;
419 return 1;
422 static void remove_trailing_chars(char *str, char c)
424 size_t len;
426 if (str == NULL)
427 return;
428 len = strlen(str);
429 while (len > 0 && str[len - 1] == c)
430 str[--len] = '\0';
433 static char *mydatetime(const struct timeval *tv)
435 static char datetime[26]; /* length imposed by ctime_r */
436 time_t time;
438 time = tv->tv_sec;
439 ctime_r(&time, datetime);
440 datetime[sizeof(datetime) - 1] = '\0';
441 remove_trailing_chars(datetime, '\n');
442 return datetime;
445 static void print_prevticks(const struct sis33_acq *acqs, int n)
447 int supported;
448 int log2;
449 int i;
451 if (sis33dev_get_attr_int(curr_index, "event_timestamping_support", &supported) < 0) {
452 mperr("get_attr event_timestamping_support");
453 return;
455 if (!supported) {
456 printf("This device doesn't support event timestamping\n");
457 return;
460 for (i = 0; i < n; i++)
461 printf("%4u 0x%8llx\n", i, (unsigned long long)acqs[i].prevticks);
462 if (sis33dev_get_attr_int(curr_index, "event_timestamping_max_ticks_log2", &log2) < 0) {
463 mperr("get_attr event_timestamping_max_ticks_log2");
464 return;
466 printf("Note that this counter overflows every 2**%d (0x%llx) ticks\n", log2, (unsigned long long)1 << log2);
469 int h_fetch(struct cmd_desc *cmdd, struct atom *atoms)
471 struct timespec timestart, timeswap, timeend;
472 struct timespec ts;
473 struct sis33_acq_list *list;
474 unsigned int segment;
475 unsigned int flags;
476 double delta;
477 int acq_events;
478 int show_tstamps = 0;
479 int ret = 1;
481 if (atoms == (struct atom *)VERBOSE_HELP) {
482 printf("%s - Fetch Acquired Data\n"
483 "%s [segment] [timeout_us] [show_tstamps]\n"
484 "\tsegment: segment number. -1 for current (default).\n"
485 "\ttimeout_us: 0 - blocking wait until the acquisition finishes\n"
486 "\t\tn > 0 - blocking wait with timeout equal to n us\n"
487 "\tshow_tstamps: 1 to show all the events' timestamps. Default: 0\n"
488 "Note: If no timeout is provided, no blocking wait is done\n",
489 cmdd->name, cmdd->name);
490 return 1;
493 ++atoms;
494 segment = curr_segment;
495 flags = SIS33_ACQF_DONTWAIT;
496 if (atoms->type == Terminator)
497 goto fetch;
498 if (atoms->type == Numeric && atoms->val != -1) {
499 segment = atoms->val;
500 if (segment < 0 || segment >= SIS33T_MAX_NR_SEGMENTS)
501 return -TST_ERR_WRONG_ARG;
503 ++atoms;
504 if (atoms->type == Terminator)
505 goto fetch;
506 if (atoms->type == Numeric) {
507 if (atoms->val > 0) {
508 ts = my_us_to_timespec(atoms->val);
509 flags = SIS33_ACQF_TIMEOUT;
510 } else if (atoms->val == 0) {
511 flags = 0;
514 ++atoms;
515 if (atoms->type == Terminator)
516 goto fetch;
517 if (atoms->type == Numeric && atoms->val)
518 show_tstamps = 1;
519 fetch:
520 if (!nr_samples[segment] || !nr_events[segment]) {
521 fprintf(stderr, "segment %d: No acquisitions done yet\n", segment);
522 return -TST_ERR_WRONG_ARG;
525 list = &acq_list[segment];
526 /* free the complete list in case there's some data already */
527 if (list->acqs)
528 sis33acq_free(list->acqs, list->n_acqs);
530 memset(list, 0, sizeof(*list));
532 list->acqs = sis33acq_zalloc(nr_events[segment], nr_samples[segment]);
533 if (list->acqs == NULL) {
534 ret = TST_ERR_SYSCALL;
535 goto out;
537 list->n_acqs = nr_events[segment];
538 list->segment = segment;
539 list->channel = channel_nr;
540 list->flags = flags;
541 list->timeout = ts;
542 list->endtime.tv_sec = 0;
543 list->endtime.tv_usec = 0;
545 /* fetch the samples */
546 if (clock_gettime(CLOCK_REALTIME, &timestart)) {
547 mperr("clock_gettime() failed for timestart");
548 ret = -TST_ERR_SYSCALL;
549 goto out;
551 acq_events = ioctl(sis33fd, SIS33_IOC_FETCH, list);
552 if (acq_events < 0) {
553 mperr("Fetch");
554 ret = -TST_ERR_IOCTL;
555 goto out;
557 if (acq_events < nr_events[segment]) {
558 fprintf(stderr, "Acquired only %d out of %d event%s\n",
559 acq_events, nr_events[segment], nr_events[segment] > 1 ? "s" : "");
561 if (clock_gettime(CLOCK_REALTIME, &timeswap)) {
562 mperr("clock_gettime() failed for timestart");
563 ret = -TST_ERR_SYSCALL;
564 goto out;
567 if (sis33acq_list_normalize(list, acq_events)) {
568 mperr("sis33acq_list_normalize failed");
569 ret = -TST_ERR_SYSCALL;
570 goto out;
573 if (clock_gettime(CLOCK_REALTIME, &timeend)) {
574 mperr("clock_gettime() failed for timestart");
575 ret = -TST_ERR_SYSCALL;
576 goto out;
579 printf("Acquisition datetime: %s +%06luus\n",
580 mydatetime(&list->endtime), list->endtime.tv_usec);
581 delta = (double)(timeswap.tv_sec - timestart.tv_sec) * 1000000 +
582 (double)(timeswap.tv_nsec - timestart.tv_nsec) / 1000.;
583 printf("Acquisition CPU time: %g us\n", delta);
584 delta = (double)(timeend.tv_sec - timeswap.tv_sec) * 1000000 +
585 (double)(timeend.tv_nsec - timeswap.tv_nsec) / 1000.;
586 printf("swap CPU time: %g us\n", delta);
587 if (show_tstamps)
588 print_prevticks(list->acqs, acq_events);
590 out:
591 return ret;
594 int exec_trigger(uint32_t trigger)
596 int ret;
598 ret = sis33dev_set_attr_int(curr_index, "trigger", trigger);
599 if (ret < 0) {
600 mperr("set_attr trigger");
601 return -TST_ERR_SYSCALL;
603 return 1;
606 int h_acq(struct cmd_desc *cmdd, struct atom *atoms)
608 struct sis33_acq_desc desc;
609 struct timespec timestart, timeend;
610 double delta;
612 if (atoms == (struct atom *)VERBOSE_HELP) {
613 printf("%s - Start Acquisition\n"
614 "%s segment nr_events ev_length [timeout_us]\n"
615 "\tsegment: segment number [0..%d]\n"
616 "\tnr_events: number of events\n"
617 "\tev_length: number of samples per event\n"
618 "\ttimeout_us: 0 - blocking wait until the acquisition finishes\n"
619 "\t\tn > 0 - blocking wait with timeout equal to n us\n"
620 "Note: If no timeout is provided, no blocking wait is done\n",
621 cmdd->name, cmdd->name, SIS33T_MAX_NR_SEGMENTS - 1);
622 return 1;
624 memset(&desc, 0, sizeof(desc));
625 ++atoms;
626 if (atoms->type != Numeric)
627 return -TST_ERR_WRONG_ARG;
628 if (atoms->val < 0 || atoms->val >= SIS33T_MAX_NR_SEGMENTS)
629 return -TST_ERR_WRONG_ARG;
630 desc.segment = atoms->val;
631 ++atoms;
632 if (atoms->type != Numeric)
633 return -TST_ERR_WRONG_ARG;
634 desc.nr_events = atoms->val;
635 ++atoms;
636 if (atoms->type != Numeric)
637 return -TST_ERR_WRONG_ARG;
638 desc.ev_length = atoms->val;
639 if (round_uint(curr_index, "available_event_lengths",
640 &desc.ev_length, SIS33_ROUND_NEAREST) < 0)
641 return -TST_ERR_SYSCALL;
642 ++atoms;
643 if (atoms->type == Numeric) {
644 if (atoms->val > 0) {
645 desc.timeout = my_us_to_timespec(atoms->val);
646 desc.flags = SIS33_ACQF_TIMEOUT;
647 } else if (atoms->val == 0)
648 desc.flags = 0;
649 else
650 desc.flags = SIS33_ACQF_DONTWAIT;
651 } else {
652 desc.flags = SIS33_ACQF_DONTWAIT;
654 if (clock_gettime(CLOCK_REALTIME, &timestart)) {
655 mperr("clock_gettime() failed for timestart");
656 return -TST_ERR_SYSCALL;
659 if (ioctl(sis33fd, SIS33_IOC_ACQUIRE, &desc) < 0) {
660 mperr("acquire");
661 return -TST_ERR_IOCTL;
664 if (clock_gettime(CLOCK_REALTIME, &timeend)) {
665 mperr("clock_gettime() failed for timeend");
666 return -TST_ERR_SYSCALL;
669 curr_segment = desc.segment;
670 nr_events[curr_segment] = desc.nr_events;
671 nr_samples[curr_segment] = desc.ev_length;
673 delta = (double)(timeend.tv_sec - timestart.tv_sec) * 1000000 +
674 (double)(timeend.tv_nsec - timestart.tv_nsec) / 1000.;
676 printf("events: %d\nev_length: %d\n", nr_events[curr_segment], nr_samples[curr_segment]);
677 printf("acquisition: time elapsed: %g us\n", delta);
679 return 1;
682 int h_cancel(struct cmd_desc *cmdd, struct atom *atoms)
684 int ret;
686 if (atoms == (struct atom *)VERBOSE_HELP) {
687 printf("%s - Cancel Acquisition\n", cmdd->name);
688 return 1;
691 ret = sis33dev_set_attr_int(curr_index, "acq_cancel", 1);
692 if (ret < 0) {
693 mperr("set_attr acq_cancel");
694 return -TST_ERR_SYSCALL;
696 return 1;
699 int h_start(struct cmd_desc *cmdd, struct atom *atoms)
701 if (atoms == (struct atom *)VERBOSE_HELP) {
702 printf("%s - Start Sampling\n", cmdd->name);
703 return 1;
705 return exec_trigger(SIS33_TRIGGER_START);
708 int h_stop(struct cmd_desc *cmdd, struct atom *atoms)
710 if (atoms == (struct atom *)VERBOSE_HELP) {
711 printf("%s - Stop Sampling\n", cmdd->name);
712 return 1;
714 return exec_trigger(SIS33_TRIGGER_STOP);
717 static void gnuplot_append(const char *string)
719 strncat(gnuplot, string, sizeof(gnuplot) - strlen(gnuplot));
720 gnuplot[sizeof(gnuplot) - 1] = '\0';
723 static void gnuplot_init(int sis33_index)
725 char value[4];
727 gnuplot[0] = '\0';
728 if (sis33dev_get_attr(sis33_index, "n_bits", value, sizeof(value))) {
729 fprintf(stderr, "Warning: Cannot get n_bits of device %u\n", sis33_index);
730 } else {
731 int n_bits = strtol(value, NULL, 0);
732 char str[32];
734 snprintf(str, sizeof(str), "set yrange [0:%d]; ", 1 << n_bits);
735 str[sizeof(str) - 1] = '\0';
736 gnuplot_append(str);
740 static int write_samp_data_to_disk(int segment)
742 char devname[32];
743 const char *filename;
744 unsigned long acq_samples;
745 int i;
747 if (!nr_events[segment] || !nr_samples[segment]) {
748 fprintf(stderr, "Error: not acquired any data.\n");
749 return -TST_ERR_WRONG_ARG;
752 if (sis33dev_get_devname(curr_index, devname, sizeof(devname)) < 0) {
753 mperr("sis33dev_get_devname");
754 return -TST_ERR_SYSCALL;
756 gnuplot_init(curr_index);
757 acq_samples = 0;
758 for (i = 0; i < acq_list[segment].n_acqs; i++) {
759 if (acq_list[segment].acqs[i].nr_samples == 0)
760 continue;
761 filename = write_file(devname, &acq_list[segment], segment, i);
762 /* we don't get the error back. Assume it's SYSCALL */
763 if (filename == NULL)
764 return -TST_ERR_SYSCALL;
765 if (i == 0)
766 gnuplot_append("plot ");
767 else
768 gnuplot_append(", ");
769 gnuplot_append("'");
770 gnuplot_append(filename);
771 gnuplot_append("' with linespoints");
772 acq_samples += acq_list[segment].acqs[i].nr_samples;
774 if (acq_samples == 0)
775 fprintf(stderr, "No samples were acquired on segment %d\n", segment);
776 return 1;
779 int h_wf(struct cmd_desc *cmdd, struct atom *atoms)
781 int segment = curr_segment;
783 if (atoms == (struct atom *)VERBOSE_HELP) {
784 printf("%s [segment] - Write acquired data to a file\n"
785 "segment: segment number. Leave empty for current.\n"
786 "Note. The file will be located at /tmp/<curr_device>.ev<n>.<channel>.dat\n",
787 cmdd->name);
788 return 1;
790 ++atoms;
791 if (atoms->type == Terminator)
792 goto write_to_disk;
793 if (atoms->type != Numeric)
794 return -TST_ERR_WRONG_ARG;
795 if (atoms->val < 0 || atoms->val >= SIS33T_MAX_NR_SEGMENTS)
796 return -TST_ERR_WRONG_ARG;
797 segment = atoms->val;
799 write_to_disk:
800 return write_samp_data_to_disk(segment);
803 static void show_devices(void)
805 char value[4096];
806 int n_channels;
807 int *indexes;
808 int ndevs;
809 int i;
811 ndevs = sis33dev_get_nr_devices();
812 if (!ndevs)
813 return;
814 indexes = calloc(ndevs, sizeof(*indexes));
815 if (indexes == NULL) {
816 mperr("calloc");
817 return;
819 if (sis33dev_get_device_list(indexes, ndevs) < 0) {
820 mperr("sis33dev_get_device_list");
821 goto out;
824 for (i = 0; i < ndevs; i++) {
825 char devname[32];
826 int index = indexes[i];
828 if (index == curr_index)
829 printf("current");
830 else
831 printf("-");
833 printf("\t%2d", index);
834 if (sis33dev_get_devname(index, devname, sizeof(devname)) < 0) {
835 fprintf(stderr, "dev%d: retrieval of 'devname' failed\n", index);
836 continue;
838 printf("\t%8s", devname);
840 if (sis33dev_get_attr(index, "description", value, sizeof(value))) {
841 fprintf(stderr, "dev%d: retrieval of 'description' failed\n", index);
842 continue;
844 printf("\t%s", value);
846 n_channels = sis33dev_get_nr_subattrs(index, "channels");
847 if (n_channels < 0) {
848 fprintf(stderr, "dev%d: retrieval of 'n_channels' failed\n", index);
849 continue;
851 printf("\t%2d", n_channels);
853 if (sis33dev_get_attr(index, "n_bits", value, sizeof(value))) {
854 fprintf(stderr, "dev%d: retrieval of 'n_bits' failed\n", index);
855 continue;
857 printf("\t%2s", value);
859 printf("\n");
861 out:
862 free(indexes);
865 static int __h_device(int index)
867 char file[SIS33_PATH_MAX];
868 char devname[32];
870 if (!sis33dev_device_exists(index)) {
871 fprintf(stderr, "Device with index %d doesn't exist\n", index);
872 return -TST_ERR_WRONG_ARG;
875 if (sis33fd > 0) {
876 if (close(sis33fd))
877 mperr("close");
878 sis33fd = -1;
881 if (sis33dev_get_devname(index, devname, sizeof(devname)) < 0) {
882 mperr("sis33dev_get_devname");
883 return -TST_ERR_SYSCALL;
885 snprintf(file, sizeof(file), "/dev/%s", devname);
886 file[sizeof(file) - 1] = '\0';
887 sis33fd = open(file, O_RDWR, 0);
888 if (sis33fd < 0) {
889 mperr("open");
890 return -TST_ERR_SYSCALL;
891 } else {
892 curr_index = index;
895 return 1;
898 int h_device(struct cmd_desc *cmdd, struct atom *atoms)
900 if (atoms == (struct atom *)VERBOSE_HELP) {
901 printf("%s - Set device\n"
902 "%s - Show available devices\n"
903 "Format:\n"
904 "curr\tindex\tdev_name\tdetailed_name\tn_channels\tn_bits\n"
905 "%s [index]\n"
906 "\tindex: set device to that given by the index\n",
907 cmdd->name, cmdd->name, cmdd->name);
908 return 1;
911 ++atoms;
912 if (atoms->type == Terminator) {
913 show_devices();
914 return 1;
917 if (atoms->type != Numeric)
918 return -TST_ERR_WRONG_ARG;
920 return __h_device(atoms->val);
923 int h_device_next(struct cmd_desc *cmdd, struct atom *atoms)
925 int *indexes;
926 int ndevs;
927 int ret;
928 int i;
930 if (atoms == (struct atom *)VERBOSE_HELP) {
931 printf("%s - Set next available device\n", cmdd->name);
932 return 1;
935 ndevs = sis33dev_get_nr_devices();
936 if (!ndevs)
937 return 1;
938 indexes = calloc(ndevs, sizeof(*indexes));
939 if (indexes == NULL) {
940 mperr("calloc");
941 return -TST_ERR_SYSCALL;
943 if (sis33dev_get_device_list(indexes, ndevs) < 0) {
944 mperr("sis33dev_get_device_list");
945 ret = -TST_ERR_SYSCALL;
946 goto out;
949 for (i = 0; i < ndevs; i++) {
950 if (indexes[i] == curr_index)
951 break;
953 if (i == ndevs) {
954 fprintf(stderr, "curr_index %d not in the devices' list. Has it been removed?\n", curr_index);
955 ret = -TST_ERR_WRONG_ARG;
956 goto out;
958 if (i == ndevs - 1)
959 ret = 1;
960 else
961 ret = __h_device(indexes[i + 1]);
962 out:
963 free(indexes);
964 return ret;
967 int h_plot(struct cmd_desc *cmdd, struct atom *atoms)
969 char cmd[sizeof(gnuplot) + 128];
970 int segment = curr_segment;
971 int ret;
972 int term = 0;
974 if (atoms == (struct atom *)VERBOSE_HELP) {
975 printf("%s [segment] [term] - Plot acquired data\n"
976 "Note: the data must have previously been written to disk\n"
977 "segment: segment number (-1 for current, default)\n"
978 "term:\n"
979 "\t0: Use 'dumb' terminal. Default.\n"
980 "\t1: Use 'X11' terminal.\n",
981 cmdd->name);
982 return 1;
985 ++atoms;
986 if (atoms->type == Terminator)
987 goto plot;
988 if (atoms->type != Numeric)
989 return -TST_ERR_WRONG_ARG;
990 if (atoms->val < -1 || atoms->val >= SIS33T_MAX_NR_SEGMENTS)
991 return -TST_ERR_WRONG_ARG;
992 if (atoms->val >= 0)
993 segment = atoms->val;
995 ++atoms;
996 if (atoms->type == Numeric) {
997 if (atoms->val != 0 && atoms->val != 1) {
998 fprintf(stderr, "Invalid terminal type %d\n", atoms->val);
999 return -TST_ERR_WRONG_ARG;
1001 term = !!atoms->val;
1003 plot:
1004 /* we need the data on disk in order to plot it */
1005 ret = write_samp_data_to_disk(segment);
1006 if (ret < 0)
1007 return ret;
1008 if (gnuplot[0] == '\0') {
1009 fprintf(stderr, "No data available\n");
1010 return 1;
1013 snprintf(cmd, sizeof(cmd), "echo \"%s%s\" | gnuplot -persist",
1014 term ? "set term x11; " : "set term dumb; ", gnuplot);
1015 cmd[sizeof(cmd) - 1] = '\0';
1016 system(cmd);
1018 return 1;
1021 int h_segments(struct cmd_desc *cmdd, struct atom *atoms)
1023 if (atoms == (struct atom *)VERBOSE_HELP) {
1024 printf("%s [segment_nr] - Get/Set number of segments\n"
1025 "segment_nr: segment number to be set\n", cmdd->name);
1026 return 1;
1028 return h_uattr(atoms, "n_segments");
1031 int h_ts_divider(struct cmd_desc *cmdd, struct atom *atoms)
1033 int val;
1034 int ret;
1036 if (atoms == (struct atom *)VERBOSE_HELP) {
1037 printf("%s [value] - Get/Set event timestamping clock divider\n"
1038 "value: desired divider value\n", cmdd->name);
1039 return 1;
1041 ret = h_attr(atoms, "event_timestamping_divider");
1042 if (ret < 0)
1043 return ret;
1044 ret = sis33dev_get_attr_int(curr_index, "event_timestamping_divider_max", &val);
1045 if (ret < 0) {
1046 mperr("get_attr");
1047 return ret;
1049 printf("max: %d\n", val);
1050 return 1;
1053 int main(int argc, char *argv[], char *envp[])
1055 char file[SIS33_PATH_MAX];
1056 char devname[32];
1057 int *indexes;
1058 int ndevs;
1060 /* try to control the first device */
1061 ndevs = sis33dev_get_nr_devices();
1062 if (!ndevs)
1063 goto out;
1064 indexes = calloc(ndevs, sizeof(*indexes));
1065 if (indexes == NULL) {
1066 mperr("calloc");
1067 goto out;
1069 if (sis33dev_get_device_list(indexes, ndevs) < 0) {
1070 mperr("sis33dev_get_device_list");
1071 goto out_free;
1073 if (sis33dev_get_devname(indexes[0], devname, sizeof(devname)) < 0) {
1074 mperr("sis33dev_get_devname");
1075 goto out_free;
1077 snprintf(file, sizeof(file), "/dev/%s", devname);
1078 file[sizeof(file) - 1] = '\0';
1079 sis33fd = open(file, O_RDWR, 0);
1080 if (sis33fd < 0)
1081 mperr("open");
1082 else
1083 curr_index = indexes[0];
1084 out_free:
1085 free(indexes);
1086 out:
1087 return extest_init(argc, argv);
1090 enum _tag_cmd_id {
1091 CmdACQ = CmdUSR,
1092 CmdCANCEL,
1093 CmdCH,
1094 CmdCH_NEXT,
1095 CmdCLKSRC,
1096 CmdCLKFREQ,
1097 CmdDEVICE,
1098 CmdDEVICE_NEXT,
1099 CmdFETCH,
1100 CmdOFFSET,
1101 CmdPLOT,
1102 CmdSEGMENTS,
1103 CmdSTART,
1104 CmdSTART_AUTO,
1105 CmdSTART_DELAY,
1106 CmdSTOP,
1107 CmdSTOP_AUTO,
1108 CmdSTOP_DELAY,
1109 CmdTRIG_EXT,
1110 CmdTS_DIVIDER,
1111 CmdWF,
1112 CmdLAST
1115 struct cmd_desc user_cmds[] = {
1116 { 1, CmdACQ, "acq", "Start Acquisition", "segment nr_events ev_length [timeout_us]", 0,
1117 h_acq },
1118 { 1, CmdCANCEL, "cancel", "Cancel Acquisition", "", 0,
1119 h_cancel },
1121 { 1, CmdCH, "ch", "Get/Set Channel", "[0,n-1]", 0,
1122 h_ch },
1123 { 1, CmdCH_NEXT, "ch_next", "Next Channel", "", 0,
1124 h_ch_next },
1126 { 1, CmdCLKSRC, "clksrc", "Clock Source", "[src]", 0,
1127 h_clksrc },
1128 { 1, CmdCLKFREQ, "clkfreq", "Clock Frequency", "[Hz]", 0,
1129 h_clkfreq },
1131 { 1, CmdDEVICE, "device", "Set device", "[index]", 0,
1132 h_device },
1133 { 1, CmdDEVICE_NEXT, "device_next", "Set next device", "", 0,
1134 h_device_next },
1136 { 1, CmdFETCH, "fetch", "Fetch Acquired Data", "[segment] [timeout_us] [show_tstamps]", 0,
1137 h_fetch },
1139 { 1, CmdOFFSET, "offset", "Input Offset", "channel value", 0,
1140 h_offset },
1142 { 1, CmdPLOT, "plot", "Plot sampled data", "[segment] [term]", 0,
1143 h_plot },
1145 { 1, CmdSEGMENTS, "segments", "Get/Set number of segments", "[nr_segments]", 0,
1146 h_segments },
1148 { 1, CmdSTART, "start", "Start Sampling", "", 0,
1149 h_start },
1150 { 1, CmdSTART_AUTO, "start_auto", "Get/Set Autostart", "bool", 0,
1151 h_start_auto },
1152 { 1, CmdSTART_DELAY, "start_delay", "Start delay", "val", 0,
1153 h_start_delay },
1155 { 1, CmdSTOP, "stop", "Stop Sampling", "", 0,
1156 h_stop },
1157 { 1, CmdSTOP_AUTO, "stop_auto", "Enable Autostop", "bool", 0,
1158 h_stop_auto },
1159 { 1, CmdSTOP_DELAY, "stop_delay", "Stop delay", "val", 0,
1160 h_stop_delay },
1162 { 1, CmdTRIG_EXT, "trig_ext", "En/Disable external trigger", "bool", 0,
1163 h_trig_ext },
1165 { 1, CmdTS_DIVIDER, "ts_divider", "Get/Set the timestamp divider", "[value]", 0,
1166 h_ts_divider },
1168 { 1, CmdWF, "wf", "Write File", "[segment]", 0,
1169 h_wf },
1171 { 0, }