/*----------------------------------------------------------------------------* GlueX EPICS event source This program inserts data gathered from EPICS as events in the DAQ data stream. It was originally written for PrimEx and was ported by Franz Klein for use in the GlueX BCAL test Sep. 2006. Original code and additional modifications by David Lawrence. *----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include // For EPICS #include #include #include typedef struct{ unsigned int length; unsigned int head; time_t time; char data[1]; // This must be in the same data block as the bank header }epics_event_t; typedef struct{ char* name; int period; // in seconds time_t last_read; // in unix time int num_elements; }epics_channel_t; // Globals et_att_id attach; et_sys_id id; char *DICTIONARY_FILENAME = "/usr/local/halld/online/scripts/epics.dictionary"; epics_channel_t EPICS_CHANNELS[1000]; int N_EPICS_CHANNELS=0; // Routines int InsertEventIntoET(unsigned int *buff, int nwords); int AddEpicsChannel(epics_event_t *ev, epics_channel_t *ch); int AddAnEpicsValue(epics_event_t *ev, char* name, float val); epics_event_t* BuildEPICSEvent(void); int main(int narg,char **argv) { int i, j, size, status, nevents_max, event_size; et_openconfig openconfig; char *fname="/tmp/et_sys_bcaltest"; char cline[256]; timespec t; epics_event_t* epics_event; FILE *f; char buff[10000]; char name[256]; int period; // Make sure EPICS_CA_ADDR_LIST is set char *ptr = getenv("EPICS_CA_ADDR_LIST"); // We added the bac_bcm_average and ibcm2 variables which are the // Halls A and C beam currents to the list. These require the // 129.57.255.5 address be in the EPICS_CA_ADDR_LIST. I'm forcing // this here since the variable doesn't normally have this in Hall-B if(!ptr){ putenv("EPICS_CA_ADDR_LIST=129.57.255.4 129.57.163.255 129.57.96.7 129.57.57.188 129.57.255.5"); } // Set timeout to 2 seconds ezcaSetTimeout(0.2); ezcaSetRetryCount(9); /* Open dictionary and read it in */ if(narg>1) DICTIONARY_FILENAME = argv[1]; f = fopen(DICTIONARY_FILENAME,"r"); if(!f){ fprintf(stderr,"Unable to open dictionary \"%s\" \n",DICTIONARY_FILENAME); return -1; } fprintf(stdout,"Reading from \"%s\" \n",DICTIONARY_FILENAME); while( fgets(cline,256,f)!=NULL ){ if(*cline=='#') continue; if(sscanf(cline,"%s %d", name, &period)==2){ if(name[0]=='#')continue; if(period<2 || period>600){ fprintf(stderr,"Period out of range for variable \"%s\" period = %d) \n",name,period); continue; } fprintf(stdout,"Adding \"%s\" to monitoring list with a period of %d seconds \n",name,period); EPICS_CHANNELS[N_EPICS_CHANNELS].name = strdup(name); EPICS_CHANNELS[N_EPICS_CHANNELS].period = period; EPICS_CHANNELS[N_EPICS_CHANNELS].last_read = 0; fprintf(stdout," getting number of elements ..."); fflush(stdout); ezcaGetNelem(name,&EPICS_CHANNELS[N_EPICS_CHANNELS].num_elements); fprintf(stderr,"done\n"); if(EPICS_CHANNELS[N_EPICS_CHANNELS].num_elements<1)continue; fprintf(stderr,"Adding epics var. \"%s\" Nelem=%d \n",name, EPICS_CHANNELS[N_EPICS_CHANNELS].num_elements); N_EPICS_CHANNELS++; } } fclose(f); fprintf(stderr,"Defined %d EPICS channels\n",N_EPICS_CHANNELS); /* open the ET system */ et_open_config_init(&openconfig); if (et_open(&id, fname, openconfig) != ET_OK) { printf("et_producer: et_open problems\n"); exit(1); } et_open_config_destroy(openconfig); /* set the level of debug output that we want (everything) */ et_system_setdebug(id, ET_DEBUG_INFO); /* attach to GRANDCENTRAL station since we are producing events */ if (et_station_attach(id, ET_GRANDCENTRAL, &attach) < 0) { printf("et_producer: error in station attach\n"); exit(1); } // Loop while alive while (et_alive(id)) { epics_event = BuildEPICSEvent(); if(epics_event){ if(epics_event->length>2){ InsertEventIntoET((unsigned int*)epics_event, epics_event->length+1); } } // Sleep for 1 second sleep(1); if (!et_alive(id)) { et_wait_for_alive(id); } } /* while(alive) */ return 0; } int InsertEventIntoET(unsigned int *buff, int nwords) { et_event *pe; int status; char *pdata; /* get new/unused event */ status = et_event_new(id, attach, &pe, ET_SLEEP, NULL, nwords*sizeof(int)); if (status != ET_OK) { printf("et_producer: error in et_event_new\n"); exit(0); } // Get pointer to data of new event et_event_getdata(pe,(void**)&pdata); // Copy contents into new event memcpy( (char*)pdata, (char*)buff, nwords*sizeof(int)); // put event back into the ET system status = et_event_put(id, attach, pe); if (status != ET_OK) { printf("et_producer: put error\n"); exit(0); } printf("--- Event Added (%d words)---\n\n", nwords); return 0; } epics_event_t* BuildEPICSEvent(void) { int maxwrds = 10000; static epics_event_t *ev=NULL; float val; char name[256]; int i; // Allocate memory if needed if(!ev)ev = (epics_event_t*)malloc(sizeof(epics_event_t)+maxwrds); if(!ev){ printf("%s:%s Error allocating memory.\n",__FILE__,__LINE__); return NULL; } // Initialize event header ev->length = 2; ev->head = (21<<16) + (1<<8) + (0xCC<<0); ev->time = time(NULL); bzero(ev->data,maxwrds*sizeof(int)); // Loop over the variable list and see if anyone is due to be written out for(i=0;itime > EPICS_CHANNELS[i].last_read+EPICS_CHANNELS[i].period){ AddEpicsChannel(ev, &EPICS_CHANNELS[i]); EPICS_CHANNELS[i].last_read = ev->time; } } // Update length of event if(strlen(ev->data)>0)ev->length = 2 + strlen(ev->data)/sizeof(int)+1; return ev; } int AddEpicsChannel(epics_event_t *ev, epics_channel_t *ch) { float vals[2048]; ezcaGet(ch->name, ezcaFloat, ch->num_elements, vals); if(ch->num_elements>1){ for(int i=0;inum_elements;i++){ char str[256]; sprintf(str, "%s[%d]",ch->name,i); AddAnEpicsValue(ev, str, vals[i]); } }else{ AddAnEpicsValue(ev, ch->name, vals[0]); } return 0; } int AddAnEpicsValue(epics_event_t *ev, char* name, float val) { printf("Adding EPICS variable \"%s\" : %f \n",name,val); // Write as key=value char str[256]; sprintf(str,"%s=%f\n",name, val); strcat(ev->data, str); return 0; }