Beispiel #1
0
TEST(ComediTest,AnalogReadings ) {
    lsampl_t data;
    int ret;
    int subdev = 0;        
    int chan = 0;          
    int range = 0;         
    int aref = AREF_GROUND;
    int num_scans = options.n_scan;
    int num_channels = options.n_chan;
    int readscans;
    std::string prop("/sys/class/comedi/comedi0/read_buffer_pos");

    dev = comedi_open(options.filename);
    ASSERT_TRUE( dev );
    subdev_flags = comedi_get_subdevice_flags(dev, options.subdevice);
    
    RecordProperty("NumScans", num_scans);
    #if 0
    fprintf(stderr, "command before testing:\n");
    dump_cmd(stderr, cmd);
    #endif

    prepare_cmd_lib(dev, options.subdevice, num_scans, num_channels, 1e9 / options.freq, cmd);
    #if 0
    fprintf(stderr, "command before testing:\n");
    dump_cmd(stderr, cmd);
    #endif

    /**
     * Setup the Command structure
     */
    cmd->chanlist_len = 2;
    cmd->stop_arg = num_scans;

    /* verify no problems */
    ret = comedi_command_test(dev, cmd);
    ASSERT_GE( ret, 0 ) << "Comedi Testing of command for device was ok";
    
    /* make sure our scan number hasn't changed */
    ASSERT_EQ( cmd->stop_arg , num_scans );
    ASSERT_EQ( cmd->chanlist_len , 2 );    

    ret = comedi_command(dev, cmd);
    sleep(1);

    ASSERT_GE( ret, 0 ) << "Able to Submit comedi command\n";


    /* Verify that the buffer position has in fact moved
       to say num_scans scans remain in it */
    FILE *fp = fopen(prop.c_str(),"r");
    ASSERT_TRUE( fp ) << "Able to open sysfs property file";
    fscanf(fp,"%d",&readscans );
    
    ASSERT_EQ( readscans, 4*num_scans ) << "Able to read the fifo position 4*" << num_scans << "\n";
    
    fclose(fp);

    comedi_close( dev );
}
Beispiel #2
0
/**
 * facq_comedi_misc_get_bps:
 * @dev:A comedi_t device.
 * @subindex: The subdevice index.
 * @err: A #GError.
 *
 * Checks the subdevice flags to get the number of bytes per sample
 * used by the subdevice.
 *
 * Returns: The number of bytes per sample, or 0 in case of error.
 */
guint facq_comedi_misc_get_bps(comedi_t *dev,guint subindex,GError **err)
{
	guint subd_flags = 0;

	subd_flags = comedi_get_subdevice_flags(dev,subindex);
	if(subd_flags < 0){
		g_set_error_literal(err,FACQ_COMEDI_MISC_ERROR,
			FACQ_COMEDI_MISC_ERROR_FAILED,
				comedi_strerror(comedi_errno()));
		return 0;
	}
	if(subd_flags & SDF_LSAMPL)
		return sizeof(lsampl_t);
	else
		return sizeof(sampl_t);
}
Beispiel #3
0
/**
 * facq_comedi_misc_can_calibrate
 * @dev: A comedi_t device.
 * @subindex: The subdevice index.
 * @err: A #GError.
 *
 * Checks if a subdevice can be calibrated, in affirmative case returns
 * the supported calibration type.
 *
 * Returns: -1 in case of error, 0 if device can't be calibrated, 1 if
 * device can be soft-calibrated, 2 if device is hard-calibrated.
 */
gint facq_comedi_misc_can_calibrate(comedi_t *dev,guint subindex,GError **err)
{
	guint subd_flags = 0;
	GError *local_err = NULL;
	const gchar *driver_name = NULL;
	guint i = 0, drivers_len = 6;
	const gchar * const drivers[] =
        {
                "ni_pcimio", "ni_atmio",
                "ni_mio_cs", "cb_pcidas",
                "cb_pcidas64", "ni_labpc"
        };

	subd_flags = comedi_get_subdevice_flags(dev,subindex);
	if(subd_flags < 0){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
		goto error;
	}
	if(subd_flags & SDF_SOFT_CALIBRATED)
		return 1;
	else {
		driver_name = comedi_get_driver_name(dev);
		if(!driver_name){
			g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
			goto error;
		}
		for(i = 0;i < drivers_len;i++)
			if(g_strcmp0(driver_name,drivers[i]) == 0)
				return 2;
	}
	return 0;

	error:
	if(local_err)
		g_propagate_error(err,local_err);
	return -1;
}
Beispiel #4
0
void ComediScope::paintEvent( QPaintEvent * ) {
        int ret;
	while (1) {
		// we need data in all the comedi devices
		for(int n=0;n<nComediDevices;n++) {
			if (!comedi_get_buffer_contents(dev[n],subdevice))
				return;
		}

		for(int n=0;n<nComediDevices;n++) {
			int subdev_flags = comedi_get_subdevice_flags(dev[n],
								      subdevice);
			int bytes_per_sample;
			if(subdev_flags & SDF_LSAMPL) {
				bytes_per_sample = sizeof(lsampl_t);
			} else {
				bytes_per_sample = sizeof(sampl_t);
			}
			
			unsigned char buffer[bytes_per_sample*channels_in_use];
			ret = read(comedi_fileno(dev[n]),
				   buffer,
				   bytes_per_sample*channels_in_use);

			if (ret==0) {
				printf("BUG! No data in buffer.\n");
				exit(1);
			}

			if (ret<0) {
				printf("\n\nError %d during read! Exiting.\n\n",ret);
				exit(1);
			}
			
			for(int i=0;i<channels_in_use;i++) {
				int sample;
				if (comediRecord->channel[n][i]->isActive()) {
					int ch = comediRecord->channel[n][i]->getChannel();
					if(subdev_flags & SDF_LSAMPL) {
						sample = ((int)((lsampl_t *)buffer)[ch]);
					} else {
						sample = ((int)((sampl_t *)buffer)[ch]);
					}
					// store raw data
					daqData[n][i] = sample;
					// convert data to physical units for plotting
					float value = comedi_to_phys(sample,
								     crange[n],
								     maxdata[n]);
					// filtering
					value = comediRecord->dcSub[n][i]->filter(value);
					value = comediRecord->hp[n][i]->filter(value);
					value = comediRecord->lp[n][i]->filter(value);
					// remove 50Hz
					if (comediRecord->filterCheckbox->checkState()==Qt::Checked) {
						value=iirnotch[n][i]->filter(value);
					}
					if ((n==fftdevno) && (ch==fftch) &&
					    (comediRecord->fftscope))
						comediRecord->fftscope->append(value);
					// average response if TB is slower than sampling rate
					adAvgBuffer[n][i] = adAvgBuffer[n][i] + value;
				}
			}
		}

		// save data
		if (comediRecord->recPushButton->checkState()==Qt::Checked) {
			writeFile();
		}

		nsamples++;
		tb_counter--;

		// enough averaged?
		if (tb_counter<=0) {
			for(int n=0;n<nComediDevices;n++) {
				for(int i=0;i<channels_in_use;i++) {
					adAvgBuffer[n][i]=adAvgBuffer[n][i]/tb_init;
				}
			}
		
			// plot the stuff
			paintData(adAvgBuffer);

			// clear buffer
			tb_counter=tb_init;
			for(int n=0;n<nComediDevices;n++) {
				for(int i=0;i<channels_in_use;i++) {
					adAvgBuffer[n][i]=0;
				}
			}
		}
	}
}
Beispiel #5
0
/**
 * facq_comedi_misc_get_polynomial:
 * @dev: A comedi_t device.
 * @subindex: The subdevice index.
 * @chanlist: A #FacqChanlist object.
 * @err: A #GError.
 *
 * The functions makes some magic to obtain a per channel,
 * comedi_polynomial_t array. Each polynomial can be used
 * to convert from comedi data to physical samples.
 * See <function>comedi_to_physical()</function> for more 
 * info.
 *
 * Returns: An array of comedi_polynomial_t members. Free it
 * when it's no longer needed. %NULL in case of error.
 * The array length equals the number of I/O Channels in the
 * chanlist.
 */
comedi_polynomial_t *facq_comedi_misc_get_polynomial(comedi_t *dev,guint subindex,const FacqChanlist *chanlist,GError **err)
{
	guint subd_flags = 0;
	guint i = 0, chan = 0, range = 0, aref = 0, iochans_n = 0;
	guint chanspec = 0;
	gchar *cal_filename = NULL;
	comedi_calibration_t *cc = NULL;
	GError *local_err = NULL;
	comedi_polynomial_t *p = NULL;

	g_return_val_if_fail(FACQ_IS_CHANLIST(chanlist),NULL);
	iochans_n = facq_chanlist_get_io_chans_n(chanlist);
	if(iochans_n < 1){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
			FACQ_COMEDI_MISC_ERROR_FAILED,
				"Chanlist is empty");
		goto error;
	}
	cal_filename = comedi_get_default_calibration_path(dev);
	if(!cal_filename){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
			FACQ_COMEDI_MISC_ERROR_FAILED,
				comedi_strerror(comedi_errno()));
		goto error;
	}
	cc = comedi_parse_calibration_file(cal_filename);
	if(!cc){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
			FACQ_COMEDI_MISC_ERROR_FAILED,
				comedi_strerror(comedi_errno()));
		goto error;
	}
	g_free(cal_filename);
	subd_flags = comedi_get_subdevice_flags(dev,subindex);
	if(subd_flags < 0){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
			FACQ_COMEDI_MISC_ERROR_FAILED,
				comedi_strerror(comedi_errno()));
		goto error;
	}
	for(i = 0;i < iochans_n;i++){
		chanspec = facq_chanlist_get_io_chanspec(chanlist,i);
		facq_chanlist_chanspec_to_src_values(chanspec,
						     &chan,
						     &range,
						     &aref,
						     NULL);
		if( comedi_apply_parsed_calibration(dev,subindex,
						chan,
						range,
						aref,
						cc) < 0){
			g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
			goto error;
		}
	}
	if(subd_flags & SDF_SOFT_CALIBRATED){
		p = facq_comedi_misc_get_polynomial_soft(dev,
							 subindex,
							 chanlist,
							 cc,
							 &local_err);
		comedi_cleanup_calibration(cc);
	}
	else {
		comedi_cleanup_calibration(cc);
		p = facq_comedi_misc_get_polynomial_hard(dev,
							 subindex,
							 chanlist,
							 &local_err);
	}
	if(!p)
		goto error;

	return p;

	error:
	if(cal_filename)
		g_free(cal_filename);
	if(cc)
		comedi_cleanup_calibration(cc);
	if(local_err)
		g_propagate_error(err,local_err);
	return NULL;
}
Beispiel #6
0
/**
 * facq_comedi_misc_test_chanlist:
 * @dev: A comedi_t device.
 * @subindex: A subdevice index.
 * @chanlist: A #FacqChanlist object.
 * @err: A #GError.
 *
 * Checks if the provided #FacqChanlist, @chanlist, can be used with
 * the subdevice @subindex, in the device @dev.
 *
 * Returns: %TRUE if supported %FALSE in other case.
 */
gboolean facq_comedi_misc_test_chanlist(comedi_t *dev,guint subindex,const FacqChanlist *chanlist,GError **err)
{
	GError *local_err = NULL;
	guint i = 0, len = 0, iochans_n = 0;
	guint n_channels = 0, n_ranges = 0, subd_flags = 0;
	guint chanspec = 0, chan = 0, range = 0, aref = 0, flags = 0;
	FacqChanDir dir = 0;
	gint subdevice_type = 0;

	g_return_val_if_fail(FACQ_IS_CHANLIST(chanlist),FALSE);
	len = facq_chanlist_get_length(chanlist);
	iochans_n = facq_chanlist_get_io_chans_n(chanlist);
	if(len < 1 || iochans_n == 0){
		g_set_error(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					"Chanlist needs at least one I/O channel");
		goto error;
	}
	subdevice_type = comedi_get_subdevice_type(dev,subindex);
	if(subdevice_type < 0){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
		goto error;
	}
	subd_flags = comedi_get_subdevice_flags(dev,subindex);
	if(subd_flags < 0){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
		goto error;
	}
	n_channels = comedi_get_n_channels(dev,subindex);
	if(n_channels < 0){
		g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
		goto error;
	}
	for(i = 0;i < len;i++){
		chanspec = facq_chanlist_get_io_chanspec(chanlist,i);
		facq_chanlist_chanspec_to_src_values(chanspec,
							&chan,&range,
								&aref,&flags);
		dir = facq_chanlist_get_io_chan_direction(chanlist,i);
		n_ranges = comedi_get_n_ranges(dev,subindex,chan);
		if(n_ranges < 0){
			g_set_error_literal(&local_err,FACQ_COMEDI_MISC_ERROR,
				FACQ_COMEDI_MISC_ERROR_FAILED,
					comedi_strerror(comedi_errno()));
			goto error;	
		}
		if(!facq_comedi_misc_test_chanspec(n_channels,n_ranges,
						subd_flags,chan,range,
						aref,flags,dir,
						subdevice_type,
						&local_err))
			goto error;
	}
	return TRUE;

	error:
	if(local_err)
		g_propagate_error(err,local_err);
	return FALSE;
}
Beispiel #7
0
int test_mmap(void)
{
	comedi_cmd cmd;
	unsigned char *buf;
	unsigned int chanlist[1];
	int go;
	int fails;
	int total=0;
	int ret;
	void *b;
	unsigned char *adr;
	unsigned char *map;
	unsigned int flags;
	int i;
	unsigned sample_size;
	unsigned map_len;

	flags = comedi_get_subdevice_flags(device,subdevice);

	/* attempt to make subdevice the current 'read' subdevice */
	if(flags&SDF_CMD_READ) comedi_set_read_subdevice(device,subdevice);
	if(!(flags&SDF_CMD) || (comedi_get_read_subdevice(device)!=subdevice)){
		printf("not applicable\n");
		return 0;
	}
	if(flags & SDF_LSAMPL) sample_size = sizeof(lsampl_t);
	else sample_size = sizeof(sampl_t);
	map_len = sample_size * N_SAMPLES;

	if(comedi_get_cmd_generic_timed(device, subdevice, &cmd, 1, 1)<0){
		printf("E: comedi_get_cmd_generic_timed failed\n");
		return 0;
	}

	buf=malloc(sample_size * N_SAMPLES);

	map = mmap(NULL, map_len,PROT_READ, MAP_SHARED, comedi_fileno(device),0);
	if(!map){
		printf("E: mmap() failed\n");
		return 0;
	}

	/* test readability */
	for(adr = map; adr < map + map_len; adr += PAGE_SIZE){
		ret=test_segfault(adr);
		if(ret){
			printf("E: %p failed\n",adr);
		}else{
			printf("%p ok\n",adr);
		}
	}

	if(realtime)cmd.flags |= TRIG_RT;

	cmd.chanlist = chanlist;
	cmd.scan_end_arg = 1;
	cmd.stop_arg = N_SAMPLES;
	cmd.chanlist_len = 1;
	chanlist[0] = CR_PACK(0,0,0);

	comedi_command(device,&cmd);

	go=1;
	b=buf;
	while(go){
		ret = read(comedi_fileno(device), b,
				(N_SAMPLES * sample_size) - total);
		if(ret<0){
			if(errno==EAGAIN){
				usleep(10000);
			}else{
				go = 0;
				perror("read");
			}
		}else if(ret==0){
			go = 0;
		}else{
			total += ret;
			b += ret;
			if(verbose) printf("read %d %d\n",ret,total);
			if(total >= (N_SAMPLES * sample_size)){
				go = 0;
			}
		}
	}

	fails = 0;
	for(i=0;i<total;i++){
		if(buf[i]!=map[i]){
			if(fails==0)printf("E: mmap compare failed\n");
			printf("offset %d (read=%02x mmap=%02x)\n",i,
				buf[i], map[i]);
			fails++;
			if(fails>10)break;
		}
	}
	if(fails==0) printf("compare ok\n");

	munmap(map, map_len);

	/* test if area is really unmapped */
	for(adr = map; adr < map + map_len; adr += PAGE_SIZE){
		ret=test_segfault(adr);
		if(ret){
			printf("%p segfaulted (ok)\n",adr);
		}else{
			printf("E: %p still mapped\n",adr);
		}
	}

	free(buf);

	return 0;
}
Beispiel #8
0
static PyObject*
comediModule(PyObject* self, PyObject* args)
{
	char *device;
	int subdevice;
	int channel;
	int range;
	int aref;
	int n_chan;
	int n_scan;
	float freq;
    if (!PyArg_ParseTuple(args, "siiiiiif", &device, &subdevice, &channel, &range, &aref, &n_chan, &n_scan, &freq))
        return NULL;
    
	comedi_t *dev;
	comedi_cmd c,*cmd=&c;
	int ret;
	int total=0;
	int i;
	struct timeval start,end;
	int subdev_flags;
	lsampl_t raw;
	struct parsed_options options;

	init_parsed_options(&options);
	options.filename = device;
	options.subdevice = subdevice;
	options.channel = channel;
	options.range = range;
	options.aref = aref;
	options.n_chan = n_chan;
	options.n_scan = n_scan;
	options.freq = freq;

	/* open the device */
	dev = comedi_open(options.filename);
	if(!dev){
		comedi_perror(options.filename);
		exit(1);
	}

	// Print numbers for clipped inputs
	comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);

	/* Set up channel list */
	for(i = 0; i < options.n_chan; i++){
		chanlist[i] = CR_PACK(options.channel + i, options.range, options.aref);
		range_info[i] = comedi_get_range(dev, options.subdevice, options.channel, options.range);
		maxdata[i] = comedi_get_maxdata(dev, options.subdevice, options.channel);
	}
	prepare_cmd_lib(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);

	fprintf(stderr, "command before testing:\n");
	dump_cmd(stderr, cmd);

	ret = comedi_command_test(dev, cmd);
	if(ret < 0){
		comedi_perror("comedi_command_test");
		if(errno == EIO){
			fprintf(stderr,"Ummm... this subdevice doesn't support commands\n");
		}
		exit(1);
	}
	fprintf(stderr,"first test returned %d (%s)\n", ret,
			cmdtest_messages[ret]);
	dump_cmd(stderr, cmd);

	ret = comedi_command_test(dev, cmd);
	if(ret < 0){
		comedi_perror("comedi_command_test");
		exit(1);
	}
	fprintf(stderr,"second test returned %d (%s)\n", ret,
			cmdtest_messages[ret]);
	if(ret!=0){
		dump_cmd(stderr, cmd);
		fprintf(stderr, "Error preparing command\n");
		exit(1);
	}

	/* this is only for informational purposes */
	gettimeofday(&start, NULL);
	fprintf(stderr,"start time: %ld.%06ld\n", start.tv_sec, start.tv_usec);

	/* start the command */
	ret = comedi_command(dev, cmd);
	if(ret < 0){
		comedi_perror("comedi_command");
		exit(1);
	}
	subdev_flags = comedi_get_subdevice_flags(dev, options.subdevice);

	const int ndim = 2;
	npy_intp nd[2] = {n_scan, n_chan};
	
	PyObject *myarray;
	double *array_buffer;
	myarray = PyArray_SimpleNew(ndim, nd, NPY_DOUBLE);
	Py_INCREF(myarray);
	array_buffer = (double *)PyArray_DATA(myarray);
	
	while(1){
		ret = read(comedi_fileno(dev),buf,BUFSZ);
		if(ret < 0){
			/* some error occurred */
			perror("read");
			break;
		}else if(ret == 0){
			/* reached stop condition */
			break;
		}else{
			static int col = 0;
			double j = 0.0;
			
			int bytes_per_sample;
			total += ret;
			if(options.verbose)fprintf(stderr, "read %d %d\n", ret, total);
			if(subdev_flags & SDF_LSAMPL)
				bytes_per_sample = sizeof(lsampl_t);
			else
				bytes_per_sample = sizeof(sampl_t);
			for(i = 0; i < ret / bytes_per_sample; i++){
				if(subdev_flags & SDF_LSAMPL) {
					raw = ((lsampl_t *)buf)[i];
				} else {
					raw = ((sampl_t *)buf)[i];
				}
				*array_buffer++ = print_datum(raw, col, 1);
				col++;
				if(col == options.n_chan){
					col=0;
					j++;
					printf("\n");
				}
			}
		}
	}

	/* this is only for informational purposes */
	gettimeofday(&end,NULL);
	fprintf(stderr,"end time: %ld.%06ld\n", end.tv_sec, end.tv_usec);

	end.tv_sec -= start.tv_sec;
	if(end.tv_usec < start.tv_usec){
		end.tv_sec--;
		end.tv_usec += 1000000;
	}
	end.tv_usec -= start.tv_usec;
	fprintf(stderr,"time: %ld.%06ld\n", end.tv_sec, end.tv_usec);
    
	return myarray;
}
Beispiel #9
0
int main(int argc, char *argv[])
{
	comedi_t *dev;
	comedi_cmd c,*cmd=&c;
	int ret;
	int total=0;
	int i;
	struct timeval start,end;
	int subdev_flags;
	lsampl_t raw;
	struct parsed_options options;

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

	/* The following variables used in this demo
	 * can be modified by command line
	 * options.  When modifying this demo, you may want to
	 * change them here. */
	options.filename = "/dev/comedi0";
	options.subdevice = 0;
	options.channel = 0;
	options.range = 6;  
	options.aref = AREF_DIFF;
	options.n_chan = 8;
	options.n_scan = 100000;
	options.freq = 1000.0;
	options.physical = 1;

	/* open the device */
	dev = comedi_open(options.filename);
	if(!dev){
		comedi_perror(options.filename);
		exit(1);
	}

	// Print numbers for clipped inputs
	comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);

	/* Set up channel list */
	//for(i = 0; i < options.n_chan/2; i++){
	for(i = 0; i < options.n_chan; i++){	
		chanlist[i] = CR_PACK(options.channel + i, options.range, options.aref);
		range_info[i] = comedi_get_range(dev, options.subdevice, options.channel, options.range);
		maxdata[i] = comedi_get_maxdata(dev, options.subdevice, options.channel);
	}

/*
    for(i = options.n_chan/2; i < options.n_chan; i++){
        fprintf(stderr,"%d: %d\n", i, options.channel + i + 8);
        chanlist[i] = CR_PACK(options.channel + i + 8, options.range, options.aref);
        range_info[i] = comedi_get_range(dev, options.subdevice, options.channel, options.range);
        maxdata[i] = comedi_get_maxdata(dev, options.subdevice, options.channel);
    }    
*/

	/* prepare_cmd_lib() uses a Comedilib routine to find a
	 * good command for the device.  prepare_cmd() explicitly
	 * creates a command, which may not work for your device. */
	prepare_cmd_lib(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);
	//prepare_cmd(dev, options.subdevice, options.n_scan, options.n_chan, 1e9 / options.freq, cmd);

	fprintf(stderr, "command:\n");
	dump_cmd(stderr, cmd);

	/* this is only for informational purposes */
	gettimeofday(&start, NULL);
	fprintf(stderr,"start time: %ld.%06ld\n", start.tv_sec, start.tv_usec);

	/* start the command */
	ret = comedi_command(dev, cmd);
	if(ret < 0){
		comedi_perror("comedi_command");
		exit(1);
	}
	subdev_flags = comedi_get_subdevice_flags(dev, options.subdevice);
	while(1){
		ret = read(comedi_fileno(dev),buf,BUFSZ);
		if(ret < 0){
			/* some error occurred */
			perror("read");
			continue;
		}else if(ret == 0){
			/* reached stop condition */
			break;
		}else{
			static int col = 0;
			int bytes_per_sample;
			total += ret;
			if(options.verbose)fprintf(stderr, "read %d %d\n", ret, total);
			if(subdev_flags & SDF_LSAMPL)
				bytes_per_sample = sizeof(lsampl_t);
			else
				bytes_per_sample = sizeof(sampl_t);
			for(i = 0; i < ret / bytes_per_sample; i++){
				if(subdev_flags & SDF_LSAMPL) {
					raw = ((lsampl_t *)buf)[i];
				} else {
					raw = ((sampl_t *)buf)[i];
				}
				print_datum(raw, col, options.physical);
				col++;
				if(col == options.n_chan){
					printf("\n");
					col=0;
				}
			}
		}
	}

	/* this is only for informational purposes */
	gettimeofday(&end,NULL);
	fprintf(stderr,"end time: %ld.%06ld\n", end.tv_sec, end.tv_usec);

	end.tv_sec -= start.tv_sec;
	if(end.tv_usec < start.tv_usec){
		end.tv_sec--;
		end.tv_usec += 1000000;
	}
	end.tv_usec -= start.tv_usec;
	fprintf(stderr,"time: %ld.%06ld\n", end.tv_sec, end.tv_usec);

	return 0;
}
Beispiel #10
0
MainWindow::MainWindow( QWidget *parent ) :
    QWidget(parent),
    adChannel(0),
    psthLength(1000),
    psthBinw(20),
    spikeThres(1),
    psthOn(0),
    spikeDetected(false),
    time(0),
    linearAverage(0)
{
  // initialize comedi
  const char *filename = "/dev/comedi0";

  /* open the device */
  if( (dev = comedi_open(filename)) == 0 )
  {
    comedi_perror(filename);
    exit(1);
  }

  // do not produce NAN for out of range behaviour
  comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER); 

  maxdata = comedi_get_maxdata(dev, COMEDI_SUB_DEVICE, 0);
  crange = comedi_get_range(dev,COMEDI_SUB_DEVICE,0,0);
  numChannels = comedi_get_n_channels(dev, COMEDI_SUB_DEVICE);

  chanlist = new unsigned[numChannels];

  /* Set up channel list */
  for( int i=0; i<numChannels; i++ )
    chanlist[i] = CR_PACK(i, COMEDI_RANGE_ID, AREF_GROUND);

  int ret = comedi_get_cmd_generic_timed( dev,
                                          COMEDI_SUB_DEVICE,
                                          &comediCommand,
                                          numChannels,
                                          (int)(1e9/(SAMPLING_RATE)) );

  if(ret < 0)
  {
    printf("comedi_get_cmd_generic_timed failed\n");
    exit(-1);
  }

  /* Modify parts of the command */
  comediCommand.chanlist = chanlist;
  comediCommand.stop_src = TRIG_NONE;
  comediCommand.stop_arg = 0;

  /* comedi_command_test() tests a command to see if the
   * trigger sources and arguments are valid for the subdevice.
   * If a trigger source is invalid, it will be logically ANDed
   * with valid values (trigger sources are actually bitmasks),
   * which may or may not result in a valid trigger source.
   * If an argument is invalid, it will be adjusted to the
   * nearest valid value.  In this way, for many commands, you
   * can test it multiple times until it passes.  Typically,
   * if you can't get a valid command in two tests, the original
   * command wasn't specified very well. */
  ret = comedi_command_test(dev, &comediCommand);

  if(ret < 0)
  {
    comedi_perror("comedi_command_test");
    exit(-1);
  }

  fprintf(stderr, "first test returned %d\n", ret);

  ret = comedi_command_test(dev, &comediCommand);
  if(ret < 0)
  {
    comedi_perror("comedi_command_test");
    exit(-1);
  }

  fprintf(stderr, "second test returned %d\n", ret);

  if(ret != 0)
  {
    fprintf(stderr,"Error preparing command\n");
    exit(-1);
  }

  // the timing is done channel by channel
  // this means that the actual sampling rate is divided by
  // number of channels
  if ((comediCommand.convert_src ==  TRIG_TIMER)&&(comediCommand.convert_arg)) {
	  sampling_rate=(((double)1E9 / comediCommand.convert_arg)/numChannels);
  }
  
  // the timing is done scan by scan (all channels at once)
  // the sampling rate is equivalent of the scan_begin_arg
  if ((comediCommand.scan_begin_src ==  TRIG_TIMER)&&(comediCommand.scan_begin_arg)) {
	  sampling_rate=(double)1E9 / comediCommand.scan_begin_arg;
  }

  // 50Hz or 60Hz mains notch filter
  iirnotch = new Iir::Butterworth::BandStop<IIRORDER>;
  assert( iirnotch != NULL );
  iirnotch->setup (IIRORDER, sampling_rate, NOTCH_F, NOTCH_F/10.0);

  /* start the command */
  ret = comedi_command(dev, &comediCommand);
  if(ret < 0)
  {
    comedi_perror("comedi_command");
    exit(1);
  }

  int subdev_flags = comedi_get_subdevice_flags(dev, COMEDI_SUB_DEVICE);

  if( (sigmaBoard = subdev_flags & SDF_LSAMPL) )
    readSize = sizeof(lsampl_t) * numChannels;
  else
    readSize = sizeof(sampl_t) * numChannels;

  //  Initialize data for plots
  for(int i=0; i<MAX_PSTH_LENGTH; i++)
  {
    xData[i] = i;     // time axis
    yData[i] = 0;
    timeData[i] = double(i)*psthBinw; // psth time axis
    spikeCountData[i] = 0;
    psthData[i] = 0;
  }

  // the gui, straight forward QT/Qwt
  resize(640,420);
  QHBoxLayout *mainLayout = new QHBoxLayout( this );

  QVBoxLayout *controlLayout = new QVBoxLayout;
  mainLayout->addLayout(controlLayout);

  QVBoxLayout *plotLayout = new QVBoxLayout;
  plotLayout->addStrut(400);
  mainLayout->addLayout(plotLayout);

  // two plots
  RawDataPlot = new DataPlot(xData, yData, psthLength, 
			     crange->max, crange->min, this);
  plotLayout->addWidget(RawDataPlot);
  RawDataPlot->show();

  plotLayout->addSpacing(20);

  MyPsthPlot = new PsthPlot(timeData, psthData, psthLength/psthBinw, this);
  plotLayout->addWidget(MyPsthPlot);
  MyPsthPlot->show();

  /*---- Buttons ----*/

  // AD group
  QGroupBox   *ADcounterGroup = new QGroupBox( "A/D Channel", this );
  QVBoxLayout *ADcounterLayout = new QVBoxLayout;

  ADcounterGroup->setLayout(ADcounterLayout);
  ADcounterGroup->setAlignment(Qt::AlignJustify);
  ADcounterGroup->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
  controlLayout->addWidget( ADcounterGroup );

  QwtCounter *cntChannel = new QwtCounter(ADcounterGroup);
  cntChannel->setRange(0, numChannels-1, 1);
  cntChannel->setValue(adChannel);
  ADcounterLayout->addWidget(cntChannel);
  connect(cntChannel, SIGNAL(valueChanged(double)), SLOT(slotSetChannel(double)));

  filter50HzCheckBox = new QCheckBox( "50Hz filter" );
  filter50HzCheckBox->setEnabled( true );
  ADcounterLayout->addWidget(filter50HzCheckBox);

  // psth functions
  QGroupBox   *PSTHfunGroup  = new QGroupBox( "Actions", this );
  QVBoxLayout *PSTHfunLayout = new QVBoxLayout;

  PSTHfunGroup->setLayout(PSTHfunLayout);
  PSTHfunGroup->setAlignment(Qt::AlignJustify);
  PSTHfunGroup->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
  controlLayout->addWidget( PSTHfunGroup );

  averagePsth = new QComboBox(PSTHfunGroup);
  averagePsth->addItem(tr("PSTH"));
  averagePsth->addItem(tr("VEP"));
  PSTHfunLayout->addWidget(averagePsth);
  connect( averagePsth, SIGNAL(currentIndexChanged(int)), SLOT(slotAveragePsth(int)) );

  triggerPsth = new QPushButton(PSTHfunGroup);
  triggerPsth->setText("PSTH on");
  triggerPsth->setCheckable(true);
  PSTHfunLayout->addWidget(triggerPsth);
  connect(triggerPsth, SIGNAL(clicked()), SLOT(slotTriggerPsth()));

  QPushButton *clearPsth = new QPushButton(PSTHfunGroup);
  clearPsth->setText("clear data");
  PSTHfunLayout->addWidget(clearPsth);
  connect(clearPsth, SIGNAL(clicked()), SLOT(slotClearPsth()));

  QPushButton *savePsth = new QPushButton(PSTHfunGroup);
  savePsth->setText("save data");
  PSTHfunLayout->addWidget(savePsth);
  connect(savePsth, SIGNAL(clicked()), SLOT(slotSavePsth()));

  // psth params
  QGroupBox   *PSTHcounterGroup = new QGroupBox( "Parameters", this );
  QVBoxLayout *PSTHcounterLayout = new QVBoxLayout;

  PSTHcounterGroup->setLayout(PSTHcounterLayout);
  PSTHcounterGroup->setAlignment(Qt::AlignJustify);
  PSTHcounterGroup->setSizePolicy( QSizePolicy(QSizePolicy::Fixed,
					       QSizePolicy::Fixed) );
  controlLayout->addWidget( PSTHcounterGroup );

  QLabel *psthLengthLabel = new QLabel("Sweep length", PSTHcounterGroup);
  PSTHcounterLayout->addWidget(psthLengthLabel);

  QwtCounter *cntSLength = new QwtCounter(PSTHcounterGroup);
  cntSLength->setNumButtons(2);
  cntSLength->setIncSteps(QwtCounter::Button1, 10);
  cntSLength->setIncSteps(QwtCounter::Button2, 100);
  cntSLength->setRange(1, MAX_PSTH_LENGTH, 1);
  cntSLength->setValue(psthLength);
  PSTHcounterLayout->addWidget(cntSLength);
  connect(cntSLength, 
	  SIGNAL(valueChanged(double)), 
	  SLOT(slotSetPsthLength(double)));

  QLabel *binwidthLabel = new QLabel("Binwidth", PSTHcounterGroup);
  PSTHcounterLayout->addWidget(binwidthLabel);

  cntBinw = new QwtCounter(PSTHcounterGroup);
  cntBinw->setNumButtons(2);
  cntBinw->setIncSteps(QwtCounter::Button1, 1);
  cntBinw->setIncSteps(QwtCounter::Button2, 10);
  cntBinw->setRange(1, 100, 1);
  cntBinw->setValue(psthBinw);
  PSTHcounterLayout->addWidget(cntBinw);
  connect(cntBinw, SIGNAL(valueChanged(double)), SLOT(slotSetPsthBinw(double)));

  QLabel *thresholdLabel = new QLabel("Spike Threshold", PSTHcounterGroup);
  PSTHcounterLayout->addWidget(thresholdLabel);

  editSpikeT = new QTextEdit("0");
  QFont editFont("Courier",14);
  QFontMetrics editMetrics(editFont);
  editSpikeT->setMaximumHeight ( editMetrics.height()*1.2 );
  editSpikeT->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  editSpikeT->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  editSpikeT->setFont(editFont);
  PSTHcounterLayout->addWidget(editSpikeT);
  connect(editSpikeT, SIGNAL(textChanged()), SLOT(slotSetSpikeThres()));

  thresholdMarker = new QwtPlotMarker();
  thresholdMarker->setValue(0,0);
  thresholdMarker->attach(RawDataPlot);
  thresholdMarker->setLineStyle(QwtPlotMarker::HLine);

  // Generate timer event every 50ms
  (void)startTimer(50);

}
Beispiel #11
0
/**
 * @brief Get the information from Comedi library
 *
 */
void MainWindow::GetComediInfo()
    {
    int i,j;
    int n_subdevices,type;
    int chan,n_chans;
    int n_ranges;
    int subdev_flags;
    comedi_range *rng;

    ChannelList.clear();
    // at the moment we are using the default device
    const char optionsfilename[]="/dev/comedi0";
    QString DeviceName=AppSettings.value(Key_Comedi_Device_Name).toString();
    if (DeviceName.length()<=0) DeviceName=optionsfilename;
    it = comedi_open(optionsfilename);
    if(!it)
        {
        QMessageBox::warning(this, optionsfilename,
            tr("Can not open the device\n"),
            QMessageBox::Ok);
        };
    cbComediDevice->addItem(optionsfilename,1);
    AppSettings.setValue(Key_Comedi_Device_Name,DeviceName);

    QString buffer="Overall info:\n";
    //buffer+=QString    printf("  Version code: 0x%06x\n", comedi_get_version_code(it));
    buffer+=QString("  Comedi version code: 0x%06x\n").arg(comedi_get_version_code(it));
    buffer+=QString("  Driver name: %1\n").arg(comedi_get_driver_name(it));
    buffer+=QString("  Board name: %1\n").arg(comedi_get_board_name(it));
    n_subdevices = comedi_get_n_subdevices(it);
    buffer+=QString(" Number of subdevices: %1\n").arg(n_subdevices);

    tlComediInfo->setText(buffer);

    int channel_unique_id=1;


    // Now scan subdevices
    for(i = 0; i < n_subdevices; i++)
        {
        buffer.clear();
        type = comedi_get_subdevice_type(it, i);
        if(type==COMEDI_SUBD_UNUSED) continue;

        QTextEdit * tabText=new QTextEdit;
        buffer+=QString("Subdevice %1\n").arg(i);
        buffer+=QString("Type: %1 (%2)\n").arg(type).arg(subdevice_types[type]);

        subdev_flags = comedi_get_subdevice_flags(it, i);
        QString flagsstring;
        flagsstring.sprintf("flags: 0x%08x\n",subdev_flags);
        buffer+=flagsstring;

        n_chans=comedi_get_n_channels(it,i);
        buffer+=QString("  Number of channels: %1\n").arg(n_chans);
        if ((type==1)||(type==2)) // Analog input or output
            {
            for(chan=0;chan<n_chans;chan++)
                {
                // here!
                ChannelList.append(AIO_channel(QString(optionsfilename),i,chan,0,type==1,++channel_unique_id));
                };
            };


        if(!comedi_maxdata_is_chan_specific(it,i))
            {
            buffer+=QString("  Maximal data value: %1\n").arg((unsigned long)comedi_get_maxdata(it,i,0));
            }
            else
            {
            buffer+=QString("  Maximal data value is channel specific:\n");
            for(chan=0;chan<n_chans;chan++)
                {
                buffer+=QString("    Channel %1: %2\n").arg(chan).arg
                    ((unsigned long)comedi_get_maxdata(it,i,chan));
                }
            };

        buffer+=QString("  ranges:\n");
        if (!comedi_range_is_chan_specific(it,i))
            {
            n_ranges=comedi_get_n_ranges(it,i,0);
            buffer+=QString("    All channels:");
            for(j=0;j<n_ranges;j++)
                {
                rng=comedi_get_range(it,i,0,j);
//                buffer+=QString(" [%g,%g]",rng->min,rng->max);
                buffer+=QString(" [%1,%2]").arg(rng->min).arg(rng->max);
                }
            buffer+=QString("\n");
            }
            else
            {
            for (chan=0;chan<n_chans;chan++)
                {
                n_ranges=comedi_get_n_ranges(it,i,chan);
                printf("    chan%d:",chan);
                for(j=0;j<n_ranges;j++)
                    {
                    rng=comedi_get_range(it,i,chan,j);
                    printf(" [%g,%g]",rng->min,rng->max);
                    }
                printf("\n");
                }

            }
        tabText->setText(buffer);
        tabWidget->addTab(tabText,QString("subdevice %1").arg(i));
        }
        //printf("  command:\n");
        //get_command_stuff(it,i);


    tabWidget->setTabText(0,tr("Connections"));

    // Create channles we might need; all are input channels save one


     Ini_ImI=   new AIO_channel(Key_Im_Input,1);
     Ini_CmdI=  new AIO_channel(Key_Cmd_Input,1);
     Ini_CmI=   new AIO_channel(Key_Cm_Tlgf_Input,1);
     Ini_GainT= new AIO_channel(Key_Gain_Tlgf_Input,1);
     Ini_FreqT= new AIO_channel(Key_Freq_Tlgf_Input,1);
     Ini_LswT=  new AIO_channel(Key_Lsw_Tlgf_Input,1);

     Ini_CmdO=  new AIO_channel(Key_Cmd_Output,0);


     for (int ch=0;ch<ChannelList.count();ch++)
        {
        if (ChannelList[ch].is_input)
            {
            cbxAI_Im->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_ImI)  {
                int zzz=cbxAI_Im->count();
                cbxAI_Im->setCurrentIndex(zzz-1);
                };

            cbxAI_Cmd->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_CmdI) { cbxAI_Cmd->setCurrentIndex(cbxAI_Cmd->count()-1); };

            cbxAI_Cm_tlg->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_CmI)  { cbxAI_Cm_tlg->setCurrentIndex(cbxAI_Cm_tlg->count()-1); };

            cbxAI_Gain_tlg->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_GainT){ cbxAI_Gain_tlg->setCurrentIndex(cbxAI_Gain_tlg->count()-1); };

            cbxAI_Freq_tlg->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_FreqT) { cbxAI_Freq_tlg->setCurrentIndex(cbxAI_Freq_tlg->count()-1); };

            cbxAI_Lsw_tlg->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_LswT) { cbxAI_Lsw_tlg->setCurrentIndex(cbxAI_Lsw_tlg->count()-1); };
            }
            else
            {
            cbxAO_Cmd->addItem(ChannelList[ch].Description(),ChannelList[ch].ID());
            if (ChannelList[ch]==Ini_CmdO)
                {
                cbxAO_Cmd->setCurrentIndex(cbxAO_Cmd->count()-1);
                };
            };

        };
    return;
    }
Beispiel #12
0
int DaqDevice::DAQcalibration(int subdev,int channel,int range_idx)
{
    int retval;
    int flags;
    comedi_calibration_t* parsed_calibration;
    comedi_polynomial_t* converter;
    comedi_conversion_direction options;

    if (COMEDI_AN_IN_SUB == subdev)
    {
	converter = &_converter_an_input[channel];
	options = COMEDI_TO_PHYSICAL;
    }
	
    else if (COMEDI_AN_OUT_SUB == subdev)
    {
	converter = &_converter_an_output[channel];
	options = COMEDI_FROM_PHYSICAL;
    }	
    else 
	return COMEDI_ERROR;

    flags = comedi_get_subdevice_flags(_dev, subdev);
    if(flags < 0)
    {
        return COMEDI_ERROR;
    }
    if(flags & SDF_SOFT_CALIBRATED) /* board uses software calibration */
    {
        char *calibration_file_path = comedi_get_default_calibration_path(_dev);

        /* parse a calibration file which was produced by the
                comedi_soft_calibrate program */
        parsed_calibration = comedi_parse_calibration_file(calibration_file_path);
        if(parsed_calibration == NULL)
        {
            return COMEDI_ERROR;
        }

        /* get the comedi_polynomial_t for the subdevice/channel/range
                we are interested in */

        retval = comedi_get_softcal_converter(subdev, channel, range_idx,
                                              options, parsed_calibration, converter);

        comedi_cleanup_calibration(parsed_calibration);
       

        if(retval < 0)
        {
            return COMEDI_ERROR;
        }
    }else /* board uses hardware calibration */
    {
        retval = comedi_get_hardcal_converter(_dev, subdev, channel, range_idx,
                                              options, converter);
        if(retval < 0)
        {
            return COMEDI_ERROR;
        }
    }

    return COMEDI_OK;
}
Beispiel #13
0
static void init(scicos_block *block)
{
  struct ADCOMDev * comdev = (struct ADCOMDev *) malloc(sizeof(struct ADCOMDev));
  *block->work = (void *)comdev;

  char devName[15];
  char board[50];
  comedi_krange krange;

  comdev->channel = block->ipar[0];
  comdev->range = block->ipar[1];
  comdev->aref = block->ipar[2];
  comdev->index = block->ipar[3];

  sprintf(devName,"/dev/comedi%d", comdev->index);
  if (!ComediDev[comdev->index]) {
    comdev->dev = comedi_open(devName);
    if (!(comdev->dev)) {
      fprintf(stderr, "COMEDI %s open failed\n", devName);
      exit_on_error();
      return;
    }
    rt_comedi_get_board_name(comdev->dev, board);
    printf("COMEDI %s (%s) opened.\n\n", devName, board);
    ComediDev[comdev->index] = comdev->dev;
  } else
    comdev->dev = ComediDev[comdev->index];

  if ((comdev->subdev = comedi_find_subdevice_by_type(comdev->dev, COMEDI_SUBD_AI, 0)) < 0) {
    fprintf(stderr, "Comedi find_subdevice failed (No analog input)\n");
    comedi_close(comdev->dev);
    exit_on_error();
    return;
  }
  if (!ComediDev_AIInUse[comdev->index] && comedi_lock(comdev->dev, comdev->subdev) < 0) {
    fprintf(stderr, "Comedi lock failed for subdevice %d\n", comdev->subdev);
    comedi_close(comdev->dev);
    exit_on_error();
    return;
  }

  if (comdev->channel >= comedi_get_n_channels(comdev->dev, comdev->subdev)) {
    fprintf(stderr, "Comedi channel not available for subdevice %d\n", comdev->subdev);
    comedi_unlock(comdev->dev, comdev->subdev);
    comedi_close(comdev->dev);
    exit_on_error();
    return;
  }
  if ((comedi_get_krange(comdev->dev, comdev->subdev, comdev->channel, comdev->range, &krange)) < 0) {
    fprintf(stderr, "Comedi get_range failed for subdevice %d\n", comdev->subdev);
    comedi_unlock(comdev->dev, comdev->subdev);
    comedi_close(comdev->dev);
    exit_on_error();
    return;
  }
#ifdef SOFTCALIB
  int flags;
  if ((flags = comedi_get_subdevice_flags(comdev->dev, comdev->subdev)) < 0) {
    fprintf(stderr, "Comedi get_subdevice_flags failed for subdevice %d\n", comdev->subdev);
  } else {
    if (flags & SDF_SOFT_CALIBRATED) {/* board uses software calibration */
      if ((comdev->use_softcal = get_softcal_coef(devName, comdev->subdev,
                comdev->channel, comdev->range, 0, comdev->coefficients)) == 0)
        fprintf(stderr, "No software calibration found for AI Channel %d\n",comdev->channel);
    }
  }
#endif

  ComediDev_InUse[comdev->index]++;
  ComediDev_AIInUse[comdev->index]++;
  comdev->maxdata = comedi_get_maxdata(comdev->dev, comdev->subdev, comdev->channel);
  comdev->range_min = (double)(krange.min)*1.e-6;
  comdev->range_max = (double)(krange.max)*1.e-6;
  printf("AI Channel %d - Range : %1.2f [V] - %1.2f [V]%s\n\n", comdev->channel,
    comdev->range_min, comdev->range_max, (comdev->use_softcal)?" Software calibration used":"");
}
Beispiel #14
0
static int openBoard( int board ) {
    MY_BOARD_HARDWARE *pBoardHard = myHardwareBoardList + board;
    MY_BOARD_SOFTWARE *pBoardSoft = mySoftwareBoardList + board;

    fprintf( stderr, "openBoard[%d]\n", board );
    fprintf( stderr, "sizeof(lsampl_t)=%d\n", sizeof(lsampl_t) );
    fprintf( stderr, "sizeof(sampl_t)=%d\n", sizeof(sampl_t) );

    if (pBoardHard == NULL || pBoardSoft == NULL) return 1;

    pBoardHard->p_comediFileHandle = comedi_open( pBoardHard->devicePath );

    if (pBoardHard->p_comediFileHandle == NULL) {
        fprintf( stderr, "comedi_open failed for board[%d] %s\n", board, pBoardHard->devicePath );
        return 1;
    }
    fprintf( stderr, "opened file\n" );
    
    pBoardHard->subDeviceNumber =
    comedi_find_subdevice_by_type(
        pBoardHard->p_comediFileHandle,
        COMEDI_SUBD_AI,
        0
    );
    
    if (pBoardHard->subDeviceNumber < 0) {
        fprintf( stderr, "subDeviceNum < 0 failed for board[%d]\n", board );
        return 1;
    }
    fprintf( stderr, "get subDevice=%d\n", pBoardHard->subDeviceNumber );

    int subDevFlags = comedi_get_subdevice_flags(
        pBoardHard->p_comediFileHandle,
        pBoardHard->subDeviceNumber
    );
    if (subDevFlags & SDF_PACKED) {
        fprintf( stderr, "subDevice using bit per channel\n" );
    } else {
        if (subDevFlags & SDF_LSAMPL) {
            pBoardHard->valueIsLsampl_t = 1;
            fprintf( stderr, "subDevice using long word lsampl_t per channel\n" );
        } else {
            fprintf( stderr, "subDevice using word sampl_t per channel\n" );
        }
    }

    pBoardHard->buffer_size_in_byte =
    comedi_get_buffer_size(
        pBoardHard->p_comediFileHandle,
        pBoardHard->subDeviceNumber
    );
    fprintf( stderr, "board[%d] hardware buffer size in BYTES=%d\n",
    board, pBoardHard->buffer_size_in_byte );
    if (pBoardHard->buffer_size_in_byte <= 0) {
        fprintf( stderr, "board buffer size faile\n" );
        return 1;
    }

    if (pBoardHard->valueIsLsampl_t) {
        pBoardHard->buffer_size_in_sample = pBoardHard->buffer_size_in_byte / sizeof(lsampl_t);
    } else {
        pBoardHard->buffer_size_in_sample = pBoardHard->buffer_size_in_byte / sizeof(sampl_t);
    }

    pBoardHard->buffer = mmap(
        NULL,
        pBoardHard->buffer_size_in_byte,
        PROT_READ,
        MAP_SHARED,
        comedi_fileno(pBoardHard->p_comediFileHandle),
        0
    );
    if (pBoardHard->buffer == MAP_FAILED) {
        fprintf( stderr, "mmap failed for board[%d]\n", board );
        return 1;
    }

    int numChannel = comedi_get_n_channels(
        pBoardHard->p_comediFileHandle,
        pBoardHard->subDeviceNumber
    );
    if (numChannel != pBoardSoft->numberOfActiveAnalogInputs) {
        fprintf( stderr, "number of channel for board[%d] from comedi=%d harccode=%d\n",
        board, numChannel, pBoardSoft->numberOfActiveAnalogInputs );
    }

#ifdef SUPPORT_CHANNEL_SPECIFIC_RANGE
    pBoardHard->maxDataIsChannelSpecific =
    comedi_maxdata_is_chan_specific(
        pBoardHard->p_comediFileHandle,
        pBoardHard->subDeviceNumber
    );
    pBoardHard->rangeIsChannelSpecific =
    comedi_maxdata_is_chan_specific(
        pBoardHard->p_comediFileHandle,
        pBoardHard->subDeviceNumber
    );
    if (pBoardHard->maxDataIsChannelSpecific) {
        fprintf( stderr, "board[%d] supports different max data per channel\n", board );
    }
    if (pBoardHard->rangeIsChannelSpecific) {
        fprintf( stderr, "board[%d] supports different range per channel\n", board );
    }
#endif

    return 0;
}