On 30/05/10 18:14, Ettore Pedretti wrote:
> Do you have any example similar to ao_waveform.c I could try to modify
> for my application? That would be a start. I have been unsuccessfully
> searching the threads for something vaguely similar.

Hi Ettore,

I'm attaching two programs I wrote to generate waveforms with analogy.

The first, analogy-waveform, generates the points describing the
waveform in a buffer and keeps feeding the DAC with data from this
buffer in a circular way.

The second, analogy-phasemod, produces instead a phase modulated sine
wave. It would be much more complex to use the same technique, therefore
I continuously compute new data points.

I hope those examples will be useful to you.

Cheers,
-- 
Daniele

/* Use an analog output subdevice with an asynchronous command to
 * generate a phase modulated sine wave. */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#include <analogy/analogy.h>

#define DEBUG(frmt, args...) fprintf(stderr, "%s:%d:%s:DEBUG: "frmt"\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args)
#define ERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt"\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args)
#define PERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt": %s\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args, strerror(errno))

#ifndef PI
#define PI 3.14159265358979323846
#endif

#define WAVEFORM_SINE           1
#define WAVEFORM_SAWTOOTH       2
#define WAVEFORM_TRIANGULAR     3
#define WAVEFORM_STEPS          4

static int analogy_internal_trigger(a4l_desc_t *dsc, unsigned int subdevice, 
unsigned int num)
{
     a4l_insn_t insn;
     unsigned int data[1];

     memset(&insn, 0, sizeof(insn));
     insn.type = A4L_INSN_INTTRIG;
     insn.idx_subd = subdevice;
     insn.data_size = 1;
     insn.data = data;

     data[0] = num;

     return a4l_snd_insn(dsc, &insn);
}

#if 0
static int analogy_find_range(a4l_desc_t *dsc, unsigned int idx_subd, unsigned 
int idx_chan, 
                              unsigned long unit, double min, double max, 
a4l_rnginfo_t **rng)
{
     a4l_chinfo_t *chinfo;
     a4l_rnginfo_t *rnginfo;
     int i, ret;
     long lmin, lmax;
     unsigned int idx_rng = -ENOENT;

     /* initializes variables */
     lmin = (long)(min * A4L_RNG_FACTOR);
     lmax = (long)(max * A4L_RNG_FACTOR);
     if (rng != NULL)
          *rng = NULL;

     /* retrieves the ranges count */
     ret = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chinfo);
     if (ret < 0)
          return ret;

     for (i = 0; i < chinfo->nb_rng; i++) {

          ret = a4l_get_rnginfo(dsc, idx_subd, idx_chan, i, &rnginfo);
          if (ret < 0)
               return ret;

          if (A4L_RNG_UNIT(rnginfo->flags) == unit &&
              rnginfo->min <= lmin && rnginfo->max >= lmax) {

               idx_rng = i;
               if (rng != NULL)
                    *rng = rnginfo;

          }
     }

     return idx_rng;
}
#endif

typedef struct _waveform {
     int kind;          /* waveform kind */
     double frequency;  /* waveform frequency */
     double amplitude;  /* peak-to-peak amplitude */
     double offset;     /* offset */
} waveform_t;

typedef struct _options {
     char *filename;
     int subdevice;
     int channel;
     int nchan;
     int aref;
     int range;
     int unit;
     int freq;
     waveform_t *waveform;
} options_t;

#define FILENAME "analogy0"

void init_options(options_t *options)
{
     memset(options, 0, sizeof(options_t));
     options->filename = FILENAME;
     options->subdevice = -1;
     options->channel = 0;
     options->nchan = 1;
     options->aref = AREF_GROUND;
     options->range = -1;
     /* options->unit = A4L_RNG_VOLT_UNIT; bug in analogy */
     options->unit = A4L_RNG_NO_UNIT;
     options->freq = 100000.0;
}

void init_waveform(waveform_t *waveform)
{
     memset(waveform, 0, sizeof(waveform_t));
     waveform->kind = WAVEFORM_SINE;
     waveform->amplitude = 1.0;
     waveform->offset = 0.0;
     waveform->frequency = 1000.0;
}

int parse_options(options_t *options, waveform_t *waveform, int argc, char 
**argv)
{
     static struct option opts[] = {
          { "device", 1, 0, 'd' },
          { "subdevice", 1, 0, 's' },
          { "channel", 1, 0, 'c' },
          { "aref", 1, 0, 'a' },
          { "range", 1, 0, 'r' },
          { "frequency", 1, 0, 'f' },
          { "waveform", 1, 0, 'w' },
          { "offset", 1, 0, 'o' },
          { "amplitude", 1, 0, 'a' },
          { 0, 0, 0, 0 },
     };

     while (1) {
          int index = 0;
          char c = getopt_long(argc, argv, "", opts, &index);
          
          if (c == -1)
               break;

          switch (c) {
          case 'd':
               options->filename = optarg;
               break;
          case 's':
               options->subdevice = strtoul(optarg, NULL, 0);
               break;
          case 'c':
               options->channel = strtoul(optarg, NULL, 0);
               break;
          case 'a':
               if (strcmp(optarg, "diff") == 0) {
                    options->aref = AREF_DIFF;
                    break;
               }
               if (strcmp(optarg, "ground") == 0) {
                    options->aref = AREF_GROUND;
                    break;
               }
               if (strcmp(optarg, "other") == 0) {
                    options->aref = AREF_OTHER;
                    break;
               }
               if (strcmp(optarg, "common") == 0) {
                    options->aref = AREF_COMMON;
                    break;
               }
               fprintf(stderr, "unknow analog reference\n");
               exit(-1);
               break;
          case 'r':
               options->range = strtoul(optarg, NULL, 0);
               break;
          case 'w':
               if (strcmp(optarg, "sin") == 0) {
                    waveform->kind = WAVEFORM_SINE;
                    break;
               }
               if (strcmp(optarg, "saw") == 0) {
                    waveform->kind = WAVEFORM_SAWTOOTH;
                    break;
               }
               if (strcmp(optarg, "tri") == 0) {
                    waveform->kind = WAVEFORM_TRIANGULAR;
                    break;
               }
               if (strcmp(optarg, "ste") == 0) {
                    waveform->kind = WAVEFORM_STEPS;
                    break;
               }
               fprintf(stderr, "unknow waveform\n");
               exit(-1);
               break;
               
          case 'o':
               waveform->offset = strtod(optarg, NULL);
               break;

          case 'f':
               waveform->frequency = strtod(optarg, NULL);
               break;

          default:
               fprintf(stderr, "unknown option\n");
               exit(-1);
          }
     }

     if (optind < argc) {
          /* amplitude */
          waveform->amplitude = strtod(argv[optind++], NULL);
     }

     DEBUG("frequency=%f", waveform->frequency);
     DEBUG("amplitude=%f", waveform->amplitude);
     DEBUG("offset=%f", waveform->offset);

     return argc;
}

typedef struct _generator {
     int kind;
     double frequency;  /* waveform frequency */
     double amplitude;  /* peak-to-peak amplitude in DAC units */
     double offset;     /* offset in DAC units */
     double dt;
     double t;          /* time */
} generator_t;

void generate(generator_t *gen, unsigned short *buffer, unsigned long size)
{
     double phase = 0;
     unsigned long samples = size / sizeof(unsigned short);
     //DEBUG("generate start=%p len=%ld samples=%ld", buffer, size, samples);
     for (unsigned long i = 0; i < samples; i++) {
          //if (i < 100) {
          //     buffer[i] = gen->offset;
          //} else {
               phase = sin(2*PI * gen->t);
               buffer[i] = gen->amplitude * cos(2*PI * gen->frequency * gen->t 
+ phase) + gen->offset;
               gen->t += gen->dt;
               //}
          //fprintf(stdout, "%d\n", buffer[i]);
     }
}

int main(int argc, char **argv)
{
     unsigned int chanlist[16];

     int ret;
     options_t options;
     init_options(&options);

     waveform_t waveform;
     init_waveform(&waveform);

     parse_options(&options, &waveform, argc, argv);

     /* open device */
     int rv;
     a4l_desc_t dsc;
     rv = a4l_open(&dsc, options.filename);
     if (rv < 0) {
          fprintf(stderr, "error opening %s\n", options.filename);
          return -1;
     }

     DEBUG("device=%s fd=%d", options.filename, dsc.fd);
     DEBUG("subdevices=%d", dsc.nb_subd);
     DEBUG("read subdevice=%d", dsc.idx_read_subd);
     DEBUG("write subdevice=%d", dsc.idx_write_subd);

     /* subdevice */
     if (options.subdevice < 0) {
          options.subdevice = dsc.idx_write_subd;
     }
     DEBUG("subdevice=%d", options.subdevice);

     /* allocate additional informations buffer */
     dsc.sbdata = malloc(dsc.sbsize);
     if (dsc.sbdata == NULL) {
          ERROR("malloc");
          return -ENOMEM;
     }

     /* get additional informations */
     rv = a4l_fill_desc(&dsc);
     if (rv < 0) {
          ERROR("analogy fill desc");
          goto out;
     }

     /* get channel infos */
     a4l_chinfo_t *info;
     rv = a4l_get_chinfo(&dsc, options.subdevice, options.channel, &info);
     if (rv < 0) {
          ERROR("analogy get chinfo");
          goto out;
     }

     /* get range */
     double min = waveform.offset - waveform.amplitude;
     double max = waveform.offset + waveform.amplitude;
     if (options.range < 0) {
          options.range = a4l_find_range(&dsc, options.subdevice, 
options.channel, options.unit, min, max, NULL);
          DEBUG("range=%d", options.range);
     }
     a4l_rnginfo_t *range;
     rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, 
options.range, &range);
     if (rv < 0) {
          ERROR("analogy get rngnfo");
          goto out;
     }

     generator_t generator;
     memset(&generator, 0, sizeof(generator));
     generator.kind = waveform.kind;
     generator.frequency = waveform.frequency;
     generator.dt = 1.0 / options.freq;

     /* physical to sample */
     unsigned short value = 0;
     double raw = 0.0;
     a4l_dtoraw(info, range, &value, &raw, 1);
     double zero = value;
     
     a4l_dtoraw(info, range, &value, &(waveform.amplitude), 1);
     generator.amplitude = value - zero;

     a4l_dtoraw(info, range, &value, &(waveform.offset), 1);
     generator.offset = value;
     
     DEBUG("amplitude=%f", generator.amplitude);
     DEBUG("offset=%f", generator.offset);

     /* setup command */
     a4l_cmd_t cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.idx_subd = options.subdevice;
     cmd.flags = A4L_CMD_WRITE;
     cmd.start_src = TRIG_INT;
     cmd.start_arg = 0;
     cmd.scan_begin_src = TRIG_TIMER;
     cmd.scan_begin_arg = 1e9 / options.freq;
     cmd.convert_src = TRIG_NOW;
     cmd.convert_arg = 0;
     cmd.scan_end_src = TRIG_COUNT;
     cmd.scan_end_arg = options.nchan;
     cmd.stop_src = TRIG_NONE;
     cmd.stop_arg = 0;
     cmd.nb_chan = 1,
     cmd.chan_descs = chanlist;

     /* setup channel description */
     chanlist[0] = PACK(options.channel, options.range, options.aref);
               
     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);

     /* get buffer size to map */
     unsigned long bufsize;
     rv = a4l_get_bufsize(&dsc, options.subdevice, &bufsize);
     if (rv < 0) {
          ERROR("analogy get bufsize");
          goto out;
     }
     DEBUG("buffer size=%lu", bufsize);

     /* map analog input subdevice buffer */
     void *map = NULL;
     rv = a4l_mmap(&dsc, options.subdevice, bufsize, &map);
     if (rv < 0) {
          ERROR("analogy mmap");
          goto out;
     }

     /* send the command to the output device */
     rv = a4l_snd_command(&dsc, &cmd);
     if (rv < 0) {
          ERROR("analogy snd command");
          goto out;
     }

     /* preload output buffer */
     generate(&generator, map, bufsize);

     /* update buffer state */
     unsigned long none;
     rv = a4l_mark_bufrw(&dsc, options.subdevice, bufsize, &none);
     if (rv < 0) {
          ERROR("analogy bufrw");
          goto out;
     }
     
     /* send internal trigger */
     ret = analogy_internal_trigger(&dsc, options.subdevice, 0);
     if (ret < 0) {
          ERROR("comedi_internal_trigger\n");
          exit(1);
     }

     /* keep updating the output buffer */
     unsigned long front = 0;
     unsigned long cnt = 0;
     while (1) {
          /* wait for device to empty buffer */
          rv = a4l_poll(&dsc, options.subdevice, A4L_INFINITE);
          if (rv < 0) {
               ERROR("analogy poll");
               goto out;
          }
          front = (unsigned long)rv;

          /* handle ring buffer wrap around */
          unsigned long tmp = front;
          unsigned long towrite;
          while (tmp) {
               if (((cnt % bufsize) + tmp) > bufsize) {
                    towrite = bufsize - (cnt % bufsize);
               } else {
                    towrite = tmp;
               }

               /* generate new data */
               generate(&generator, map + (cnt % bufsize), towrite);
               tmp -= towrite;

               /* update counter */
               cnt += towrite;
          }
                  
          /* update buffer state */
          rv = a4l_mark_bufrw(&dsc, options.subdevice, front, &front);
          if (rv < 0) {
               ERROR("analogy bufrw");
               goto out;
          }
     }

out:
     /* free buffer */
     if (dsc.sbdata != NULL)
          free(dsc.sbdata);

     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);
     
     /* close file descriptor */
     a4l_close(&dsc);
     
     return rv;
}
/* Use an analog output subdevice with an asynchronous command to
 * generate a waveform.
 *
 * A 32-bit accumulator is incremented by a phase factor which is the
 * amount that the generator advances each time step.  The accumulator
 * is then shifted right by 16 bits to get a 16 bit offset into a
 * lookup table.  The value in the lookup table at that offset is then
 * put into a buffer for output to the DAC.
 */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#include <analogy/analogy.h>

#define DEBUG(frmt, args...) fprintf(stderr, "%s:%d:%s:DEBUG: "frmt"\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args)
#define ERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt"\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args)
#define PERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt": %s\n" , 
__FILE__, __LINE__, __FUNCTION__, ##args, strerror(errno))

#ifndef PI
#define PI 3.14159265358979323846
#endif

#define WAVEFORM_SINE           1
#define WAVEFORM_SAWTOOTH       2
#define WAVEFORM_TRIANGULAR     3
#define WAVEFORM_STEPS          4

static int analogy_internal_trigger(a4l_desc_t *dsc, unsigned int subdevice, 
unsigned int num)
{
     a4l_insn_t insn;
     unsigned int data[1];

     memset(&insn, 0, sizeof(insn));
     insn.type = A4L_INSN_INTTRIG;
     insn.idx_subd = subdevice;
     insn.data_size = 1;
     insn.data = data;

     data[0] = num;

     return a4l_snd_insn(dsc, &insn);
}

static int analogy_find_range(a4l_desc_t *dsc, unsigned int idx_subd, unsigned 
int idx_chan, 
                              unsigned long unit, double min, double max, 
a4l_rnginfo_t **rng)
{
     a4l_chinfo_t *chinfo;
     a4l_rnginfo_t *rnginfo;
     int i, ret;
     long lmin, lmax;
     unsigned int idx_rng = -1;

     /* initializes variables */
     lmin = (long)(min * A4L_RNG_FACTOR);
     lmax = (long)(max * A4L_RNG_FACTOR);
     if (rng != NULL)
          *rng = NULL;

     /* retrieves the ranges count */
     ret = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chinfo);
     if (ret < 0)
          return ret;

     for (i = 0; i < chinfo->nb_rng; i++) {

          ret = a4l_get_rnginfo(dsc, idx_subd, idx_chan, i, &rnginfo);
          if (ret < 0)
               return ret;

          if (A4L_RNG_UNIT(rnginfo->flags) == unit &&
              rnginfo->min <= lmin && rnginfo->max >= lmax) {

               idx_rng = i;
               if (rng != NULL)
                    *rng = rnginfo;

          }
     }

     return idx_rng;
}

typedef struct _waveform {
     int kind;          /* waveform kind */
     double frequency;  /* waveform frequency */
     double amplitude;  /* peak-to-peak amplitude */
     double offset;     /* offset */
} waveform_t;

typedef struct _options {
     char *filename;
     int subdevice;
     int channel;
     int nchan;
     int aref;
     int range;
     int unit;
     int freq;
     waveform_t *waveform;
} options_t;

#define FILENAME "analogy0"

void init_options(options_t *options)
{
     memset(options, 0, sizeof(options_t));
     options->filename = FILENAME;
     options->subdevice = -1;
     options->channel = 0;
     options->nchan = 1;
     options->aref = AREF_GROUND;
     options->range = -1;
     /* options->unit = A4L_RNG_VOLT_UNIT; bug in analogy */
     options->unit = A4L_RNG_NO_UNIT;
     options->freq = 100000.0;
}

void init_waveform(waveform_t *waveform)
{
     memset(waveform, 0, sizeof(waveform_t));
     waveform->kind = WAVEFORM_SINE;
     waveform->amplitude = 1.0;
     waveform->offset = 0.0;
     waveform->frequency = 10.0;
}

int parse_options(options_t *options, waveform_t *waveform, int argc, char 
**argv)
{
     static struct option opts[] = {
          { "device", 1, 0, 'd' },
          { "subdevice", 1, 0, 's' },
          { "channel", 1, 0, 'c' },
          { "aref", 1, 0, 'a' },
          { "range", 1, 0, 'r' },
          { "frequency", 1, 0, 'f' },
          { "waveform", 1, 0, 'w' },
          { "offset", 1, 0, 'o' },
          { "amplitude", 1, 0, 'a' },
          { 0, 0, 0, 0 },
     };

     while (1) {
          int index = 0;
          char c = getopt_long(argc, argv, "", opts, &index);
          
          if (c == -1)
               break;

          switch (c) {
          case 'd':
               options->filename = optarg;
               break;
          case 's':
               options->subdevice = strtoul(optarg, NULL, 0);
               break;
          case 'c':
               options->channel = strtoul(optarg, NULL, 0);
               break;
          case 'a':
               if (strcmp(optarg, "diff") == 0) {
                    options->aref = AREF_DIFF;
                    break;
               }
               if (strcmp(optarg, "ground") == 0) {
                    options->aref = AREF_GROUND;
                    break;
               }
               if (strcmp(optarg, "other") == 0) {
                    options->aref = AREF_OTHER;
                    break;
               }
               if (strcmp(optarg, "common") == 0) {
                    options->aref = AREF_COMMON;
                    break;
               }
               fprintf(stderr, "unknow analog reference\n");
               exit(-1);
               break;
          case 'r':
               options->range = strtoul(optarg, NULL, 0);
               break;
          case 'w':
               if (strcmp(optarg, "sin") == 0) {
                    waveform->kind = WAVEFORM_SINE;
                    break;
               }
               if (strcmp(optarg, "saw") == 0) {
                    waveform->kind = WAVEFORM_SAWTOOTH;
                    break;
               }
               if (strcmp(optarg, "tri") == 0) {
                    waveform->kind = WAVEFORM_TRIANGULAR;
                    break;
               }
               if (strcmp(optarg, "ste") == 0) {
                    waveform->kind = WAVEFORM_STEPS;
                    break;
               }
               fprintf(stderr, "unknow waveform\n");
               exit(-1);
               break;
               
          case 'o':
               waveform->offset = strtod(optarg, NULL);
               break;

          case 'f':
               waveform->frequency = strtod(optarg, NULL);
               break;

          default:
               fprintf(stderr, "unknown option\n");
               exit(-1);
          }
     }

     if (optind < argc) {
          /* amplitude */
          waveform->amplitude = strtod(argv[optind++], NULL);
     }

     fprintf(stderr, "amplitude=%f\n", waveform->amplitude);
     fprintf(stderr, "offset=%f\n", waveform->offset);

     return argc;
}

#define WAVEFORMSHIFT 16
#define WAVEFORMLEN   (1 << WAVEFORMSHIFT)
#define WAVEFORMMASK  (WAVEFORMLEN - 1)

typedef struct _dds {
     int kind;
     double frequency;  /* waveform frequency */
     double amplitude;  /* peak-to-peak amplitude in DAC units */
     double offset;     /* offset in DAC units */
     
     unsigned int adder;
     unsigned int acc;
     sampl_t waveform[WAVEFORMLEN];
} dds_t;

void dds_init_sine(dds_t *dds)
{
     for (int i = 0; i < WAVEFORMLEN ; i++) {
          dds->waveform[i] = rint(dds->offset + 0.5 * dds->amplitude * 
cos(i*2*PI/(WAVEFORMLEN-1)));
     }
}

void dds_init_sawtooth(dds_t *dds)
{
     for (int i = 0; i < WAVEFORMLEN; i++) {
          dds->waveform[i] = rint(dds->offset + dds->amplitude * 
((double)i)/(WAVEFORMLEN-1));
          //fprintf(stdout, "%d %f %d\n", i, ((double)i)/(WAVEFORMLEN-1), 
dds->waveform[i]);
     }
     //fflush(stdout);
}

void dds_init_triangular(dds_t *dds)
{
     fprintf(stderr, "here\n");
     int i = 0;
     for ( ; i < WAVEFORMLEN/2; i++) {
          dds->waveform[i] = rint(dds->offset + dds->amplitude * 
((double)i)/WAVEFORMLEN*2);
          //fprintf(stdout, "%d %d\n", i, dds->waveform[i]);
     }
     for ( ; i < WAVEFORMLEN; i++) { 
          dds->waveform[i] = rint(dds->offset + 2.0 * dds->amplitude - 
dds->amplitude * ((double)i)/WAVEFORMLEN*2);
          //fprintf(stdout, "%d %d\n", i, dds->waveform[i]);
     }
     //fflush(stdout);
}

void dds_init_steps(dds_t *dds)
{
     int i = 0;
     for ( ; i < WAVEFORMLEN/2; i++) {
          dds->waveform[i] = rint(dds->offset + dds->amplitude * 
(i*10/WAVEFORMLEN*2)/10);
          //printf("%d %d\n", i, dds->waveform[i]);
     }
     for ( ; i < WAVEFORMLEN; i++) { 
          dds->waveform[i] = rint(dds->offset + 2.0 * dds->amplitude - 
dds->amplitude * (i*10/WAVEFORMLEN*2)/10);
     }
     //fflush(stdout);
}

void dds_init(dds_t *dds, double frequency)
{
     fprintf(stderr, "initialise waveform table\n");
     dds->acc = 0;
     dds->adder = dds->frequency / frequency * (1 << 16) * (1 << WAVEFORMSHIFT);
     //fprintf(stderr, "adder=%12d\n", dds->adder);
     switch (dds->kind) {
     case WAVEFORM_SINE:
          dds_init_sine(dds);
          break;
     case WAVEFORM_SAWTOOTH:
          dds_init_sawtooth(dds);
          break;
     case WAVEFORM_TRIANGULAR:
          dds_init_triangular(dds);
          break;
     case WAVEFORM_STEPS:
          dds_init_steps(dds);
          break;
     }
     fprintf(stderr, "done\n");
}

void dds_output(dds_t *dds, sampl_t *buf, int n)
{
     sampl_t *p = buf;
     
     int ii;

     for (int i = 0; i < n; i++) {
          ii = (dds->acc >> 16) & WAVEFORMMASK;
          *p = dds->waveform[(dds->acc >> 16) & WAVEFORMMASK];
          //fprintf(stdout, "%d %d\n", ii, *p);
          p++;
          dds->acc += dds->adder;
     }
     //fflush(stdout);
}

/* chunks size */
#define BUFLEN 0x8000
sampl_t data[BUFLEN];

int main(int argc, char **argv)
{
     int n, m;
     int total = 0;
     unsigned int chanlist[16];

     int ret;
     options_t options;
     init_options(&options);

     waveform_t waveform;
     init_waveform(&waveform);

     parse_options(&options, &waveform, argc, argv);

     /* open device */
     int rv;
     a4l_desc_t dsc;
     rv = a4l_open(&dsc, options.filename);
     if (rv < 0) {
          fprintf(stderr, "error opening %s\n", options.filename);
          return -1;
     }

     DEBUG("device=%s fd=%d", options.filename, dsc.fd);
     DEBUG("subdevices=%d", dsc.nb_subd);
     DEBUG("read subdevice=%d", dsc.idx_read_subd);
     DEBUG("write subdevice=%d", dsc.idx_write_subd);
     DEBUG("sbsize=%d", dsc.sbsize);

     /* subdevice */
     if (options.subdevice < 0) {
          options.subdevice = dsc.idx_write_subd;
     }
     DEBUG("subdevice=%d", options.subdevice);

     /* allocate additional informations buffer */
     dsc.sbdata = malloc(dsc.sbsize);
     if (dsc.sbdata == NULL) {
          ERROR("malloc");
          return -ENOMEM;
     }

     /* get additional informations */
     rv = a4l_fill_desc(&dsc);
     if (rv < 0) {
          ERROR("analogy fill desc");
          goto out;
     }

     a4l_chinfo_t *info;
     rv = a4l_get_chinfo(&dsc, options.subdevice, options.channel, &info);
     if (rv < 0) {
          ERROR("analogy get chinfo");
          goto out;
     }

     for (int i = 0; i < info->nb_rng; i++) {
          a4l_rnginfo_t *range;
          rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, i, 
&range);
          if (rv < 0) {
               ERROR("analogy get rngnfo");
               goto out;
          }
          DEBUG("range=%d %ld %ld", i, range->max, range->min);
     }

     /* range */
     double min = waveform.offset - waveform.amplitude;
     double max = waveform.offset + waveform.amplitude;
     DEBUG("min=%f max=%f", min, max);
     if (options.range < 0) {
          options.range = analogy_find_range(&dsc, options.subdevice, 
options.channel, options.unit, min, max, NULL);
          DEBUG("range=%d", options.range);
     }
     a4l_rnginfo_t *range;
     rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, 
options.range, &range);
     if (rv < 0) {
          ERROR("analogy get rngnfo");
          goto out;
     }

     dds_t dds;
     dds.kind = waveform.kind;
     dds.frequency = waveform.frequency;

     /* physical to sample */
     unsigned short value = 0;
     double raw = 0.0;
     a4l_dtoraw(info, range, &value, &raw, 1);
     double zero = value;
     
     a4l_dtoraw(info, range, &value, &(waveform.amplitude), 1);
     dds.amplitude = value - zero;

     a4l_dtoraw(info, range, &value, &(waveform.offset), 1);
     dds.offset = value;
     
     DEBUG("amplitude=%f", dds.amplitude);
     DEBUG("offset=%f", dds.offset);

     /* setup command */
     a4l_cmd_t cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.idx_subd = options.subdevice;
     cmd.flags = A4L_CMD_WRITE;
     cmd.start_src = TRIG_INT;
     cmd.start_arg = 0;
     cmd.scan_begin_src = TRIG_TIMER;
     cmd.scan_begin_arg = 1e9 / options.freq;
     cmd.convert_src = TRIG_NOW;
     cmd.convert_arg = 0;
     cmd.scan_end_src = TRIG_COUNT;
     cmd.scan_end_arg = options.nchan;
     cmd.stop_src = TRIG_COUNT;
     cmd.stop_arg = 10000000;
     cmd.nb_chan = 1,
     cmd.chan_descs = chanlist;

     chanlist[0] = PACK(options.channel, options.range, options.aref);
               
     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);

     /* send the command to the input device */
     rv = a4l_snd_command(&dsc, &cmd);
     if (rv < 0) {
          ERROR("analogy snd command");
          goto out;
     }

     dds_init(&dds, options.freq);     
     dds_output(&dds, data, BUFLEN);

     n = BUFLEN * sizeof(sampl_t);
     m = a4l_sys_write(dsc.fd, (void *)data, n);
     if (m < 0) {
          ERROR("write");
          exit(1);
     } else if (m < n) {
          fprintf(stderr, "failed to preload output buffer\n");
          exit(1);
     }
     
     /* send internal trigger */
     ret = analogy_internal_trigger(&dsc, options.subdevice, 0);
     if (ret < 0) {
          ERROR("comedi_internal_trigger\n");
          exit(1);
     }

     while (1) {
          dds_output(&dds, data, BUFLEN);
          n = BUFLEN * sizeof(sampl_t);
          while (n > 0) {
               m = a4l_sys_write(dsc.fd, (void 
*)data+(BUFLEN*sizeof(sampl_t)-n), n);
               if (m < 0) {
                    ERROR("write: %s", strerror(-m));
                    exit(0);
               }
               n -= m;
          }
          total += BUFLEN;
     }


out:
     /* free buffer */
     if (dsc.sbdata != NULL) {
          free(dsc.sbdata);
     }

     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);
     
     /* close file descriptor */
     a4l_close(&dsc);
     
     return rv;
}
_______________________________________________
Xenomai-help mailing list
Xenomai-help@gna.org
https://mail.gna.org/listinfo/xenomai-help

Reply via email to