diff --git a/demo/Makefile.am b/demo/Makefile.am index b770e70..6765420 100644 --- a/demo/Makefile.am +++ b/demo/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = \ antialias ao_waveform ao_mmap apply_cal board_info choose_clock choose_filter \ - choose_routing cmd dio eeprom_dump gpct_buffered_counting \ + choose_routing cmd do_waveform dio eeprom_dump gpct_buffered_counting \ gpct_encoder gpct_pulse_generator \ gpct_simple_counting inp inpn insn ledclock \ mmap outp poll receiver select \ @@ -49,6 +49,10 @@ dio_SOURCES = dio.c common.c dio_CFLAGS = $(COMEDILIB_CFLAGS) dio_LDADD = $(COMEDILIB_LIBS) +do_waveform_SOURCES = do_waveform.c common.c +do_waveform_CFLAGS = $(COMEDILIB_CFLAGS) +do_waveform_LDADD = $(COMEDILIB_LIBS) + eeprom_dump_SOURCES = eeprom_dump.c common.c eeprom_dump_CFLAGS = $(COMEDILIB_CFLAGS) eeprom_dump_LDADD = $(COMEDILIB_LIBS) diff --git a/demo/do_waveform.c b/demo/do_waveform.c new file mode 100644 index 0000000..1af25e1 --- /dev/null +++ b/demo/do_waveform.c @@ -0,0 +1,223 @@ +/* + * Asynchronous Digital Output Example + * Part of Comedilib + * + * Copyright (c) 1999,2000 David A. Schleef + * Copyright (c) 2007 Frank Mori Hess + * + * This file may be freely modified, distributed, and combined with + * other software, as long as proper attribution is given in the + * source code. + */ + +/* + * Requirements: NI M-Series board. + * + * This demo uses the digital io subdevice with an + * asynchronous command to generate waveforms. The + * waveforms in this example are square waves with + * varying periods depending on the digital output + * channel. Channel N outputs a square wave with + * period 2*(N+1) clocks. The command line argument chooses the + * clock signal for updating the outputs. As a suggestion, + * you might use the output of one of the general + * purpose counters for a clock (the default clock + * source is the output of general purpose counter 0), + * and run the gpct_pulse_generator demo to start the counter + * generating pulses on its output. + * + * Note, you must configure at least one of the digital channels as + * an output (for example by running the dio demo program) + * before running this program. You must also pass the dio + * subdevice file using the -f option, since the default write + * subdevice for the m-series boards is the analog output. For + * example, "dio_waveform -f /dev/comedi0_sub2". + */ + +#include +#include +#include +#include +#include "examples.h" +#include +#include +#include +#include +#include +#include +#include + +#define BUF_LEN 0x1000 + +struct test_waveform_generator +{ + unsigned *toggle_countdowns; + unsigned num_channels; + lsampl_t last_output; +}; + +int init_test_waveform_generator(struct test_waveform_generator *generator, unsigned num_channels) +{ + unsigned i; + + generator->num_channels = num_channels; + generator->toggle_countdowns = malloc(sizeof(unsigned) * num_channels); + if(generator->toggle_countdowns == NULL) return -ENOMEM; + for(i = 0; i < num_channels; ++i) + generator->toggle_countdowns[i] = i + 1; + generator->last_output = 0; + return 0; +} + +void cleanup_test_waveform_generator(struct test_waveform_generator *generator) +{ + if(generator->toggle_countdowns) + { + free(generator->toggle_countdowns); + generator->toggle_countdowns = NULL; + } +} + +void build_waveforms(struct test_waveform_generator *generator, lsampl_t *data, unsigned data_len) +{ + unsigned i; + for(i = 0; i < data_len; ++i) + { + unsigned j; + + data[i] = generator->last_output; + for(j = 0; j < generator->num_channels; ++j) + { + if(--generator->toggle_countdowns[j] == 0) + { + generator->toggle_countdowns[j] = j + 1; + data[i] ^= 1 << j; + } + } + generator->last_output = data[i]; + } +} + +int main(int argc, char *argv[]) +{ + comedi_cmd cmd; + struct parsed_options options; + comedi_t *dev; + int i; + struct test_waveform_generator generator; + lsampl_t *buffer = NULL; + int err; + int n, m; + int total=0; + unsigned int *chanlist; + int ret; + + init_parsed_options(&options); + options.subdevice = -1; + options.n_chan = 8; + options.value = NI_CDIO_SCAN_BEGIN_SRC_G0_OUT; + parse_options(&options, argc, argv); + + dev = comedi_open(options.filename); + if(dev == NULL){ + fprintf(stderr, "error opening %s\n", options.filename); + return -1; + } + if(options.subdevice < 0) + options.subdevice = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_DIO, 0); + + memset(&cmd,0,sizeof(cmd)); + cmd.subdev = options.subdevice; + cmd.flags = CMDF_WRITE; + cmd.start_src = TRIG_INT; + cmd.start_arg = 0; + cmd.scan_begin_src = TRIG_EXT; + cmd.scan_begin_arg = options.value; + cmd.convert_src = TRIG_NOW; + cmd.convert_arg = 0; + cmd.scan_end_src = TRIG_COUNT; + cmd.scan_end_arg = options.n_chan; + cmd.stop_src = TRIG_NONE; + cmd.stop_arg = 0; + + chanlist = malloc(options.n_chan * sizeof(unsigned)); + assert(chanlist); + cmd.chanlist = chanlist; + cmd.chanlist_len = options.n_chan; + for(i = 0; i < cmd.chanlist_len; ++i) + { + cmd.chanlist[i] = i; + } + + dump_cmd(stdout, &cmd); + + err = comedi_command_test(dev, &cmd); + if (err < 0) { + comedi_perror("comedi_command_test"); + exit(1); + } + + err = comedi_command_test(dev, &cmd); + if (err < 0) { + comedi_perror("comedi_command_test"); + exit(1); + } + + err = comedi_command_test(dev, &cmd); + if(err != 0) { + fprintf(stderr, "After 3 passes, comedi_command_test returns %i\n", err); + exit(1); + } + + if ((err = comedi_command(dev, &cmd)) < 0) { + comedi_perror("comedi_command"); + exit(1); + } + + ret = init_test_waveform_generator(&generator, cmd.chanlist_len); + assert(ret == 0); + buffer = malloc(sizeof(lsampl_t) * BUF_LEN); + assert(buffer); + build_waveforms(&generator, buffer, BUF_LEN); + n = BUF_LEN * sizeof(buffer[0]); + m = write(comedi_fileno(dev), buffer, n); + if(m < 0){ + perror("write"); + exit(1); + }else if(m < n) + { + fprintf(stderr, "Failed to preload output buffer with %i bytes, is it too small?\n" + "See the --write-buffer option of comedi_config\n", n); + exit(1); + } + printf("m=%d\n",m); + + ret = comedi_internal_trigger(dev, options.subdevice, 0); + if(ret < 0){ + perror("comedi_internal_trigger\n"); + exit(1); + } + + while(1) + { + build_waveforms(&generator, buffer, BUF_LEN); + n = BUF_LEN * sizeof(buffer[0]); + while(n > 0) + { + m = write(comedi_fileno(dev), (void*)(buffer) + (BUF_LEN * sizeof(buffer[0]) - n), n); + if(m < 0){ + perror("write"); + exit(0); + } + printf("m=%d\n",m); + n -= m; + } + total += BUF_LEN; + //printf("%d\n",total); + } + + cleanup_test_waveform_generator(&generator); + free(buffer); + free(chanlist); + return 0; +}