Module: xenomai-abe Branch: analogy Commit: 4d6520727c1c51fad59999e368061f1524de688e URL: http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=4d6520727c1c51fad59999e368061f1524de688e
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