damaris-backends/drivers/Datel-PCI416/Datel-PCI416.cpp
2014-06-26 11:10:51 +00:00

234 lines
7.4 KiB
C++

/* **************************************************************************
Author: Achim Gaedke
Created: June 2004
****************************************************************************/
#include "core/core.h"
#include "Datel-PCI416.h"
DatelPCI416::DatelPCI416(const ttlout& t_line){
trigger_line=t_line;
PCI_DLL = LoadLibrary("PCI41632");
if (PCI_DLL==NULL) {
throw ADC_exception("found no library\n");
}
/* import all functions from dll and exit on error*/
# define pci41632dll_getproc(name) \
name = (TFP_ ## name)GetProcAddress(PCI_DLL,#name); \
if (name == NULL) {FreeLibrary(PCI_DLL); throw ADC_exception("found no " #name " function in DLL");}
# include "PCI416_func_import.cpp"
if (pci416_init(&brdcount)!=NOERROR) {
brdcount=0;
throw ADC_exception("initialisation failed");
}
// now hardcoded, use first board
board=0;
if (NOERROR!=pci416_getcaps(board,4,caps))
throw ADC_exception("getcaps failed");
fprintf(stderr,"Datel PCI416 caps: FIFO size: %d, DMA size: %d, index ADM %d, acqmode %d\n",caps[0],caps[1],caps[2],caps[3]);
sample_count=0;
trigger_count=0;
sample_frequency=0;
trigger_line.ttls=1<<2;
trigger_line.id=0;
}
DatelPCI416::~DatelPCI416() {
pci416_close(board);
FreeLibrary(PCI_DLL);
}
/**
here the data aquisition unit is configured and adds the necessary pusle components to the program
*/
void DatelPCI416::set_daq(state& exp) {
sample_count=0;
trigger_count=0;
sample_frequency=0;
// todo: cleanup before exception...
state_iterator si(dynamic_cast<state_sequent&>(exp));
state* a_state=(state*)si.get_state();
/* loop over all states */
while (NULL!=a_state) {
// collect analogin sections in state
std::list<analogin*> inputs;
/* loop over all device definitions in a state */
state::iterator i=a_state->begin();
while (i!=a_state->end()) {
analogin* input=dynamic_cast<analogin*>(*i);
if (input!=NULL) {
/* collect appropiate analogin sections, forget others */
if (input->samples<=0 || input->sample_frequency<=0)
delete input;
else
inputs.push_back(input);
i=a_state->erase(i);
}
else
++i;
}
if (!inputs.empty()) {
/* evaluate the found analogin definitions */
if (inputs.size()>1) {
while (!inputs.empty()) {delete inputs.front(); inputs.pop_front();}
throw ADC_exception("can not handle more than one analogin section per state");
}
if (trigger_count==0) {
sample_count=inputs.front()->samples;
sample_frequency=inputs.front()->sample_frequency;
trigger_count=si.get_count();
}
else if ( sample_count==inputs.front()->samples && sample_frequency==inputs.front()->sample_frequency ) {
trigger_count+=si.get_count();
}
else {
while (!inputs.empty()) {delete inputs.front(); inputs.pop_front();}
throw ADC_exception("Sorry, but multittriggering requires same parameters in all analogin sections");
}
if (a_state->length<1.0*sample_count/sample_frequency) {
fprintf(stderr,"WARINING: state is shorter than aquisition time\n");
}
a_state->push_back(trigger_line.copy_new());
// to do: more analogin sections per state
while (!inputs.empty()) {delete inputs.front(); inputs.pop_front();}
}
// send a trigger pulse
// todo only short trigger pulse
a_state=(state*)si.next_state();
}
/* nothing to do! */
if (trigger_count==0 || sample_count==0) return;
if (sample_count*trigger_count*4>caps[1])
throw ADC_exception("required dma buffer size is too big for pci slot config");
fprintf(stderr,"samples: %d, triggers: %d, frequency=%f\n", sample_count, trigger_count, sample_frequency);
/* initialise board */
if (NOERROR!=set_modes(board,
0, // clock source: 0=internal
sample_frequency, // sample rate
sample_count*2, // samples per trigger
1, // trigger src: 0=internal, 1=external digital
1, // channel (1= Ch1 and Ch2)
0, // pretrigger
1, // scan (multichannel=1)
0 // marker
))
throw ADC_exception("set_modes failed...");
// clear fifo, even when using dma
if (NOERROR!=pci416_clear_fifo(board)) throw ADC_exception("clear_fifo failed");
DWORD dma_buffer_size[2];
dma_buffer_size[0]=dma_buffer_size[1]=sample_count*trigger_count*4; //bytes
dma_buffer_handle=0;
if (NOERROR!=pci416_setup_dma(board,DMA_SINGLE,dma_buffer_size,&dma_buffer_handle))
throw ADC_exception("setup_dma failed");
// start single aquisition
double freq=1.0;
// start_daq(board, trigger_mode, frequency) trigger mode: 0 external
if (NOERROR!=start_daq(board,0,&freq)) throw ADC_exception("start_daq failed");
}
adc_result* DatelPCI416::get_samples(double timeout) {
// nothing to do here
if (trigger_count==0 || sample_count==0) return new adc_result(1,0,NULL);
const size_t poll_time=10000;
double time_spent=0;
// busy wait for end
fprintf(stderr,"waiting for ADC");
while (core::term_signal==0) {
DWORD dma_status=0;
// status NOT DONE=0, Done=1
if (pci416_dma_status(board,&dma_status)!=NOERROR)
throw ADC_exception("dma_status failed");
if (dma_status!=0) break;
usleep(poll_time);
time_spent+=1e-6*poll_time;
fprintf(stderr,".",dma_status);
fflush(stderr);
if (time_spent>timeout) {
fprintf(stderr," timeout!\n");
throw ADC_exception("ran into timeout!");
}
}
fprintf(stderr," done\n");
if (core::term_signal!=0) return NULL;
if (NOERROR!=stop_daq(board))
throw ADC_exception("stop daq failed");
if(NOERROR!=pci416_stop_dma(board,NULL))
throw ADC_exception("stop_dma failed");
// copy results...
DWORD resulting_bytes=sample_count*trigger_count*4; // bytes
short int* data=(short int*)malloc(resulting_bytes);
if (data==NULL) throw ADC_exception("Could not allocate enough memory");
if (NOERROR!=pci416_copy_dmabuffer(board, DMA_SINGLE, 0, &resulting_bytes, (DWORD*)data)) {
free(data);
throw ADC_exception("copy_dmabuffer failed");
}
#if 0
fprintf(stderr,"got %d bytes back\n",resulting_bytes);
FILE* binfile=fopen("/tmp/bla.bin","w+");
if (binfile!=NULL) {
fwrite(data,1,resulting_bytes, binfile);
fclose(binfile);
}
else
fprintf(stderr,"could not open file\n");
#endif
/* return them */
return new adc_result(1, sample_count*trigger_count, data, sample_frequency);
}
void DatelPCI416::sample_after_external_trigger(const double rate, const size_t samples, double sensitivity, size_t resolution) {
const int board=0;
// try dma
if (NOERROR!=set_modes(board,
0, // clock source: 0=internal
rate, // sample rate
samples*2, // samples per trigger
1, // trigger src: 0=internal, external digital =1
1, // channel (1= Ch1 and Ch2)
0, // pretrigger
1, // scan
0 // marker
))
throw ADC_exception("set_modes failed...");
// clear fifo, even when using dma
if (NOERROR!=pci416_clear_fifo(board)) throw ADC_exception("clear_fifo failed");
DWORD dma_buffer_size[2];
dma_buffer_size[0]=dma_buffer_size[1]=samples*trigger_count*4; //bytes
DWORD dma_buffer_handle=0;
if (NOERROR!=pci416_setup_dma(board,DMA_SINGLE,dma_buffer_size,&dma_buffer_handle))
throw ADC_exception("setup_dma failed");
fprintf(stderr,"buffersize %d\n",dma_buffer_size[0]);
// start single aquisition
double freq=1.0;
if (NOERROR!=start_daq(board,0,&freq)) throw ADC_exception("start_daq failed");
}