/** * Start the the ADC sampling, unless the external trigger command * is set it will begin sampling as soon as the usbdux device has been * initialized. * The final three arguments are very important to get right * as the recorder thread will use them to determine where to write it's samples and * when it's reached end of the buffer. It doesn't care about the c_buffer class * at all. * @param arg_device name of the comedi device e.g., 'comedi0' * @param arg_sample_rate the rate the usb_dux should sample with in hertz (max=3[Mhz]}) * @param arg_start_address the start address of the circle buffer sample should be loading into * @param arg_end_address the end address of the cicle buffer. * @param arg_buffer_size byte size of the buffer. */ int start_Sampling(char* arg_device, uint32_t arg_sample_rate, char* arg_start_address, char* arg_end_address, int arg_buffer_size){ _channel_amount = 16; _sample_rate = arg_sample_rate; unsigned int chanlist[_channel_amount]; unsigned int convert_arg = 1e9 / _sample_rate; int ret; comedi_cmd *cmd = (comedi_cmd *) calloc(1, sizeof(comedi_cmd)); _device = comedi_open(arg_device); int buffer = 1048576*40; buffer = (buffer * 4096)/4096; if(comedi_set_max_buffer_size(_device, 0, buffer) < 0 ){ printf("Failed to set max buffer size to %i bytes\n", buffer); return -1; } else printf("Maximum buffer size set to %i bytes\n", comedi_get_max_buffer_size(_device,0)); if(comedi_set_buffer_size(_device, 0, buffer) < 0){ printf("Failed to set buffer size to %iBytes\n", buffer); return -1; } else printf("Buffer size set to %iBytes\n", comedi_get_buffer_size(_device,0)); if(!_device){ errx(1, "unable to open device"); comedi_perror("/dev/comedi0"); return -1; } for(int i = 0; i < _channel_amount; i++) chanlist[i] = i; comedi_set_global_oor_behavior(COMEDI_OOR_NUMBER); if((ret = comedi_get_cmd_generic_timed(_device, 0, cmd, _channel_amount,0)) < 0){ printf("comedi_get_cmd_generic_timed failed\n"); return ret; } cmd->chanlist = chanlist; cmd->stop_src = TRIG_NONE; cmd->stop_arg = 0; cmd->convert_arg = convert_arg; //setup the sampling to start from the trigger. //cmd->start_src = TRIG_EXT //cmd->start_arg = 1; /* call test twice because different things are tested? * if tests are successful run sampling command */ if((ret = comedi_command_test(_device, cmd)) != 0 || (ret = comedi_command_test(_device, cmd)) != 0 || (ret = comedi_command(_device, cmd)) < 0){ fprintf(stderr, "err: %d\n", ret); return -1; } FILE* dux_fp; if((dux_fp = fdopen(comedi_fileno(_device), "r")) <= 0) comedi_perror("fdopen"); char* write_address = arg_start_address; Utility::SNAP_SAMPLE = 0; Utility::LAST_SAMPLE = 0; uint64_t active_sample = 0; uint32_t tmp_block = 0; int samples_pr_block = 4096/sizeof(Type); while((ret = fread(write_address, 1, 4096,dux_fp)) >= 0){ write_address += 4096; tmp_block += 1; active_sample += samples_pr_block; Utility::LAST_SAMPLE += samples_pr_block; if(tmp_block >= Utility::SNAPSHOT_BLOCK_SIZE){ //printf("signalling serial snapshotter\n"); tmp_block = 0; Utility::SNAP_SAMPLE = active_sample; Utility::SNAP_READY = true; Utility::CV.notify_one(); } if(write_address == arg_end_address){ write_address -= arg_buffer_size; //printf("resetting to beginning of buffer\n"); } if(_stop == true) break; } if(ret < 0) perror("read"); comedi_cancel(_device, 0); return 0; }
void *_laytube_toFile(void *args){ long unsigned int expansion_size; void *pause_after; tubeID *pTube; rohrStation sendingStation; rohrStation receivingStation; pTube = (tubeID *) args; /* Populate Station Information */ sendingStation.stationSize = comedi_get_buffer_size(pTube->dev, pTube->subdev); receivingStation.stationSize = _file_size(pTube->tail); expansion_size = 64 * sysconf(_SC_PAGESIZE); /* Set file expansion size to a mulitple of memory page size */ if (expansion_size < sendingStation.stationSize){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } /* Check for empty file */ if (receivingStation.stationSize < 1){ receivingStation.stationSize = expansion_size; /* Let's make the file one page-size in length */ ftruncate(pTube->tail, receivingStation.stationSize); } /* Set up COMEDI ring buffer memory map */ sendingStation.firstByte = mmap(NULL, sendingStation.stationSize, PROT_READ, MAP_SHARED, pTube->mouth, 0); if (sendingStation.firstByte == MAP_FAILED){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } sendingStation.address = sendingStation.firstByte; sendingStation.lastByte = sendingStation.firstByte + sendingStation.stationSize - 1; /* Last valid byte */ /* Set up HDD file memory map */ receivingStation.firstByte = mmap(NULL, receivingStation.stationSize, PROT_WRITE | MAP_HUGETLB, MAP_SHARED, pTube->tail, 0); if (receivingStation.firstByte == MAP_FAILED){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } receivingStation.address = receivingStation.firstByte; receivingStation.lastByte = receivingStation.firstByte + receivingStation.stationSize - 1; /* Last valid byte */ /* Stations are setup... set status and command flags... */ pTube->tubeCmd = 0x00; pTube->tubeStatus = TUBE_INPLACE; /* <-- un-blocks laytube_toFile to return to calling function */ /* Core algorithm - This while loop handles the data transfer from ring buffer to disk */ while( !(pTube->tubeCmd & TUBE_STOP) ){ /* Check if the storage file is out or about to be out of space */ if (sendingStation.stationSize >= (receivingStation.lastByte - receivingStation.address) ){ if (_growStation(&receivingStation, pTube->tail, expansion_size) == -1){ pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(NULL); } } pause_after = sendingStation.firstByte + comedi_get_buffer_contents(pTube->dev, pTube->subdev) - 1; if (pause_after < sendingStation.address){ pTube->bytesMoved = receivingStation.address - receivingStation.firstByte; /* comedi_poll(pTube->dev, pTube->subdev)); */ usleep(10); /* TODO: optimize by setting sleep number to best guess at when data might show up again */ } else if (pause_after < sendingStation.lastByte) /* Confirm COMEDI ring buffer has not aliased */ { do { *((CARRIER *)receivingStation.address++) = *((CARRIER *)sendingStation.address++); } while(sendingStation.address <= pause_after); } else if (pause_after >= sendingStation.lastByte) /* COMEDI ring buffer has aliased... copy up to end of ring buffer and reset */ { do { *((CARRIER *)receivingStation.address++) = *((CARRIER *)sendingStation.address++); } while(sendingStation.address <= sendingStation.lastByte); comedi_mark_buffer_read(pTube->dev, pTube->subdev, sendingStation.stationSize); /* Reset the ring buffer mark */ sendingStation.address = sendingStation.firstByte; } else { pTube->tubeStatus = pTube->tubeStatus | TUBE_FAILED; pthread_exit(0); } } /* Clean up Stations, truncate file, flush tube */ expansion_size = receivingStation.address - receivingStation.firstByte; /* 'address' should point to one byte past last byte written */ ftruncate(pTube->tail, expansion_size); fsync(pTube->tail); pTube->bytesMoved = expansion_size; pTube->tubeStatus = pTube->tubeStatus | TUBE_EXIT; pthread_exit(0); }
int PLLReferenceGeneration() { //Initial test function to try out Real time stuff. int m, i=0, err, n; lsampl_t data_to_card; static comedi_t * dev; static int OutputFIFOBufferSize; static int PLLGenerationBufferSize; unsigned int maxdata; unsigned int chanlist[16]; int ret; static lsampl_t data[PLLGenerationBufferNPoints]; //this is the buffer used to send data points out comedi_cmd cmd; dev = comedi_open(device_names[PLLReferenceGenerationChannel.board_number]); //Check the size of the output buffer OutputFIFOBufferSize = comedi_get_buffer_size(dev, PLLReferenceGenerationChannel.subdevice); rt_printk("OutputFIFO Buffer size is %i\n", OutputFIFOBufferSize); //Set the actual buffer size that we will be using to half this and the number of data points to one fourth //Now configure the output channel using a Comedi instruction //BufferSize is initially set to be double the number of PLLGenerationBufferNPoints PLLGenerationBufferSize = 2*PLLGenerationBufferNPoints; maxdata = comedi_get_maxdata(dev, PLLReferenceGenerationChannel.subdevice, PLLReferenceGenerationChannel.channel); rt_printk("PLL Reference channel max data is %i\n", maxdata); offset = maxdata / 2; amplitude = maxdata - offset; memset(&cmd,0,sizeof(cmd)); cmd.subdev = PLLReferenceGenerationChannel.subdevice; cmd.flags = CMDF_WRITE; cmd.start_src = TRIG_INT; cmd.start_arg = 0; cmd.scan_begin_src = TRIG_TIMER; cmd.scan_begin_arg = PLLGenMinPulseTime; //minimum update time for the cmd.convert_src = TRIG_NOW; cmd.convert_arg = 0; cmd.scan_end_src = TRIG_COUNT; cmd.scan_end_arg = NCHAN; //only one channel cmd.stop_src = TRIG_NONE; cmd.stop_arg = 0; cmd.chanlist = chanlist; cmd.chanlist_len = NCHAN; chanlist[0] = CR_PACK(PLLReferenceGenerationChannel.channel, AO_RANGE, AREF_GROUND); dds_init(PLLWaveformFrequency, PLLUpdateFrequency); err = comedi_command_test(dev, &cmd); if (err < 0) { comedi_perror("comedi_command_test"); exit(1); } err = comedi_command_test(dev, &cmd); if (err < 0) { comedi_perror("comedi_command_test"); exit(1); } if ((err = comedi_command(dev, &cmd)) < 0) { comedi_perror("comedi_command"); exit(1); } dds_output(data,PLLGenerationBufferNPoints); n = PLLGenerationBufferNPoints * sizeof(sampl_t); m = write(comedi_fileno(dev), (void *)data, n); if(m < 0){ perror("write"); exit(1); }else if(m < n) { fprintf(stderr, "failed to preload output buffer with %i bytes, is it too small?\n" "See the --write-buffer option of comedi_config\n", n); exit(1); } if(!(PLLRefGen_Task = rt_task_init_schmod(nam2num( "PLLReferenceGeneration" ), // Name 2, // Priority 0, // Stack Size 0, //, // max_msg_size SCHED_FIFO, // Policy CPUMAP ))) // cpus_allowed { printf("ERROR: Cannot initialize pll reference generation task\n"); exit(1); } //specify that this is to run on one CPU rt_set_runnable_on_cpuid(PLLRefGen_Task, 1); //Convert samp_time, which is in nanoseconds, to tick time //sampling_interval = nano2count(SAMP_TIME); //Converts a value from //nanoseconds to internal count units. mlockall(MCL_CURRENT|MCL_FUTURE); rt_make_hard_real_time(); PLLUpdateTime = nano2count(PLLGenerationLoopTime); rt_printk("PLL generation update time is %f12 \n",count2nano((float) PLLUpdateTime)); // Let's make this task periodic.. expected = rt_get_time() + 100*PLLUpdateTime; rt_task_make_periodic(PLLRefGen_Task, expected, PLLUpdateTime); //period in counts //rt_task_resume(Sinewaveloop_Task); PLLGenerationOn = TRUE; // Concurrent function Loop //rt_printk("SineWaveAmplitude is is %f \n",SineWaveAmplitude); //rt_printk("SineWaveFrequency is %f \n",SineWaveFrequency); //rt_printk("sine_loop_running is %d \n",sine_loop_running); //rt_printk("SAMP_TIME is %d \n",SAMP_TIME); start_time = (float)rt_get_time_ns()/1E9; //in seconds old_time = start_time; rt_printk("PLLReferenceGenerationChannel board_it is %p \n",PLLReferenceGenerationChannel.board_id); rt_printk("PLLReferenceGenerationChannel devicename is %p \n",*(PLLReferenceGenerationChannel.devicename)); rt_printk("PLLReferenceGenerationChannel boardname is %p \n",*(PLLReferenceGenerationChannel.boardname)); rt_printk("PLLReferenceGenerationChannel subdevice is %d \n",PLLReferenceGenerationChannel.subdevice); rt_printk("PLLReferenceGenerationChannel channel is %d \n",PLLReferenceGenerationChannel.channel); OutputValue = 1; PLLGenerationBufferSize = comedi_get_buffer_size(dev, PLLReferenceGenerationChannel.subdevice); //sine_loop_running = 0; //set this to 0 for testing while(PLLGenerationOn) { i++; // Count Loops. current_time = (float)rt_get_time_ns()/1E9; //rt_printk("LOOP %d,-- Period time: %f12 %f12\n",i, current_time - old_time,count2nano((float)sampling_interval)/1E9); OutputValue = SineWaveAmplitude*sin(2*PI*SineWaveFrequency*(current_time-start_time)); //OutputValue = -1*OutputValue; //rt_printk("OutputValue is %f12 \n",OutputValue); data_to_card = (lsampl_t) nearbyint(((OutputValue - MinOutputVoltage)/OutputRange)*MaxOutputBits); //m=rt_comedi_command_data_write(AnalogOutputChannel.board_id, AnalogOutputChannel.subdevice, NCHAN, data_to_card); comedi_lock(dev, AnalogOutputChannel.subdevice); m=comedi_data_write(dev, AnalogOutputChannel.subdevice, AnalogOutputChannel.channel, AO_RANGE, AREF_DIFF, data_to_card); comedi_unlock(dev, AnalogOutputChannel.subdevice); // m=comedi_data_write(AnalogOutputChannel.board_id, AnalogOutputChannel.subdevice, // AnalogOutputChannel.channel, AO_RANGE, AREF_GROUND, data_to_card); //rt_printk("Data_to_card is %d; result from rt_comedi_command_data_write is %d \n",data_to_card, m); //rt_printk("LOOP %d,-- AO Out time: %f12 \n",i, (float)rt_get_time_ns()/1E9 - current_time); //rt_printk("Data_to_card is %d \n",data_to_card); //old_time = current_time; /* if (i== 100000) { sine_loop_running = 0; //printf("LOOP -- run: %d %d\n ",keep_on_running,&keep_on_running); //printf("RTAI LOOP -- run: %d \n ",i); break; } */ rt_task_wait_period(); // And waits until the end of the period. } rt_make_soft_real_time(); comedi_close(dev); rt_task_delete(Sinewaveloop_Task); //Self termination at end. pthread_exit(NULL); return 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; }