// // // // g++ -o tiIO -I$LINUXVME_INC tiIO.cc -L$LINUXVME_LIB -lti -ljvme -lremex // // #include #include #include #include using namespace std; #include #include #include #include #include extern "C"{ #include #include extern int nfa125; extern int fa125A32Base; DMA_MEM_ID vmeIN,vmeOUT; extern unsigned int *dma_dabufp; extern DMANODE *the_event; // These copied from tiLib.c to allow low-level operations that are // not provided by library. extern volatile struct TI_A24RegStruct *TIp; extern pthread_mutex_t tiMutex; #define TILOCK if(pthread_mutex_lock(&tiMutex)<0) perror("pthread_mutex_lock"); #define TIUNLOCK if(pthread_mutex_unlock(&tiMutex)<0) perror("pthread_mutex_unlock"); } #define BIT(A,B) ((A>>B)&0x1) bool gPRINT_STATUS = false; int gOUTPUT_MASK = 0; int gOUTPUT_VAL = -1; int gOUTPUT_INITIAL = 0; long gOUTPUT_WIDTH = 10; int gNPULSES = 0; double gRATE_HZ = 100; bool gIS_RANDOM = false; //---------------------- // Usage //---------------------- void Usage(string mess="") { cout << "" << endl; cout << "Usage:" << endl; cout << " tiIO [options]" << endl; cout << "" << endl; cout << "This program can be used to pulse or set the TI module's" << endl; cout << "front panel outputs marked O#1 - O#4. Pulsing the output" << endl; cout << "is useful when it is connected to one of the trigger inputs." << endl; cout << "This allows one to test the external triggering." << endl; cout << "" << endl; cout << "options:" << endl; cout << "" << endl; cout << " -h print this usage statement." << endl; cout << " -S print TI status and exit." << endl; cout << " -b # output to modify (1-4). Can be given more than once to modify" << endl; cout << " more than one output" << endl; cout << " -s # set output to # which should be either 1 or 0" << endl; cout << " -N # pulse output this number of times (more details below)" << endl; cout << " -w pulse width in ns. (Limited by OS)" << endl; cout << " -r rate to pulse in Hz" << endl; cout << " -R randomize time between pulses" << endl; cout << "" << endl; cout << "The -s option is used to simply set the level of the output. It is" << endl; cout << "mutually exclusive with the -N option. Either the -s or the -N" << endl; cout << "option must be given, but not both." << endl; cout << "" << endl; cout << "If the -N option is used then the specified output channels" << endl; cout << "are initially set to 0 before the first pulse is issued. They" << endl; cout << "are also set to zero after the pulsing completes." << endl; cout << "" << endl; cout << "The pulse width is by setting the output high and then calling" << endl; cout << "nanosleep for the specified time before setting it low. The" << endl; cout << "OS will limit how small this can be (possibly microseconds)." << endl; cout << "Similarly, the rate is controlled by adjusting the time between" << endl; cout << "pulses. Again, this may run into limitations from the OS or" << endl; cout << "overheads from VME communication that cause the actual rate to" << endl; cout << "differ from what is specified." << endl; cout << "" << endl; cout << mess << endl; exit(0); } //---------------------- // ParseCommandLineArguments //---------------------- void ParseCommandLineArguments(int argc, char *argv[]) { if(argc<=1) Usage(); for(int i=1;i4)Usage("Argument to option\"-b\" must be 1,2,3, or 4 !"); gOUTPUT_MASK |= 1 << (bit-1); } if(arg=="-s"){ int val = atoi(next.c_str()); if(val<0 || val>1) Usage("Argument to option \"-s\" must be 0 or 1 !"); gOUTPUT_VAL = val; } if(arg=="-S") gPRINT_STATUS = true; if(arg=="-w") gOUTPUT_WIDTH = atoi(next.c_str()); if(arg=="-r") gRATE_HZ = atoi(next.c_str()); if(arg=="-N") gNPULSES = atoi(next.c_str()); if(arg=="-R") gIS_RANDOM = true; } if(gNPULSES>0){ if(gOUTPUT_VAL!=-1) Usage("ONLY ONE OF \"-s\" or \"-N\" MAY BE SPECIFIED!"); if(gRATE_HZ<0.01) Usage("Option \"-R\" requires value greater than 0.01!"); } } //---------------------- // SetMasked //---------------------- int SetMasked(int val) { int outputs = 0x0; for(int i=0; i<4; i++){ int v = BIT(gOUTPUT_INITIAL, i); if( BIT(gOUTPUT_MASK,i) ) v = val; outputs |= (v<output); TIUNLOCK; gOUTPUT_INITIAL &= 0x0F; cout << "outputs found set to: 0x" << hex << gOUTPUT_INITIAL << dec << endl; //--------- Set output level if(gOUTPUT_VAL != -1){ int outputs = SetMasked(gOUTPUT_VAL); tiSetOutputPort(BIT(outputs,0), BIT(outputs,1), BIT(outputs,2), BIT(outputs,3)); } //-------- Pulse output printf("TS#1 scaler: %d\n", tiGetTSscaler(1, 1)); // Set time delays // double Tpulse = 1.8E-3; // empirically determined time to generate pulse // double Ttot = 1.0/gRATE_HZ; // double Tdelay = Ttot - Tpulse; // if(Tdelay<0.0) Tdelay==0.0; // time_t Tdelay_sec = (time_t)floor(Tdelay); // long Tdelay_ns = (long)((Tdelay-(double)Tdelay_sec)*1.0E9); // struct timespec delay_width = {0, gOUTPUT_WIDTH}; // struct timespec delay_rate = {Tdelay_sec, Tdelay_ns}; // Fill array of times to delay between events. For fixed rate, // these will all be the same. For random rate, these will // differ. Theses will be looped over as many times as needed // to send N triggers. It is done this way to prevent lots // of calculations within the loop which would make the // rate less accurate. #define Ntimes 10000 struct timespec delays[Ntimes]; double Ttot = 1.0/gRATE_HZ; double Tpulse = 1.8E-3; // empirically determined time to generate pulse double T = Ttot - Tpulse; // average period we actually want to sample from cout << "Generating time delays ..."; cout.flush(); for(int i=0; ioutput); TIUNLOCK; outputs &= 0x0F; cout << "outputs left set to: 0x" << hex << outputs << dec << endl; cout << endl; cout << "Done." << endl; return 0; }