From: Daniele Nicolodi <daniele@domain.hid>
To: xenomai@xenomai.org
Subject: Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
Date: Mon, 31 May 2010 12:23:44 +0200 [thread overview]
Message-ID: <4C038E30.5070606@domain.hid> (raw)
In-Reply-To: <AANLkTimHOPpI3mst8-fM4Atf6V_-kurbqD-RKZdWDbUY@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 737 bytes --]
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
[-- Attachment #2: analogy-phasemod.c --]
[-- Type: text/plain, Size: 11945 bytes --]
/* 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;
}
[-- Attachment #3: analogy-waveform.c --]
[-- Type: text/plain, Size: 13349 bytes --]
/* 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;
}
next prev parent reply other threads:[~2010-05-31 10:23 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-30 16:14 [Xenomai-help] How to generate a waveform / digital output (Alexis) Ettore Pedretti
2010-05-31 10:23 ` Daniele Nicolodi [this message]
2010-05-31 23:24 ` Ettore Pedretti
2010-06-01 1:37 ` Ettore Pedretti
2010-06-02 21:06 ` Alexis Berlemont
2010-06-03 13:19 ` Daniele Nicolodi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C038E30.5070606@domain.hid \
--to=daniele@domain.hid \
--cc=xenomai@xenomai.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.