Module: xenomai-abe
Branch: analogy
Commit: 9426be27db84fbe909e0d7375f5b811d1a2a9ae3
URL:    
http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=9426be27db84fbe909e0d7375f5b811d1a2a9ae3

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Thu Dec  2 01:00:55 2010 +0100

analogy: add a 1st version of wf_cmd_write

This program takes the waveforms created by wf_generate as standard
input. So we are able to inject specific waveforms into the output
subdevice of a board.

Warning: more parameters needs to be added
Warning: it should not be used as is

---

 src/utils/analogy/Makefile.am    |    7 +
 src/utils/analogy/wf_cmd_write.c |  483 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 490 insertions(+), 0 deletions(-)

diff --git a/src/utils/analogy/Makefile.am b/src/utils/analogy/Makefile.am
index 8e7734f..a2c3e96 100644
--- a/src/utils/analogy/Makefile.am
+++ b/src/utils/analogy/Makefile.am
@@ -3,6 +3,7 @@ sbin_PROGRAMS = analogy_config
 bin_PROGRAMS = \
        cmd_read \
        cmd_write \
+       wf_cmd_write \
        cmd_bits \
        insn_read \
        insn_write \
@@ -42,6 +43,12 @@ cmd_write_LDADD = \
        ../../skins/rtdm/librtdm.la \
        ../../skins/common/libxenomai.la
 
+wf_cmd_write_SOURCES = wf_cmd_write.c
+wf_cmd_write_LDADD = \
+       ../../drvlib/analogy/libanalogy.la \
+       ../../skins/rtdm/librtdm.la \
+       ../../skins/common/libxenomai.la
+
 cmd_bits_SOURCES = cmd_bits.c
 cmd_bits_LDADD = \
        ../../drvlib/analogy/libanalogy.la \
diff --git a/src/utils/analogy/wf_cmd_write.c b/src/utils/analogy/wf_cmd_write.c
new file mode 100644
index 0000000..38e0c29
--- /dev/null
+++ b/src/utils/analogy/wf_cmd_write.c
@@ -0,0 +1,483 @@
+/**
+ * @file
+ * Analogy for Linux, output command test program
+ *
+ * @note Copyright (C) 1997-2000 David A. Schleef <d...@schleef.org>
+ * @note Copyright (C) 2008 Alexis Berlemont <alexis.berlem...@free.fr>
+ *
+ * Xenomai is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Xenomai is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+
+#include <analogy/analogy.h>
+
+#define BUFFER_DEPTH 1024
+
+struct config {
+
+       /* Configuration parameters
+          TODO: add real_time and use_mmap*/
+
+       int verbose;
+       
+       int subd;
+       char *str_chans;
+       unsigned int *chans;
+       int chans_count;
+       char *str_ranges;
+       int scans_count;
+
+       char *filename;
+       FILE *input;
+
+       /* Analogy stuff */
+
+       a4l_desc_t dsc;
+       a4l_chinfo_t *cinfo;
+       a4l_rnginfo_t *rinfo;
+
+       /* Buffer stuff
+          TODO: add buffer depth / size (useful for mmap) */
+       void *buffer;
+
+};
+
+/* --- Options / arguments part --- */
+
+struct option options[] = {
+       {"verbose", no_argument, NULL, 'v'},
+       {"device", required_argument, NULL, 'd'},
+       {"subdevice", required_argument, NULL, 's'},
+       {"scans-count", required_argument, NULL, 'S'},
+       {"channels", required_argument, NULL, 'c'},
+       {"range", required_argument, NULL, 'c'},
+       {"help", no_argument, NULL, 'h'},
+       {0},
+};
+
+void print_usage(void)
+{
+       fprintf(stdout, "usage:\tcmd_write [OPTS]\n");
+       fprintf(stdout, "\tOPTS:\t -v, --verbose: verbose output\n");
+       fprintf(stdout,
+               "\t\t -d, --device: "
+               "device filename (analogy0, analogy1, ...)\n");
+       fprintf(stdout, "\t\t -s, --subdevice: subdevice index\n");
+       fprintf(stdout, "\t\t -S, --scans-count: count of scan to perform\n");
+       fprintf(stdout, 
+               "\t\t -c, --channels: channels to use "
+               "<i,j,...> (ex.: -c 0,1)\n");
+       fprintf(stdout, 
+               "\t\t -R, --range: range to use "
+               "<min,max,unit> (ex.: -R 0,1,V)\n");
+       fprintf(stdout, "\t\t -h, --help: print this help\n");
+}
+
+/* --- Configuration related stuff --- */
+
+int init_dsc_config(struct config *cfg)
+{
+       int err = 0;
+
+       /* Here we have to open the Analogy device file */
+       err = a4l_open(&cfg->dsc, cfg->filename);
+       if (err < 0) {
+               fprintf(stderr,
+                       "cmd_write: a4l_open %s failed (ret=%d)\n",
+                       cfg->filename, err);
+               goto out;
+       }
+
+       /* Allocate a buffer so as to get more info (subd, chan, rng) */
+       cfg->dsc.sbdata = malloc(cfg->dsc.sbsize);
+       if (!cfg->dsc.sbdata) {
+               err = -ENOMEM;
+               fprintf(stderr, "cmd_write: malloc failed\n");
+               goto out;               
+       }
+
+       /* Get these data */
+       err = a4l_fill_desc(&cfg->dsc);
+       if (err < 0) {
+               fprintf(stderr,
+                       "cmd_write: a4l_get_desc failed (err=%d)\n", err);
+               goto out;
+       }
+
+out:
+       if (err < 0 && cfg->buffer) 
+               free(cfg->buffer);
+
+       return err;
+}
+
+int init_chans_config(struct config *cfg)
+{
+       int err = 0;
+       int len, offset;
+       char *str_chans = cfg->str_chans;
+
+       /* Recover the number of arguments */
+       do {
+               cfg->chans_count++;
+               len = strlen(str_chans);
+               offset = strcspn(str_chans, ",");
+               str_chans += offset + 1;
+       } while (len != offset);
+
+       cfg->chans = malloc(cfg->chans_count * sizeof(int));
+       if (!cfg->chans) {
+               err = -ENOMEM;
+               fprintf(stderr, "cmd_write: basic allocation failed\n");
+               goto out;
+       }
+
+       /* A little reinitialization step and... */
+       str_chans = cfg->str_chans;
+       cfg->chans_count = 0;
+       
+       /* ...we recover the channels */
+       do {
+               cfg->chans_count++;
+               len = strlen(str_chans);
+               offset = strcspn(str_chans, ",");
+               if (sscanf(str_chans, 
+                          "%u", &cfg->chans[cfg->chans_count - 1]) == 0) {
+                       err = -EINVAL;
+                       fprintf(stderr, "cmd_write: bad channels argument\n");
+                       goto out;
+               }
+               str_chans += offset + 1;
+       } while (len != offset);
+
+       /* We consider in this program that all the channels are
+          identical so we took a pointer to a chinfo structure for only
+          one of them */
+       err = a4l_get_chinfo(&cfg->dsc, cfg->subd, cfg->chans[0], &cfg->cinfo);
+       if (err < 0) {
+               fprintf(stderr, 
+                       "cmd_write: channel info "
+                       "recovery failed (err=%d)\n", err);
+       }
+
+out:
+       if (err < 0 && cfg->chans)
+               free(cfg->chans);
+
+       return err;
+}
+
+int init_range_config(struct config *cfg)
+{
+       int index = 0, err = 0;
+       int len, offset;
+       int limits[2];
+       unsigned long unit;
+       char * str_ranges = cfg->str_ranges;
+
+       /* Convert min and max values */
+       do {
+               len = strlen(str_ranges);
+               offset = strcspn(str_ranges, ",");
+               if (sscanf(str_ranges, "%d", &limits[index++]) == 0) {
+                       err = -EINVAL;
+                       fprintf(stderr, "cmd_write: bad range min/max value\n");
+                       goto out;
+               }
+               str_ranges += offset + 1;
+       } while (len != offset && index < 2);
+
+       /* Find the unit among Volt, Ampere, external or no unit */
+       if (!strcmp(str_ranges, "V"))
+               unit = A4L_RNG_VOLT_UNIT;
+       else if (!strcmp(str_ranges, "mA"))
+               unit = A4L_RNG_MAMP_UNIT;
+       else if (!strcmp(str_ranges, "ext"))
+               unit = A4L_RNG_EXT_UNIT;
+       else if (!strlen(str_ranges))
+               unit = A4L_RNG_NO_UNIT;
+       else {
+               err = -EINVAL;
+               fprintf(stderr, "cmd_write: bad range unit value\n");
+               goto out;
+       }
+
+       err = a4l_find_range(&cfg->dsc, 
+                                   cfg->subd, 
+                                   cfg->chans[0], 
+                                   unit, limits[0], limits[1], &cfg->rinfo);
+       if (err < 0) {
+               fprintf(stderr, 
+                       "cmd_write: no range found for %s\n", cfg->str_ranges);
+       } else 
+               err = 0;
+
+out:
+       return err;
+}
+
+void print_config(struct config *cfg)
+{
+       printf("cmd_write configuration:\n");
+       printf("\tRTDM device name: %s\n", cfg->filename);
+       printf("\tSubdevice index: %d\n", cfg->subd);
+       printf("\tSelected channels: %s\n", cfg->str_chans);
+       printf("\tSelected range: %s\n", cfg->str_ranges);
+       printf("\tScans count: %d\n", cfg->scans_count);
+}
+
+void cleanup_config(struct config *cfg)
+{
+       if (cfg->buffer)
+               free(cfg->buffer);
+
+       if (cfg->dsc.sbdata)
+               free(cfg->dsc.sbdata);
+
+       if (cfg->dsc.fd != -1)
+               a4l_close(&cfg->dsc);
+}
+
+int init_config(struct config *cfg, int argc, char *argv[])
+{
+       int scan_size, err = 0;
+
+       memset(cfg, 0, sizeof(struct config));
+       cfg->str_chans = "0,1";
+       cfg->str_chans = "0,5,V";
+       cfg->filename = "analogy0";     
+       cfg->input = stdin;
+       cfg->dsc.fd = -1;
+
+       while ((err = getopt_long(argc, 
+                                 argv, "vd:s:S:c:R:h", options, NULL)) >= 0) {
+               switch (err) {
+               case 'v':
+                       cfg->verbose = 1;
+                       break;
+               case 'd':
+                       cfg->filename = optarg;
+                       break;
+               case 's':
+                       cfg->subd = strtoul(optarg, NULL, 0);
+                       break;
+               case 'S':
+                       cfg->scans_count = strtoul(optarg, NULL, 0);
+                       break;
+               case 'c':
+                       cfg->str_chans = optarg;
+                       break;
+               case 'R':
+                       cfg->str_ranges = optarg;
+                       break;
+               case 'h':
+               default:
+                       print_usage();
+                       return -EINVAL;
+               };
+       }
+
+       /* If stdin is a terminal, we will not be able to read binary
+          data from it */
+       if (isatty(fileno(cfg->input))) {
+               fprintf(stderr, "cmd_write: stdin cannot be a terminal\n");
+               return -EINVAL;
+       }
+
+       /* Open the analogy device and retrieve pointers on the info
+          structures */
+       err = init_dsc_config(cfg);
+       if (err < 0)
+               goto out;
+
+       /* Parse the channel option so as to know which and how many
+          channels will be used */
+       err = init_chans_config(cfg);
+       if (err < 0)
+               goto out;
+
+       /* Find out the most suitable range for the acquisition */
+       err = init_range_config(cfg);
+       if (err < 0)
+               goto out;
+
+       /* Compute the width of a scan */
+       scan_size = cfg->chans_count * a4l_sizeof_chan(cfg->cinfo);
+       if (scan_size < 0) {
+               fprintf(stderr,
+                       "cmd_write: a4l_sizeof_chan failed (err=%d)\n", err);
+               goto out;               
+       }
+
+       /* Allocate a temporary buffer
+          TODO: implement mmap */
+       cfg->buffer = malloc(BUFFER_DEPTH * scan_size);
+       if (!cfg->buffer) {
+               err = -ENOMEM;
+               fprintf(stderr, "cmd_write: malloc failed\n");
+               goto out;
+       }
+       
+out:
+
+       if (err < 0)
+               cleanup_config(cfg);
+
+       return err;
+}
+
+/* --- Processing functions --- */
+
+int process_stdin(struct config *cfg)
+{
+       int err = 0, filled = 0;
+
+       /* The return value of a4l_sizeof_chan() was already
+       controlled in init_config so no need to do it twice */
+       int chan_size = a4l_sizeof_chan(cfg->cinfo);
+       int scan_size = cfg->chans_count * chan_size;
+
+       while (filled < BUFFER_DEPTH) {
+
+               int i;
+               double value;
+               char tmp[128];
+
+               /* Data from stdin are supposed to be double values
+                  coming from wf_generate... */
+               err = fread(&value, sizeof(double), 1, cfg->input);
+               if (err != 0 && !feof(cfg->input)) {
+                       err = -errno;
+                       fprintf(stderr, 
+                               "cmd_write: stdin IO error (err=%d)\n", err);
+                       goto out;
+               } else if (err == 0 && feof(cfg->input))
+                       goto out;
+               
+               /* ...and these data are just for one channel... */
+               err = a4l_dtoraw(cfg->cinfo, cfg->rinfo, tmp, &value, 1);
+               if (err < 0) {
+                       fprintf(stderr, 
+                               "cmd_write: conversion "
+                               "from stdin failed (err=%d)\n", err);
+                       goto out;                       
+               }
+
+               /* ...so we have to duplicate the conversion if many
+                  channels are selected for the acquisition */
+               for (i = 0; i < cfg->chans_count; i++)
+                       memcpy(cfg->buffer + 
+                              filled * scan_size + i * chan_size, 
+                              tmp, chan_size);
+
+               filled ++;
+       }
+
+       if (filled) {
+               err = a4l_async_write(&cfg->dsc, 
+                                     cfg->buffer, 
+                                     filled * scan_size, A4L_INFINITE);
+               if (err < 0)
+                       fprintf(stderr, 
+                               "cmd_write: a4l_async_write failed (err=%d)\n",
+                               err);
+       }
+       
+out:
+       return err;
+}
+
+int init_acquisition(struct config *cfg)
+{
+       int err = 0;
+
+       a4l_cmd_t cmd = {
+               .idx_subd = cfg->subd,
+               .flags = 0,
+               .start_src = TRIG_INT,
+               .start_arg = 0,
+               .scan_begin_src = TRIG_TIMER,
+               .scan_begin_arg = 2000000, /* in ns */
+               .convert_src = TRIG_NOW,
+               .convert_arg = 0,
+               .scan_end_src = TRIG_COUNT,
+               .scan_end_arg = cfg->chans_count,
+               .stop_src = TRIG_COUNT,
+               .stop_arg = cfg->scans_count,
+               .nb_chan = cfg->chans_count,
+               .chan_descs = cfg->chans
+       };
+
+       a4l_insn_t insn = {
+               .type = A4L_INSN_INTTRIG,
+               .idx_subd = cfg->subd,
+               .data_size = 0,
+       };
+
+       /* Cancel any former command which might be in progress */
+       a4l_snd_cancel(&cfg->dsc, cfg->subd);
+
+       /* Send the command so as to initialize the asynchronous
+          acquisition */
+       err = a4l_snd_command(&cfg->dsc, &cmd);
+       if (err < 0) {
+               fprintf(stderr, 
+                       "cmd_write: a4l_snd_command failed (err=%d)\n", err);
+               goto out;
+       }
+
+       /* Fill the asynchronous buffer with data
+          TODO: the amount of data to be prefilled should be configured */
+       err = process_stdin(cfg);
+       if (err < 0)
+               goto out;
+
+       /* Trigger the start of the output device feeding  */
+       err = a4l_snd_insn(&cfg->dsc, &insn);
+
+out:
+       return err;
+}
+
+int main(int argc, char *argv[])
+{
+       int err = 0;
+       struct config cfg;
+
+       err = init_config(&cfg, argc, argv);
+       if (err < 0)
+               goto out;
+
+       if (cfg.verbose)
+               print_config(&cfg);
+
+       err = init_acquisition(&cfg);
+       if (err < 0)
+               goto out;
+
+       while ((err = process_stdin(&cfg)) == 0);
+
+out:
+       cleanup_config(&cfg);
+       
+       return err;
+}


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to