diff --git a/demo/gpct_buffered_counting.c b/demo/gpct_buffered_counting.c new file mode 100644 index 0000000..144f121 --- /dev/null +++ b/demo/gpct_buffered_counting.c @@ -0,0 +1,194 @@ +/* + * NI general-purpose counter example. Makes the counter + * do buffered event counting using comedi_command(). + * Different clock sources can be chosen + * with the choose_clock demo. The gate source is + * set to PFI1 (which is assumed to already be configured as + * an input). The gate source latches the count + * into the data stream, and possibly resets it (for + * non-cumulative buffered counting). + * Part of Comedilib + * + * 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: A board with a National Instruments general-purpose + * counter, and comedi driver version 0.7.74 or newer. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "examples.h" + +int ni_gpct_configure_buffered_event_counting(comedi_t *device, unsigned subdevice) +{ + int retval; + lsampl_t counter_mode; + static const unsigned gate_pfi_channel = 1; + static const unsigned initial_count = 0; + + retval = reset_counter(device, subdevice); + if(retval < 0) return retval; + + retval = set_gate_source(device, subdevice, 0, NI_GPCT_PFI_GATE_SELECT(gate_pfi_channel) /*| CR_EDGE*/); + if(retval < 0) return retval; + retval = set_gate_source(device, subdevice, 1, NI_GPCT_DISABLED_GATE_SELECT | CR_EDGE); + if(retval < 0) + { + fprintf(stderr, "Failed to set second gate source. This is expected for older boards (e-series, etc.)\n" + "that don't have a second gate.\n"); + } + + counter_mode = NI_GPCT_COUNTING_MODE_NORMAL_BITS; + // output pulse on terminal count (doesn't really matter for this application) + counter_mode |= NI_GPCT_OUTPUT_TC_PULSE_BITS; + /* Don't alternate the reload source between the load a and load b registers.*/ + counter_mode |= NI_GPCT_RELOAD_SOURCE_FIXED_BITS; + /* Reload counter on gate. Do not set if you want to do cumulative buffered counting. */ + counter_mode |= NI_GPCT_LOADING_ON_GATE_BIT; + /* Make gate start/stop counting */ + counter_mode |= NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS; + // count up + counter_mode |= NI_GPCT_COUNTING_DIRECTION_UP_BITS; + // don't stop on terminal count + counter_mode |= NI_GPCT_STOP_ON_GATE_BITS; + // don't disarm on terminal count or gate signal + counter_mode |= NI_GPCT_NO_HARDWARE_DISARM_BITS; + retval = set_counter_mode(device, subdevice, counter_mode); + if(retval < 0) return retval; + + /* Set initial counter value by writing to channel 0.*/ + retval = comedi_data_write(device, subdevice, 0, 0, 0, initial_count); + /* Set value of "load a" register by writing to channel 1.*/ + retval = comedi_data_write(device, subdevice, 1, 0, 0, initial_count); + + return 0; +} + +int ni_gpct_send_command(comedi_t *device, unsigned subdevice, unsigned n_counts) +{ + comedi_cmd cmd; + static const unsigned num_chan = 1; + lsampl_t chanlist[num_chan]; + int retval; + + memset(&cmd, 0, sizeof(cmd)); + cmd.subdev = subdevice; + cmd.flags = 0; + cmd.flags |= TRIG_WAKE_EOS; + /* Wake up at the end of every scan, reduces latency for slow data streams. + Turn off for more efficient throughput. */ + cmd.flags |= TRIG_WAKE_EOS; + cmd.start_src = TRIG_NOW; + cmd.start_arg = 0; + /* TRIG_OTHER will use the already configured gate source to latch counts. Can also use + TRIG_EXT and specify the gate source as the scan_begin_arg */ + cmd.scan_begin_src = TRIG_OTHER; + cmd.scan_begin_arg = 0; + cmd.convert_src = TRIG_NOW; + cmd.convert_arg = 0; + cmd.scan_end_src = TRIG_COUNT; + cmd.scan_end_arg = num_chan; + cmd.stop_src = TRIG_COUNT; + cmd.stop_arg = n_counts; + cmd.chanlist = chanlist; + cmd.chanlist_len = num_chan; + chanlist[0] = 0; + + retval = comedi_command_test(device, &cmd); + if(retval) + { + fprintf(stderr, "comedi_command_test() failed.\n"); + return -1; + } + retval = comedi_command(device, &cmd); + if(retval) + { + fprintf(stderr, "comedi_command() failed.\n"); + return -1; + } + return 0; +} + +int ni_gpct_read_and_dump_counts(comedi_t *device, const char *device_filename, unsigned subdevice) +{ + char subdevice_filename[100]; + int retval; + int fd; + static const unsigned buffer_size = 1000; + lsampl_t buffer[buffer_size]; + + //TODO: allow subdevice file name to be specified as a command-line option (with sensible default) +#if 0 + retval = snprintf(subdevice_filename, sizeof(subdevice_filename), "%s_sub%i", device_filename, subdevice); + assert(retval < sizeof(subdevice_filename)); + fd = open(subdevice_filename, O_RDONLY); + if(fd < 0) + { + fprintf(stderr, "error opening subdevice file \"%s\".\n", subdevice_filename); + perror("open"); + return -errno; + } +#endif + fd = comedi_fileno(device); + retval = read(fd, buffer, buffer_size * sizeof(lsampl_t)); + while(retval > 0) + { + unsigned num_counts = retval / sizeof(lsampl_t); + unsigned i; + for(i = 0; i < num_counts; ++i) + { + printf("%i\n", buffer[i]); + } + retval = read(fd, buffer, buffer_size * sizeof(lsampl_t)); + } + if(retval < 0) + { + fprintf(stderr, "error reading from subdevice file \"%s\".\n", subdevice_filename); + perror("read"); + return -errno; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + comedi_t *device; + int retval; + struct parsed_options options; + + init_parsed_options(&options); + parse_options(&options, argc, argv); + device = comedi_open(options.filename); + if(!device) + { + comedi_perror(options.filename); + exit(-1); + } + /*FIXME: check that device is counter */ + printf("Running buffered event counting on subdevice %d.\n", options.subdevice); + + retval = ni_gpct_configure_buffered_event_counting(device, options.subdevice); + if(retval < 0) return retval; + retval = ni_gpct_send_command(device, options.subdevice, options.n_scan); + if(retval < 0) return retval; + retval = ni_gpct_read_and_dump_counts(device, options.filename, options.subdevice); + if(retval < 0) return retval; + return 0; +} +