/***************************************************************** * * tiprimary_list.c - "Primary" Readout list routines for tiprimary * * Usage: * * #include "tiprimary_list.c" * * then define the following routines: * * void rocDownload(); * void rocPrestart(); * void rocGo(); * void rocEnd(); * void rocTrigger(); * * SVN: $Rev: 11433 $ * */ //-------------- RCM MONOTORING ------------------- #include "shmem_roc.h" static void shmem_get(); static int semid,shmid; static roc_shmem *shmem_ptr; struct timeval tvA[10], tvB[10]; SHM_HIST *hrol1; //-------------------------------------------------- #define ROL_NAME__ "TIPRIMARY" #ifndef MAX_EVENT_LENGTH /* Check if an older definition is used */ #ifdef MAX_SIZE_EVENTS #define MAX_EVENT_LENGTH MAX_SIZE_EVENTS #else #define MAX_EVENT_LENGTH 10240 #endif /* MAX_SIZE_EVENTS */ #endif /* MAX_EVENT_LENGTH */ #ifndef MAX_EVENT_POOL /* Check if an older definition is used */ #ifdef MAX_NUM_EVENTS #define MAX_EVENT_POOL MAX_NUM_EVENTS #else #define MAX_EVENT_POOL 400 #endif /* MAX_NUM_EVENTS */ #endif /* MAX_EVENT_POOL */ /* POLLING_MODE */ #define POLLING___ #define POLLING_MODE /* INIT_NAME should be defined by roc_### (maybe at compilation time - check Makefile-rol) */ #ifndef INIT_NAME #warn "INIT_NAME undefined. Setting to tiprimary_list__init" #define INIT_NAME tiprimary_list__init #endif #include #include #include "jvme.h" #include #include "tiLib.h" extern int bigendian_out; extern int tiFiberLatencyOffset; /* offset for fiber latency */ extern int tiDoAck; extern int tiNeedAck; /*! Buffer node pointer */ extern DMANODE *the_event; /*! Data pointer */ extern unsigned int *dma_dabufp; /* Redefine tsCrate according to TI_MASTER or TI_SLAVE */ #ifdef TI_SLAVE int tsCrate=0; #else #ifdef TI_MASTER int tsCrate=1; #endif #endif int chuck=0; int emptyCount = 0; /* Count the number of times event buffers are empty */ #define ISR_INTLOCK INTLOCK #define ISR_INTUNLOCK INTUNLOCK pthread_mutex_t ack_mutex=PTHREAD_MUTEX_INITIALIZER; #define ACKLOCK { \ if(pthread_mutex_lock(&ack_mutex)<0) \ perror("pthread_mutex_lock"); \ } #define ACKUNLOCK { \ if(pthread_mutex_unlock(&ack_mutex)<0) \ perror("pthread_mutex_unlock"); \ } pthread_cond_t ack_cv = PTHREAD_COND_INITIALIZER; #define ACKWAIT { \ if(pthread_cond_wait(&ack_cv, &ack_mutex)<0) \ perror("pthread_cond_wait"); \ } #define ACKSIGNAL { \ if(pthread_cond_signal(&ack_cv)<0) \ perror("pthread_cond_signal"); \ } int ack_runend=0; /* ROC Function prototypes defined by the user */ void rocDownload(); void rocPrestart(); void rocGo(); void rocEnd(); void rocTrigger(int arg); void rocCleanup(); int getOutQueueCount(); int getInQueueCount(); void doAck(); /* Asynchronous (to tiprimary rol) trigger routine, connects to rocTrigger */ void asyncTrigger(); /* Input and Output Partitions for VME Readout */ DMA_MEM_ID vmeIN, vmeOUT; static void __download() { int status; daLogMsg("INFO","Readout list compiled %s", DAYTIME); #ifdef POLLING___ rol->poll = 1; #endif *(rol->async_roc) = 0; /* Normal ROC */ //==================== SHMEM =============== daLogMsg("INFO","Attach shared memory "); shmem_get(); hrol1 = shmem_ptr->H_rol1; hbook1(hrol1,1,"Trigger time ",500,0.,500.); bigendian_out=1; pthread_mutex_init(&ack_mutex, NULL); pthread_cond_init(&ack_cv,NULL); /* Open the default VME windows */ vmeOpenDefaultWindows(); /* Initialize memory partition library */ dmaPartInit(); /* Setup Buffer memory to store events */ dmaPFreeAll(); vmeIN = dmaPCreate("vmeIN",MAX_EVENT_LENGTH,MAX_EVENT_POOL,0); vmeOUT = dmaPCreate("vmeOUT",0,0,0); /* Reinitialize the Buffer memory */ dmaPReInitAll(); dmaPStatsAll(); /* Initialize VME Interrupt interface - use defaults */ tiFiberLatencyOffset = FIBER_LATENCY_OFFSET; tiInit(TI_ADDR,TI_READOUT,0); /* Set crate ID */ tiSetCrateID(ROCID); printf("TI CrateID register set to %d\n",ROCID); /* Set timestamp format 48 bits */ tiSetEventFormat(3); /* Execute User defined download */ rocDownload(); daLogMsg("INFO","Download Executed"); tiDisableVXSSignals(); } /*end download */ static void __prestart() { ACKLOCK; ack_runend=0; ACKUNLOCK; CTRIGINIT; *(rol->nevents) = 0; unsigned long jj, adc_id; daLogMsg("INFO","Entering Prestart"); chuck=0; TIPRIMARY_INIT; CTRIGRSS(TIPRIMARY,1,usrtrig,usrtrig_done); CRTTYPE(1,TIPRIMARY,1); /* If the TI Master, send a Clock and Trig Link Reset */ #ifdef TI_MASTER tiClockReset(); taskDelay(2); tiTrigLinkReset(); #endif tiEnableVXSSignals(); /* Execute User defined prestart */ rocPrestart(); /* If the TI Master, send a Sync Reset - required by FADC250 after it is enabled */ #ifdef TI_MASTER printf("%s: Sending sync as TI master\n",__FUNCTION__); sleep(1); tiSyncReset(1); /* set the Block Level */ taskDelay(2); printf(" SASCHA SET BLOCK LEVEL ONCE AGAIN \n"); tiSetBlockBufferLevel(blockLevel); #endif /* Connect User Trigger Routine */ tiIntConnect(TI_INT_VEC,asyncTrigger,0); daLogMsg("INFO","Prestart Executed"); if (__the_event__) WRITE_EVENT_; *(rol->nevents) = 0; rol->recNb = 0; } /*end prestart */ static void __end() { int ii, ievt, rem_count; int len, type, lock_key; DMANODE *outEvent; int oldnumber; int iwait=0; int blocksLeft=0; unsigned int blockstatus=0; int bready=0; /* Stop the madness */ if(tsCrate) { tiDisableTriggerSource(1); } printf("%s: Starting purge of TI blocks\n",__FUNCTION__); while(iwait<10000) { iwait++; if (getOutQueueCount()>0) { /* chuck=1; */ printf("Purging an event in vmeOUT (iwait = %d, count = %d)\n",iwait, getOutQueueCount()); /* This wont work without a secondary readout list (will crash EB or hang the ROC) */ __poll(); } bready=tiBReady(); if(tsCrate) blockstatus=tiBlockStatus(0,0); else blockstatus=0; if(bready==0) { if(blockstatus==0) { printf("tiBlockStatus = 0x%x tiBReady() = %d\n", blockstatus,bready); break; } } } if(tsCrate) tiBlockStatus(0,1); printf("%s: DONE with purge of TI blocks\n",__FUNCTION__); INTLOCK; INTUNLOCK; iwait=0; printf("starting secondary poll loops\n"); while(iwait<10000) { iwait++; if(iwait>10000) { printf("Halt on iwait>10000\n"); break; } if(getOutQueueCount()>0) __poll(); else break; } printf("secondary __poll loops %d\n",iwait++); tiStatus(0); dmaPStatsAll(); tiIntDisable(); tiIntDisconnect(); printf("vmeIN empty buffer count = %d\n",emptyCount); /* Execute User defined end */ rocEnd(); CDODISABLE(TIPRIMARY,1,0); /* we need to make sure all events taken by the VME are collected from the vmeOUT queue */ /* rem_count = getOutQueueCount(); */ /* if (rem_count > 0) */ /* { */ /* /\* chuck=1; *\/ */ /* printf("tiprimary_list End: %d events left on vmeOUT queue (will now de-queue them)\n",rem_count); */ /* /\* This wont work without a secondary readout list (will crash EB or hang the ROC) *\/ */ /* for(ii=0;ii>2]; DMANODE *outEvent; static int prev_len=0; if(chuck==1) printf("%s: chuck\n",__FUNCTION__); /* ISR_INTLOCK; */ outEvent = dmaPGetItem(vmeOUT); if(chuck==1) printf("%s: after dmaPGetItem\n",__FUNCTION__); if(outEvent != NULL) { len = outEvent->length; type = outEvent->type; event_number = outEvent->nevent; #ifdef NEEDTHIS? tiDecodeTrigData(data, &type, &syncFlag, &lateFail); #endif /* CEOPEN(type, BT_UI4); */ CEOPEN(ROCID, BT_BANK, blockLevel); /* Create Dummy Trigger Bank CBOPEN(0xff11,BT_SEG,blockLevel); for(ii=0;iidabufp++ = (type<<24)|(0x01<<16)|(3); *rol->dabufp++ = (blockLevel*(event_number-1) + (ii+1)); *rol->dabufp++ = 0x12345678; *rol->dabufp++ = 0; } CBCLOSE; */ shmEvent=0; if((event_number % 1000) == 0) shmEvent=1; if(rol->dabufp != NULL) { #undef PRINTOUT #ifdef PRINTOUT printf("Received %d triggers... \n", event_number); #endif /* if( abs(len-prev_len)>4 ) */ /* printf("%8d: unusual event. length = %d\n",event_number,len); */ for(ii=0;iidata[ii]; *rol->dabufp++ = currentWord; #ifdef PRINTOUT if((ii%5)==0) printf("\n\t"); printf(" 0x%08x ",(unsigned int)LSWAP(outEvent->data[ii])); #endif if(shmEvent) { shmData[ii] = currentWord; } } if(shmEvent) { /* crateShmSetData(event_number, shmData, len); */ } #ifdef PRINTOUT printf("\n\n"); #endif prev_len=len; } else { printf("tiprimary_list: ERROR rol->dabufp is NULL -- Event lost\n"); } /* Execute the doAck routine after freeing up the buffer. This allows for an Acknowledge to be sent back to the TI Master, if it is needed */ /* outEvent->part->free_cmd = *doAck; */ CECLOSE; if(chuck==1) printf("%s: before ACKLOCK\n",__FUNCTION__); ACKLOCK; if(chuck==1) printf("%s: GOT ACKLOCK\n",__FUNCTION__); dmaPFreeItem(outEvent); /* doAck performed in here */ if(tiNeedAck>0) { tiNeedAck=0; if(chuck==1) printf("%s: before SEND SIGNAL\n",__FUNCTION__); ACKSIGNAL; } ACKUNLOCK; } else { logMsg("Error: no Event in vmeOUT queue\n",0,0,0,0,0,0); } /* ISR_INTUNLOCK; */ } /*end trigger */ /* * doAck() * Routine to send a signal to the asyncTrigger thread, indicating that a * buffer has been freed. * */ void doAck() { ACKLOCK; if(tiNeedAck>0) { tiNeedAck=0; ACKSIGNAL; } ACKUNLOCK; } void asyncTrigger() { int intCount=0; int length,size; unsigned int tirval; int clocksource=-1; gettimeofday(&tvA[1], NULL); intCount = tiGetIntCount(); /* clocksource = tiGetClockSource(0); */ /* if(!tsCrate) */ /* { */ /* if(clocksource!=2) */ /* { */ /* clocksource = tiGetClockSource(1); */ /* printf("%s: ERROR. TI CLOCK SOURCE is NOT FIBER. (%s)", */ /* __FUNCTION__,clocksource); */ /* printf(" ABORTING READOUT\n"); */ /* return; */ /* } */ /* } */ /* grap a buffer from the queue */ GETEVENT(vmeIN,intCount); if(the_event->length!=0) { printf("Interrupt Count = %d\t",intCount); printf("the_event->length = %d\n",the_event->length); } #ifdef NEEDTHIS? the_event->type = tirReadData(); #else the_event->type = 1; #endif /* Execute user defined Trigger Routine */ rocTrigger(0); /* Put this event's buffer into the OUT queue. */ ACKLOCK; PUTEVENT(vmeOUT); /* Check if the event length is larger than expected */ length = (((int)(dma_dabufp) - (int)(&the_event->length))) - 4; size = the_event->part->size - sizeof(DMANODE); if(length>size) { printf("rocLib: ERROR: Event length > Buffer size (%d > %d). Event %d\n", length,size,the_event->nevent); } if(dmaPEmpty(vmeIN)) { emptyCount++; /*printf("WARN: vmeIN out of event buffers (intCount = %d).\n",intCount);*/ if(ack_runend==0 || tiBReady()>0) { /* Set the NeedAck for Ack after a buffer is freed */ tiNeedAck = 1; /* Wait for the signal indicating that a buffer has been freed */ ACKWAIT; } else { printf(" WHO CARES... ack_runend==1 tiBready = %d\n",tiBReady()); } } ACKUNLOCK; } void usrtrig_done() { } /*end done */ void __done() { gettimeofday(&tvB[1], NULL); int idiff=tvB[1].tv_usec - tvA[1].tv_usec + 1000000 * (tvB[1].tv_sec - tvA[1].tv_sec); //---- Fill Hist send wait for shmem ------------ hf1(hrol1,1,idiff); //printf(" time for rocGo()=%d us \n",idiff); poolEmpty = 0; /* global Done, Buffers have been freed */ } /*end done */ static void __reset() { tiIntDisable(); tiIntDisconnect(); printf(" **Reset Called** \n"); } /* end reset */ int getOutQueueCount() { if(vmeOUT) return(vmeOUT->list.c); else return(0); } int getInQueueCount() { if(vmeIN) return(vmeIN->list.c); else return(0); } /* This routine is automatically executed just before the shared libary is unloaded. Clean up memory that was allocated */ __attribute__((destructor)) void end (void) { static int ended=0; if(ended==0) { printf("ROC Cleanup\n"); rocCleanup(); dmaPFreeAll(); vmeCloseDefaultWindows(); ended=1; } } static void shmem_get() { /*---------------------------------------------------------------------*/ /* Shared memory */ /*---------------------------------------------------------------------*/ if ( (semid=semget( SEM_ID1, 1, 0) ) < 0 ) { printf("shmem_ROL_2: can not get semaphore \n"); fflush(stdout); } if ( (shmid=shmget(SHM_ID1,sizeof(roc_shmem), 0))<0) { printf("==> shmem_ROL_2: shared memory 0x%x, size=%d get error=%d\n",SHM_ID1,sizeof(roc_shmem),shmid); fflush(stdout); exit(1); } if ( (shmem_ptr=(roc_shmem *) shmat (shmid, 0, 0))<0 ) { printf("==> shmem_ROL_2: shared memory attach error\n"); fflush(stdout); } printf("==> shmem_ROL_2: shared memory attached OK ptr=%p\n",shmem_ptr); fflush(stdout); printf("===== ROL_2 wait semaphore ====== \n"); fflush(stdout); //--- add new shmem client here ----------- //-- access to shmem -- //sem_wait(semid); //if (shmem_ptr) shmem_ptr->rol2_hist=1; //sem_post(semid); }