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
[email protected]
https://mail.gna.org/listinfo/xenomai-help