예제 #1
0
파일: daq.c 프로젝트: bogaskilop/daq_gert
int init_daq(double min_range, double max_range, int range_update) {
    int i = 0;

    if (!DEV_OPEN) {
        it = comedi_open("/dev/comedi0");
        if (it == NULL) {
            comedi_perror("comedi_open");
            ADC_OPEN = FALSE;
            DEV_OPEN = FALSE;
            return -1;
        }
        DEV_OPEN = TRUE;
    }

    subdev_ai = comedi_find_subdevice_by_type(it, COMEDI_SUBD_AI, subdev_ai);
    if (subdev_ai < 0) {
        return -2;
        ADC_OPEN = FALSE;
    }


    subdev_ao = comedi_find_subdevice_by_type(it, COMEDI_SUBD_AO, subdev_ao);
    if (subdev_ao < 0) {
        HAS_AO = FALSE;
    } else {
        HAS_AO = TRUE;
    }

    printf("Subdev AI  %i ", subdev_ai);
    channels_ai = comedi_get_n_channels(it, subdev_ai);
    printf("Analog  Channels %i ", channels_ai);
    maxdata_ai = comedi_get_maxdata(it, subdev_ai, i);
    printf("Maxdata %i ", maxdata_ai);
    ranges_ai = comedi_get_n_ranges(it, subdev_ai, i);
    printf("Ranges %i ", ranges_ai);
    ad_range = comedi_get_range(it, subdev_ai, i, ranges_ai - 1);
    if (range_update) {
        ad_range->min = min_range;
        ad_range->max = max_range;
    }
    printf(": ad_range .min = %.3f, max = %.3f\n", ad_range->min,
            ad_range->max);

    if (HAS_AO) {
        printf("Subdev AO  %i ", subdev_ao);
        channels_ao = comedi_get_n_channels(it, subdev_ao);
        printf("Analog  Channels %i ", channels_ao);
        maxdata_ao = comedi_get_maxdata(it, subdev_ao, i);
        printf("Maxdata %i ", maxdata_ao);
        ranges_ao = comedi_get_n_ranges(it, subdev_ao, i);
        printf("Ranges %i ", ranges_ao);
        da_range = comedi_get_range(it, subdev_ao, i, ranges_ao - 1);
        printf(": da_range .min = %.3f, max = %.3f\n", da_range->min,
                da_range->max);
    }

    ADC_OPEN = TRUE;
    comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);
    return 0;
}
예제 #2
0
파일: daq.c 프로젝트: nsaspook/mbmc
int init_dio(void)
{
	int i = 0;

	if (!DEV_OPEN) {
		it = comedi_open(comedi_dev);
		if (it == NULL) {
			comedi_perror("comedi_open");
			DIO_OPEN = FALSE;
			DEV_OPEN = FALSE;
			return -1;
		}
		DEV_OPEN = TRUE;
	}

	subdev_dio = comedi_find_subdevice_by_type(it, COMEDI_SUBD_DIO, subdev_dio);
	if (subdev_dio < 0) {
		return -1;
		DIO_OPEN = FALSE;
	}

	printf("Subdev  %i ", subdev_dio);
	channels_dio = comedi_get_n_channels(it, subdev_dio);
	printf("Digital Channels %i ", channels_dio);
	maxdata_dio = comedi_get_maxdata(it, subdev_dio, i);
	printf("Maxdata %i ", maxdata_dio);
	ranges_dio = comedi_get_n_ranges(it, subdev_dio, i);
	printf("Ranges %i \n", ranges_dio);
	DIO_OPEN = TRUE;
	return 0;
}
예제 #3
0
    void ComediSubDeviceDOut::init(bool all_bits)
    {
        Logger::In in( nameserver.getName( this ).c_str() );
        if (!myCard) {
            log(Error) << "Error creating ComediSubDeviceDOut: null ComediDevice given." <<endlog();
            return;
        }
        if ( ( myCard->getSubDeviceType( subDevice ) != COMEDI_SUBD_DO ) &&
             ( myCard->getSubDeviceType( subDevice ) != COMEDI_SUBD_DIO) )
            {
                Logger::In in("ComediSubDeviceDOut");
                log(Error) << "SubDevice "<< subDevice <<" is not a digital output:";
                log() << "type = " << myCard->getSubDeviceType( subDevice ) << endlog();
                // channels remains '0'.
                return;
            }

        channels = comedi_get_n_channels(myCard->getDevice()->it, subDevice);

        // Only for DIO
        if ( ( myCard->getSubDeviceType( subDevice ) == COMEDI_SUBD_DIO) && all_bits) {
            log(Info) << "Configuring first "<<channels<<" dio channels on subdevice "<<subDevice<<" as output type." << endlog();

            for (unsigned int i=0; i<channels; ++i)
                comedi_dio_config(myCard->getDevice()->it, subDevice, i, COMEDI_OUTPUT);
        } else {
            log(Info) << "Subdevice "<<subDevice<<" is digital output with "<<channels << " channels." << endlog();
        }


    }
예제 #4
0
파일: cal_common.c 프로젝트: jbetten/rtxi
int generic_cal_ao(calibration_setup_t *setup,
	const generic_layout_t *layout  )
{
	int channel, range, num_ao_ranges,
		num_ao_channels, retval;
	comedi_calibration_setting_t *current_cal;


	if(setup->da_subdev >= 0 && setup->do_output)
	{
		assert( comedi_range_is_chan_specific( setup->dev, setup->da_subdev ) == 0 );

		num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 );
		if( num_ao_ranges < 0 ) return -1;

		num_ao_channels = comedi_get_n_channels( setup->dev, setup->da_subdev );
		if( num_ao_channels < 0 ) return -1;
	}else
		num_ao_ranges = num_ao_channels = 0;
	for( channel = 0; channel < num_ao_channels; channel++ )
	{
		for( range = 0; range < num_ao_ranges; range++ )
		{
			current_cal = sc_alloc_calibration_setting(setup->new_calibration);
			generic_prep_dac_caldacs( setup, layout, channel, range );
			generic_do_dac_channel( setup, layout, setup->new_calibration,
				current_cal, channel, range );
		}
	}
	retval = write_calibration_file(setup->cal_save_file_path, setup->new_calibration);
	return retval;
}
예제 #5
0
extern uchar init(char* dev) {
    uint i, nchan;
    ni = comedi_open(dev);
    if (ni == NULL) {
        printf("Error opening device\n");
        return -1;
    }
    nchan = comedi_get_n_channels(ni, 0);
    printf("found comedi system with %d channels\n", nchan);
    for (i=0; i < nchan; i++) {
        if (comedi_dio_config(ni, 0, i, COMEDI_OUTPUT) < 0)
            return -1;
    }
    return 0;
}
예제 #6
0
/*!
    \fn newViewDialog::slotPluginSelected()
 */
void newViewDialog::slotPluginSelected()
{
	QString name = pluginsList->currentItem()->text();
	okPushButton->setEnabled( TRUE );
	
	QListIterator<pluginData> it(pl);
	while( it.hasNext() ){
		pluginData data = it.next();
		if ( data.name == name ){
			maxSelect = data.numChannels;

            int comediSubdevice = comedi_find_subdevice_by_type(comediDevice,data.type_comedi,0);
            if( comediSubdevice >= 0){
                maxChannels = comedi_get_n_channels(comediDevice, comediSubdevice);
                okPushButton->setEnabled(TRUE);
                status->setText(QString("comedi subdevice\ntype %1 found!").arg(data.type_comedi));
            }
            else{
                //comedi_perror( QString("error in %1 line %2").arg(__func__).arg(__LINE__).toStdString().c_str() );
                okPushButton->setEnabled(FALSE);
                maxChannels = 0;
                status->setText(QString("comedi subdevice\ntype %1 not found!").arg(data.type_comedi));
            }

            if( maxChannels < 0 ){
                maxChannels = 0;
                comedi_perror( QString("error in %1 line %2").arg(__func__).arg(__LINE__).toStdString().c_str() );
            }

			if(channelSelectors.count() < maxSelect)
				for( int i = channelSelectors.count(); i < maxSelect; i++ ) {
					QSpinBox *spinBox = new QSpinBox();
					spinBox->setRange( 0, maxChannels-1 );
					channelsListL->addWidget( spinBox );
					
					channelSelectors << spinBox ;
				}
			else if(channelSelectors.count() > maxSelect) {
				channelSelectors.last();
				for( int i = maxSelect; i< channelSelectors.count(); i++ )
					 delete channelSelectors.takeLast();
			}
        }
	}
}
예제 #7
0
파일: daq.c 프로젝트: nsaspook/mbmc
int init_daq(void)
{
	int i = 0, range_index = 0;
	comedi_range *ad_range;

	if (!DEV_OPEN) {
		it = comedi_open(comedi_dev);
		if (it == NULL) {
			comedi_perror("comedi_open");
			ADC_OPEN = FALSE;
			DEV_OPEN = FALSE;
			HAVE_DIO = FALSE;
			HAVE_AI = FALSE;
			return -1;
		}
		DEV_OPEN = TRUE;
	}

	subdev_ai = comedi_find_subdevice_by_type(it, COMEDI_SUBD_AI, subdev_ai);
	if (subdev_ai < 0) {
		return -1;
		ADC_OPEN = FALSE;
	}

	printf("Subdev  %i ", subdev_ai);
	channels_ai = comedi_get_n_channels(it, subdev_ai);
	printf("Analog  Channels %i ", channels_ai);
	maxdata_ai = comedi_get_maxdata(it, subdev_ai, i);
	printf("Maxdata %i ", maxdata_ai);
	ranges_ai = comedi_get_n_ranges(it, subdev_ai, i);
	printf("Ranges %i ", ranges_ai);

	for (range_index = 0; range_index < ranges_ai; range_index++) {
		ad_range = comedi_get_range(it, subdev_ai, i, range_index);
		printf(": range %i, min = %.1f, max = %.1f ", range_index,
		ad_range->min, ad_range->max);
	}
	printf("\n");

	ADC_OPEN = TRUE;
	comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);
	return 0;
}
예제 #8
0
파일: cal_common.c 프로젝트: jbetten/rtxi
int generic_cal_by_range( calibration_setup_t *setup,
	const generic_layout_t *layout  )
{
	int channel, range, num_ai_ranges, num_ao_ranges,
		num_ao_channels, retval;
	comedi_calibration_setting_t *current_cal;
	int postgain_bip, postgain_unip;

	assert( comedi_range_is_chan_specific( setup->dev, setup->ad_subdev ) == 0 );

	num_ai_ranges = comedi_get_n_ranges( setup->dev, setup->ad_subdev, 0 );
	if( num_ai_ranges < 0 ) return -1;

	if(setup->da_subdev >= 0 && setup->do_output )
	{
		assert( comedi_range_is_chan_specific( setup->dev, setup->da_subdev ) == 0 );

		num_ao_ranges = comedi_get_n_ranges( setup->dev, setup->da_subdev, 0 );
		if( num_ao_ranges < 0 ) return -1;

		num_ao_channels = comedi_get_n_channels( setup->dev, setup->da_subdev );
		if( num_ao_channels < 0 ) return -1;
	}else
		num_ao_ranges = num_ao_channels = 0;

	if( layout->adc_postgain_offset( 0 ) >= 0 )
	{
		/* bipolar postgain */
		current_cal = sc_alloc_calibration_setting(setup->new_calibration);
		generic_do_adc_postgain_offset( setup, layout, current_cal, 0, 0 );
		sc_push_channel( current_cal, SC_ALL_CHANNELS );
		for( range = 0; range < num_ai_ranges; range++ )
			if( is_bipolar( setup->dev, setup->ad_subdev, 0, range ) )
				sc_push_range( current_cal, range );
		postgain_bip = setup->caldacs[ layout->adc_postgain_offset( 0 ) ].value;
		/* unipolar postgain */
		if( layout->do_adc_unipolar_postgain )
		{
			current_cal = sc_alloc_calibration_setting(setup->new_calibration);
			generic_do_adc_postgain_offset( setup, layout, current_cal, 0, 1 );
			sc_push_channel( current_cal, SC_ALL_CHANNELS );
		}
		for( range = 0; range < num_ai_ranges; range++ )
			if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
				sc_push_range( current_cal, range );
		postgain_unip = setup->caldacs[ layout->adc_postgain_offset( 0 ) ].value;
	}else
		postgain_bip = postgain_unip = -1;

	for( range = 0; range < num_ai_ranges; range++ )
	{
		current_cal = sc_alloc_calibration_setting(setup->new_calibration);
		generic_prep_adc_caldacs( setup, layout, 0, range );
		if( is_unipolar( setup->dev, setup->ad_subdev, 0, range ) )
			update_caldac( setup, layout->adc_postgain_offset( 0 ), postgain_unip );
		else
			update_caldac( setup, layout->adc_postgain_offset( 0 ), postgain_bip );
		generic_do_adc_channel( setup, layout, current_cal, 0, range );
		sc_push_channel( current_cal, SC_ALL_CHANNELS );
	}
	for( channel = 0; channel < num_ao_channels; channel++ )
	{
		for( range = 0; range < num_ao_ranges; range++ )
		{
			current_cal = sc_alloc_calibration_setting(setup->new_calibration);
			generic_prep_dac_caldacs( setup, layout, channel, range );
			generic_do_dac_channel( setup, layout, setup->new_calibration,
				current_cal, channel, range );
		}
	}
	retval = write_calibration_file(setup->cal_save_file_path, setup->new_calibration);
	return retval;
}
예제 #9
0
ComediScope::ComediScope( ComediRecord *comediRecordTmp, 
			  int channels, 
			  float f, 
			  int port_for_ext_data, 
			  int maxComediDevs,
			  int first_dev_no,
			  int req_sampling_rate,
			  const char* defaultTextStringForMissingExtData,
			  int fftdevnumber, int fftchannel, int fftmaxf
	)
    : QWidget( comediRecordTmp ) {

	channels_in_use = channels;

	tb_init=1;
	tb_counter=tb_init;
	comediRecord=comediRecordTmp;
	// erase plot
	eraseFlag = 1;

	fftdevno = fftdevnumber;
	fftch = fftchannel;
	fftmaxfrequency = fftmaxf;

	// for ASCII
	rec_file=NULL;

	// filename
	rec_filename=new QString();

	// flag if data has been recorded and we need a new filename
	recorded=0;

	if (port_for_ext_data>0) {
		fprintf(stderr,
			"Expecting a connection on TCP port %d. \n"
			"Start your client now, for example: \n"
			"telnet localhost %d\n"
			"Press Ctrl-C to abort.\n",
			port_for_ext_data,
			port_for_ext_data);
		ext_data_receive = new Ext_data_receive(
			port_for_ext_data,
			defaultTextStringForMissingExtData
			);
	} else {
		ext_data_receive = NULL;
	}	


	//////////////////////////////////////////////////////////////

	setAttribute(Qt::WA_OpaquePaintEvent);

	int range = 0;
	int aref = AREF_GROUND;
	// do not produce NAN for out of range behaviour
	comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER);

	// create an array which keeps the comedi devices
	dev = new comedi_t*[maxComediDevs];
	for(int devNo=0;devNo<maxComediDevs;devNo++) {
		dev[devNo] = NULL;
	}
	// let's probe how many we have
	nComediDevices = 0;
	for(int devNo=0;devNo<maxComediDevs;devNo++) {
		char filename[128];
		sprintf(filename,"/dev/comedi%d",devNo+first_dev_no);
		dev[devNo] = comedi_open(filename);
		if(dev[devNo]){
			nComediDevices = devNo + 1;
		} else {
			break;
		}
	}

	// none detected
	if (nComediDevices<1) {
		fprintf(stderr,"No comedi devices detected!\n");
		exit(1);
	}

	// create channel lists
	chanlist = new unsigned int*[nComediDevices];
	// create command structures
	cmd = new comedi_cmd*[nComediDevices];
	// find the subdevice which is analogue in
	subdevice = comedi_find_subdevice_by_type(dev[0],COMEDI_SUBD_AI,0);

	// check if user has specified channels or if requested
	// number of channels make sense
	if ((channels_in_use < 1)||
	    (channels_in_use > comedi_get_n_channels(dev[0],subdevice)))
	{
		channels_in_use = comedi_get_n_channels(dev[0],subdevice);
	}

	// create channel lists and the command structures
	for(int devNo=0;devNo<nComediDevices;devNo++) {
		chanlist[devNo] = new unsigned int[channels_in_use];
		assert( chanlist[devNo]!=NULL );
		for(int i=0;i<channels_in_use;i++){
			chanlist[devNo][i] = CR_PACK(i,range,aref);
		}
		cmd[devNo] = new comedi_cmd;
		assert( dev[devNo]!=NULL );
		int r = comedi_get_cmd_generic_timed(dev[devNo],
						     subdevice,
						     cmd[devNo],
						     channels_in_use,
						     (int)(1e9/req_sampling_rate));
		if(r<0){
			comedi_perror("comedi_get_cmd_generic_timed failed\n");
			exit(-1);
		}
		/* Modify parts of the command */
		cmd[devNo]->chanlist           = chanlist[devNo];
		cmd[devNo]->chanlist_len       = channels_in_use;
		cmd[devNo]->scan_end_arg = channels_in_use;
		cmd[devNo]->stop_src=TRIG_NONE;
		cmd[devNo]->stop_arg=0;
		int ret = comedi_command_test(dev[devNo],cmd[devNo]);
		if(ret<0){
			comedi_perror("1st comedi_command_test failed\n");
			exit(-1);
		}
		ret = comedi_command_test(dev[devNo],cmd[devNo]);
		if(ret<0){
			comedi_perror("2nd comedi_command_test failed\n");
			exit(-1);
		}
		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 ((cmd[0]->convert_src ==  TRIG_TIMER)&&(cmd[0]->convert_arg)) {
		sampling_rate=((1E9 / cmd[0]->convert_arg)/channels_in_use);
	}
	
	// the timing is done scan by scan (all channels at once)
	// the sampling rate is equivalent of the scan_begin_arg
	if ((cmd[0]->scan_begin_src ==  TRIG_TIMER)&&(cmd[0]->scan_begin_arg)) {
		sampling_rate=1E9 / cmd[0]->scan_begin_arg;
	}

	// initialise the graphics stuff
	ypos = new int**[nComediDevices];
	assert(ypos != NULL);
	for(int devNo=0;devNo<nComediDevices;devNo++) {
		ypos[devNo]=new int*[channels_in_use];
		assert(ypos[devNo] != NULL);
		for(int i=0;i<channels_in_use;i++) {
			ypos[devNo][i] = new int[MAX_DISP_X];
			assert( ypos[devNo][i] != NULL);
			for(int j=0;j<MAX_DISP_X;j++) {
				ypos[devNo][i][j]=0;
			}
		}
	}

	xpos=0;
	nsamples=0;

	maxdata = new lsampl_t[nComediDevices];
	assert( maxdata != NULL );
	crange = new comedi_range*[nComediDevices];
	assert( crange != NULL );
	for(int devNo=0;devNo<nComediDevices;devNo++) {
		// we just go for the default ranges
		maxdata[devNo]=comedi_get_maxdata(dev[devNo],subdevice,0);
		crange[devNo]=comedi_get_range(dev[devNo],subdevice,0,0);
	}

	// 50Hz or 60Hz mains notch filter
	iirnotch = new Iir::Butterworth::BandStop<IIRORDER>**[nComediDevices];
	assert( iirnotch != NULL );
	adAvgBuffer = new float*[nComediDevices];
	assert( adAvgBuffer != NULL );
	daqData = new lsampl_t*[nComediDevices];
	assert( daqData != NULL );
	for(int devNo=0;devNo<nComediDevices;devNo++) {
		iirnotch[devNo] = new Iir::Butterworth::BandStop<IIRORDER>*[channels_in_use];
		assert( iirnotch[devNo] != NULL );
		// floating point buffer for plotting
		adAvgBuffer[devNo]=new float[channels_in_use];
		assert( adAvgBuffer[devNo] != NULL );
		for(int i=0;i<channels_in_use;i++) {
			adAvgBuffer[devNo][i]=0;
			iirnotch[devNo][i] = new Iir::Butterworth::BandStop<IIRORDER>;
			assert( iirnotch[devNo][i] != NULL );
		}
		// raw data buffer for saving the data
		daqData[devNo] = new lsampl_t[channels_in_use];
		assert( daqData[devNo] != NULL );
		for(int i=0;i<channels_in_use;i++) {
			daqData[devNo][i]=0;
		}
	}

	setNotchFrequency(f);

	counter = new QTimer( this );
	assert( counter != NULL );
	connect( counter, 
		 SIGNAL(timeout()),
		 this, 
		 SLOT(updateTime()) );
}
예제 #10
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;
}
예제 #11
0
 unsigned int ComediSubDeviceDIn::nbOfInputs() const
 {
   if (!myCard) return 0;
   return comedi_get_n_channels(myCard->getDevice()->it, _subDevice);
 }
예제 #12
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);

}
예제 #13
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;
    }
예제 #14
0
static void mdlStart(SimStruct *S)
{
#ifndef MATLAB_MEX_FILE
  void *dev;
  int subdev;
  int index = (int)COMEDI_DEVICE - 1;
  unsigned int channel = (unsigned int)COMEDI_CHANNEL;
  unsigned int range   = (unsigned int)COMEDI_RANGE;
  int n_channels;
  char *devname[4] = {"/dev/comedi0","/dev/comedi1","/dev/comedi2","/dev/comedi3"};
  char board[50];
  static char_T errMsg[256];
  comedi_krange krange;
  double range_min, range_max;
	
  if (!ComediDev[index]) {
    dev = comedi_open(devname[index]);
    if (!dev) {
      sprintf(errMsg, "Comedi open failed\n");
      ssSetErrorStatus(S, errMsg);
      printf("%s", errMsg);
      return;
    }
    rt_comedi_get_board_name(dev, board);
    printf("COMEDI %s (%s) opened.\n\n", devname[index], board);
    ComediDev[index] = dev;
  } else {
    dev = ComediDev[index];
  }

  if ((subdev = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AI, 0)) < 0) {
    sprintf(errMsg, "Comedi find_subdevice failed (No analog input)\n");
    ssSetErrorStatus(S, errMsg);
    printf("%s", errMsg);
    comedi_close(dev);
    return;
  }
  if (!ComediDev_AIInUse[index] && comedi_lock(dev, subdev) < 0) {
    sprintf(errMsg, "Comedi lock failed for subdevice %d\n", subdev);
    ssSetErrorStatus(S, errMsg);
    printf("%s", errMsg);
    comedi_close(dev);
    return;
  }

  if ((n_channels = comedi_get_n_channels(dev, subdev)) < 0) {
    sprintf(errMsg, "Comedi get_n_channels failed for subdevice %d\n", subdev);
    ssSetErrorStatus(S, errMsg);
    printf("%s", errMsg);
    comedi_unlock(dev, subdev);
    comedi_close(dev);
    return;
  }

  if ((comedi_get_krange(dev, subdev, channel, range, &krange)) < 0) {
    sprintf(errMsg, "Comedi get range failed for subdevice %d\n", subdev);
    ssSetErrorStatus(S, errMsg);
    printf("%s", errMsg);
    comedi_unlock(dev, subdev);
    comedi_close(dev);
    return;
  }

  ComediDev_InUse[index]++;
  ComediDev_AIInUse[index]++;
  range_min = (double)(krange.min)*1.e-6;
  range_max = (double)(krange.max)*1.e-6;
  printf("AI Channel %d - Range : %1.2f [V] - %1.2f [V]\n", channel, range_min, range_max);
  ssGetPWork(S)[0] = (void *)dev;
  ssGetIWork(S)[0] = subdev;
  ssGetRWork(S)[0] = range_min;
  ssGetRWork(S)[1] = range_max;
#endif
}
예제 #15
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":"");
}
예제 #16
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;
}