/*! \brief extract channel information from raw data ReadBuffData extracts channel information from the raw data arrays and places it into a structure called evt. A pointer to each of the evt objects is placed in the eventlist vector for later time sorting. \param [in] buf : the buffer to process \param [in] bufLen : the length of the buffer \param [in] eventList : the event list to add the extracted buffer to \return An unused integer */ int ReadBuffDataF(word_t *buf, unsigned long *bufLen, vector<ChanEvent*> &eventList) { // multiplier for high bits of 48-bit time static const double HIGH_MULT = pow(2., 32.); word_t modNum; unsigned long numEvents = 0; word_t *bufStart = buf; /* Determine the number of words in the buffer */ *bufLen = *buf++; /* Read the module number */ modNum = *buf++; ChanEvent *lastVirtualChannel = NULL; if(*bufLen > 0) { // check if the buffer has data if(*bufLen == 2) { // this is an empty channel return 0; } do { ChanEvent *currentEvt = new ChanEvent; // decoding event data... see pixie16app.c // buf points to the start of channel data //Decode the first header word word_t chanNum = (buf[0] & 0x0000000F); word_t slotNum = (buf[0] & 0x000000F0) >> 4; word_t crateNum = (buf[0] & 0x00000F00) >> 8; word_t headerLength = (buf[0] & 0x0001F000) >> 12; word_t eventLength = (buf[0] & 0x7FFE0000) >> 17; currentEvt->pileupBit = (buf[0] & 0x80000000) != 0; // Sanity check if(headerLength == stats.headerLength) { // this is a manual statistics block inserted poll stats.DoStatisticsBlock(&buf[1], modNum); buf += eventLength; numEvents = readbuff::STATS; continue; } //Decode the second header word word_t lowTime = buf[1]; //Decode the third header word word_t highTime = buf[2] & 0x0000FFFF; word_t cfdTime = (buf[2] & 0x3FFF0000) >> 16; currentEvt->cfdTrigSource = ((buf[2] & 0x40000000) != 0); currentEvt->cfdForceTrig = ((buf[2] & 0x80000000) != 0); //Decode the foruth header word word_t energy = buf[3] & 0x0000FFFF; word_t traceLength = (buf[3] & 0x7FFF0000) >> 16; currentEvt->saturatedBit = ((buf[3] & 0x80000000) != 0); int offset = headerLength - 8; switch(headerLength) { case 4: case 6: case 8: case 10: break; case 12: case 14: case 16: case 18: for(int i=0; i < currentEvt->numQdcs; i++) currentEvt->qdcValue[i] = buf[offset + i]; break; default: cerr << " Unexpected header length: " << headerLength << endl; cerr << " Buffer " << modNum << " of length " << *bufLen << endl; cerr << " CHAN:SLOT:CRATE " << chanNum << ":" << slotNum << ":" << crateNum << endl; return readbuff::ERROR; break; } // one last sanity check if(traceLength / 2 + headerLength != eventLength) { cerr << " Bad event length (" << eventLength << ") does not correspond with length of header (" << headerLength << ") and length of trace (" << traceLength << ")" << endl; buf += eventLength; continue; } // handle multiple crates modNum += 100 * crateNum; currentEvt->chanNum = chanNum; currentEvt->modNum = modNum; if(currentEvt->virtualChannel) { DetectorLibrary* modChan = DetectorLibrary::get(); currentEvt->modNum += modChan->GetPhysicalModules(); if(modChan->at(modNum, chanNum).HasTag("construct_trace")) { lastVirtualChannel = currentEvt; } } currentEvt->energy = energy; if(currentEvt->saturatedBit) currentEvt->energy = 16383; currentEvt->trigTime = lowTime; currentEvt->cfdTime = cfdTime; currentEvt->eventTimeHi = highTime; currentEvt->eventTimeLo = lowTime; currentEvt->time = highTime * HIGH_MULT + lowTime; buf += headerLength; /* Check if trace data follows the channel header */ if(traceLength > 0) { // sbuf points to the beginning of trace data halfword_t *sbuf = (halfword_t *)buf; currentEvt->trace.reserve(traceLength); if(currentEvt->saturatedBit) currentEvt->trace.SetValue("saturation", 1); if(lastVirtualChannel != NULL && lastVirtualChannel->trace.empty()) { lastVirtualChannel->trace.assign(traceLength, 0); } // Read the trace data (2-bytes per sample, i.e. 2 samples per word) for(unsigned int k = 0; k < traceLength; k ++) { currentEvt->trace.push_back(sbuf[k]); if(lastVirtualChannel != NULL) { lastVirtualChannel->trace[k] += sbuf[k]; } } buf += traceLength / 2; } eventList.push_back(currentEvt); numEvents++; } while(buf < bufStart + *bufLen); } else { // if buffer has data
/*! \brief extract channel information from raw data ReadBuffData extracts channel information from the raw data arrays and places it into a structure called evt. A pointer to each of the evt objects is placed in the eventlist vector for later time sorting. \param [in] buf : the buffer to process \param [in] bufLen : the length of the buffer \param [in] eventList : the event list to add the extracted buffer to \return An unused integer */ int ReadBuffDataD(word_t *buf, unsigned long *bufLen, vector<ChanEvent*> &eventList) { // multiplier for high bits of 48-bit time static const double HIGH_MULT = pow(2., 32.); word_t modNum; unsigned long numEvents = 0; word_t *bufStart = buf; /* Determine the number of words in the buffer */ *bufLen = *buf++; /* Read the module number */ modNum = *buf++; ChanEvent *lastVirtualChannel = NULL; if(*bufLen > 0) { // check if the buffer has data if(*bufLen == 2) { // this is an empty channel return 0; } do { ChanEvent *currentEvt = new ChanEvent; // decoding event data... see pixie16app.c // buf points to the start of channel data word_t chanNum = (buf[0] & 0x0000000F); word_t slotNum = (buf[0] & 0x000000F0) >> 4; word_t crateNum = (buf[0] & 0x00000F00) >> 8; word_t headerLength = (buf[0] & 0x0001F000) >> 12; word_t eventLength = (buf[0] & 0x1FFE0000) >> 17; currentEvt->virtualChannel = ((buf[0] & 0x20000000) != 0); currentEvt->saturatedBit = ((buf[0] & 0x40000000) != 0); currentEvt->pileupBit = ((buf[0] & 0x80000000) != 0); // Rev. D header lengths not clearly defined in pixie16app_defs //! magic numbers here for now // make some sanity checks if(headerLength == stats.headerLength) { // this is a manual statistics block inserted by the poll program stats.DoStatisticsBlock(&buf[1], modNum); buf += eventLength; numEvents = readbuff::STATS; continue; } if(headerLength != 4 && headerLength != 8 && headerLength != 12 && headerLength != 16) { cout << " Unexpected header length: " << headerLength << endl; cout << " Buffer " << modNum << " of length " << *bufLen << endl; cout << " CHAN:SLOT:CRATE " << chanNum << ":" << slotNum << ":" << crateNum << endl; // advance to next event and continue // buf += EventLength; // continue; // skip the rest of this buffer return readbuff::ERROR; //return numEvents; } word_t lowTime = buf[1]; word_t highTime = buf[2] & 0x0000FFFF; word_t cfdTime = (buf[2] & 0xFFFF0000) >> 16; word_t energy = buf[3] & 0x0000FFFF; word_t traceLength = (buf[3] & 0xFFFF0000) >> 16; if(headerLength == 8 || headerLength == 16) { // skip the onboard partial sums for now // trailing, leading, gap, baseline } if(headerLength >= 12) { int offset = headerLength - 8; for(int i=0; i < currentEvt->numQdcs; i++) { currentEvt->qdcValue[i] = buf[offset + i]; } } // one last sanity check if(traceLength / 2 + headerLength != eventLength) { cout << " Bad event length (" << eventLength << ") does not correspond with length of header (" << headerLength << ") and length of trace (" << traceLength << ")" << endl; buf += eventLength; continue; } // handle multiple crates modNum += 100 * crateNum; currentEvt->chanNum = chanNum; currentEvt->modNum = modNum; if(currentEvt->virtualChannel) { DetectorLibrary* modChan = DetectorLibrary::get(); currentEvt->modNum += modChan->GetPhysicalModules(); if(modChan->at(modNum, chanNum).HasTag("construct_trace")) { lastVirtualChannel = currentEvt; } } currentEvt->energy = energy; //KM 2012-10-24 reinstating removal of saturated if(currentEvt->saturatedBit) currentEvt->energy = 16383; currentEvt->trigTime = lowTime; currentEvt->cfdTime = cfdTime; currentEvt->eventTimeHi = highTime; currentEvt->eventTimeLo = lowTime; currentEvt->time = highTime * HIGH_MULT + lowTime; buf += headerLength; /* Check if trace data follows the channel header */ if(traceLength > 0) { // sbuf points to the beginning of trace data halfword_t *sbuf = (halfword_t *)buf; currentEvt->trace.reserve(traceLength); if(currentEvt->saturatedBit) currentEvt->trace.SetValue("saturation", 1); if(lastVirtualChannel != NULL && lastVirtualChannel->trace.empty()) { lastVirtualChannel->trace.assign(traceLength, 0); } // Read the trace data (2-bytes per sample, i.e. 2 samples per word) for(unsigned int k = 0; k < traceLength; k ++) { currentEvt->trace.push_back(sbuf[k]); if(lastVirtualChannel != NULL) { lastVirtualChannel->trace[k] += sbuf[k]; } } buf += traceLength / 2; } eventList.push_back(currentEvt); numEvents++; } while(buf < bufStart + *bufLen); } else { // if buffer has data
extern "C" void hissub_(unsigned short *ibuf[],unsigned short *nhw) #endif { static float hz = sysconf(_SC_CLK_TCK); // get the number of clock ticks per second static clock_t clockBegin; // initialization time static struct tms tmsBegin; vector<ChanEvent*> eventList; // vector to hold the events /* Pointer to singleton DetectorLibrary class */ DetectorLibrary* modChan = DetectorLibrary::get(); /* Pointer to singleton DetectorDriver class */ DetectorDriver* driver = DetectorDriver::get(); // local version of ibuf pointer word_t *lbuf; int retval = 0; // return value from various functions unsigned long bufLen; /* Various event counters */ unsigned long numEvents = 0; static int counter = 0; // the number of times this function is called static int evCount; // the number of times data is passed to ScanList static unsigned int lastVsn; // the last vsn read from the data time_t theTime = 0; /* Assign the local variable lbuf to the variable ibuf which is passed into the routine. The difference between the new and old pixie16 readouts is the type of the variable and source of the variable ibuf. In the new readout ibuf is from a C++ function and is of type unsigned int* In the old readout ibuf is from a Fortran function and is of type unsigned short* This results in two different assignment statements depending on the readout. */ #ifdef newreadout lbuf=(word_t *)ibuf[0]; #else lbuf=(word_t *)ibuf; //old readout #endif /* Initialize the scan program before the first event */ if (counter==0) { /* Retrieve the current time for use later to determine the total * running time of the analysis. */ clockBegin = times(&tmsBegin); cout << "First buffer at " << clockBegin << " sys time" << endl; /* After completion the descriptions of all channels are in the modChan * vector, the DetectorDriver and rawevent have been initialized with the * detectors that will be used in this analysis. */ cout << "Using event width " << pixie::eventInSeconds * 1e6 << " us" << endl << " " << pixie::eventWidth << " in pixie16 clock tics." << endl; modChan->PrintUsedDetectors(rawev); if (verbose::MAP_INIT) modChan->PrintMap(); driver->Init(rawev); /* Make a last check to see that everything is in order for the driver * before processing data */ if ( !driver->SanityCheck() ) { cout << "Detector driver did not pass sanity check!" << endl; exit(EXIT_FAILURE); } lastVsn=-1; // set last vsn to -1 so we expect vsn 0 first cout << "Init done at " << times(&tmsBegin) << " sys time." << endl; } counter++; unsigned int nWords=0; // buffer counter, reset only for new buffer // true if the buffer being analyzed is split across a spill from pixie bool multSpill; do { word_t vsn = U_DELIMITER; bool fullSpill=false; //true if spill had all vsn's multSpill=false; //assume all buffers are not split between spills /* while the current location in the buffer has not gone beyond the end * of the buffer (ignoring the last three delimiters, continue reading */ while (nWords < (nhw[0]/2 - 6)) { /* Retrieve the record length and the vsn number */ word_t lenRec = lbuf[nWords]; vsn = lbuf[nWords+1]; /* If the record length is -1 (after end of spill), increment the location in the buffer by two and start over with the while loop */ if (lenRec == U_DELIMITER) { nWords += 2; // increment two whole words and try again continue; } // Buffer with vsn 1000 was inserted with the time for superheavy exp't if (vsn == clockVsn) { memcpy(&theTime, &lbuf[nWords+2], sizeof(time_t)); nWords += lenRec; } /* If the record length is 6, this is an empty channel. Skip this vsn and continue with the next */ //! Revision specific, so move to ReadBuffData if (lenRec==6) { nWords += lenRec+1; // one additional word for delimiter lastVsn=vsn; continue; } /* If both the current vsn inspected is within an acceptable range, begin reading the buffer. */ if ( vsn < modChan->GetPhysicalModules() ) { if ( lastVsn != U_DELIMITER) { // the modules should be read out cyclically if ( ((lastVsn+1) % modChan->GetPhysicalModules() ) != vsn ) { #ifdef VERBOSE cout << " MISSING BUFFER " << vsn << "/" << modChan->GetPhysicalModules() << " -- lastVsn = " << lastVsn << " " << ", length = " << lenRec << endl; #endif RemoveList(eventList); fullSpill=true; } } /* Read the buffer. After read, the vector eventList will contain pointers to all channels that fired in this buffer */ retval= ReadBuffData(&lbuf[nWords], &bufLen, eventList); /* If the return value is less than the error code, reading the buffer failed for some reason. Print error message and reset variables if necessary */ if ( retval <= readbuff::ERROR ) { cout << " READOUT PROBLEM " << retval << " in event " << counter << endl; if ( retval == readbuff::ERROR ) { cout << " Remove list " << lastVsn << " " << vsn << endl; RemoveList(eventList); } return; } else if ( retval == 0 ) { // empty buffers are regular in Rev. D data // cout << " EMPTY BUFFER" << endl; nWords += lenRec + 1; lastVsn = vsn; continue; // return; } else if ( retval > 0 ) { /* increment the total number of events observed */ numEvents += retval; } /* Update the variables that are keeping track of what has been analyzed and increment the location in the current buffer */ lastVsn = vsn; nWords += lenRec+1; // one extra word for delimiter } else { // bail out if we have lost our place, // (bad vsn) and process events if (vsn != 9999 && vsn != clockVsn) { #ifdef VERBOSE cout << "UNEXPECTED VSN " << vsn << endl; #endif } break; } } // while still have words if (nWords > nhw[0] / 2 - 6) { cout << "This actually happens!" << endl; } /* If the vsn is 9999 this is the end of a spill, signal this buffer for processing and determine if the buffer is split between spills. */ if ( vsn == 9999 || vsn == clockVsn ) { fullSpill = true; nWords += 3;//skip it if (lbuf[nWords+1] != U_DELIMITER) { cout << "this actually happens!" << endl; multSpill = true; } lastVsn=U_DELIMITER; } /* if there are events to process, continue */ if( numEvents>0 ) { if (fullSpill) { // if full spill process events // sort the vector of pointers eventlist according to time double lastTimestamp = (*(eventList.rbegin()))->GetTime(); sort(eventList.begin(),eventList.end(),CompareTime); driver->CorrelateClock(lastTimestamp, theTime); /* once the vector of pointers eventlist is sorted based on time, begin the event processing in ScanList() */ ScanList(eventList, rawev); /* once the eventlist has been scanned, remove it from memory and reset the number of events to zero and update the event counter */ evCount++; /* every once in a while (when evcount is a multiple of 1000) print the time elapsed doing the analysis */ if(evCount % 1000 == 0 || evCount == 1) { tms tmsNow; clock_t clockNow = times(&tmsNow); if (theTime != 0) { cout << " data read up to poll status time " << ctime(&theTime); } cout << " buffer = " << evCount << ", user time = " << (tmsNow.tms_utime - tmsBegin.tms_utime) / hz << ", system time = " << (tmsNow.tms_stime - tmsBegin.tms_stime) / hz << ", real time = " << (clockNow - clockBegin) / hz << ", ts = " << lastTimestamp << endl; } RemoveList(eventList); numEvents=0; } // end fullSpill else { cout << "Spill split between buffers" << endl; return; //! this tosses out all events read into the vector so far } } // end numEvents > 0 else if (retval != readbuff::STATS) { cout << "bad buffer, numEvents = " << numEvents << endl; return; } } while (multSpill); // end while loop over multiple spills return; }