StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RichEventReader.cxx
1 /***************************************************************************
2  * $Id: RichEventReader.cxx,v 1.5 2007/12/24 06:04:23 fine Exp $
3  * Author: Zhangbu Xu
4  ***************************************************************************
5  * Description: Rich Event reader code for standalone data file
6  *
7  * change log
8  * 06-Jun-99 MJL implement EventReader::getEventInfo()
9  * 06-Jun-99 MJL implement EventReader::printEventInfo()
10  * 23-Jun-99 MJL add verbose flag and setVerbose() method
11  * 23-Jun-99 MJL turn off all printf, cout when verbose=0
12  * 24-Jun-99 MJL navigation now reads DATAP without prior
13  * knowledge of DATAP length
14  * 20-Jul-99 MJL added EventReader::fprintError()
15  * 20-Jul-99 MJL add alternate constructor for EventReader with name of logfile
16  * 20-Jul-99 MJL add alternate getEventReader with name of logfile
17  * 20-Jul-99 MJL add overloaded printEventInfo(FILE *)
18  * 29-Aug-99 MJL if((MMAPP = (char *) mmap(0, ... for HP platform
19  * 28-Dec-99 MJL add alternate InitEventReaders, mapped and unmapped
20  * 31-Jan-00 MJL set runnum (mapped version)
21  * 21-Apr-00 Adopted by Z. Xu to read Rich standalone events
22  *
23  ***************************************************************************
24  * $Log: RichEventReader.cxx,v $
25  * Revision 1.5 2007/12/24 06:04:23 fine
26  * introduce OLDEVP namespace to allow ole and new EVP library concurrently
27  *
28  * Revision 1.4 2004/02/18 20:17:52 ward
29  * Access SSD data in makers.
30  *
31  * Revision 1.3 2003/12/24 21:55:57 perev
32  * Cleanup
33  *
34  * Revision 1.2 2000/04/25 15:18:08 xzb
35  * Fix the compiler warnings.
36  *
37  * Revision 1.1 2000/04/25 14:55:28 xzb
38  * Clean up RICH_Reader array, add RichEventReader for standalone data file
39  *
40  * Revision 1.19 2000/01/31 19:26:11 levine
41  * restore run number to memory-mapped version
42  *
43  * Revision 1.18 2000/01/11 22:04:40 levine
44  * EventReader.hh // change the header file to include std::string
45  * EventReader.cxx // convert string to char* via c_str() member
46  * (changes from Brian Lasiuk)
47  *
48  * Revision 1.17 2000/01/04 20:54:46 levine
49  * Implemented memory-mapped file access in EventReader.cxx. Old method
50  * (via seeks) is still possible by setting mmapp=0 in
51  *
52  * getEventReader(fd,offset,(const char *)logfile,mmapp);
53  *
54  *
55  * but memory-mapped access is much more effective.
56  *
57  * Revision 1.16 1999/12/07 23:10:30 levine
58  * changes to silence the gcc compiler warnings
59  *
60  * Revision 1.15 1999/12/07 20:24:45 levine
61  * add #include <time.h> to make compile warning go away
62  *
63  * Revision 1.14 1999/12/06 22:53:20 levine
64  * Cleaned up information generated on failure to initialize EventReader
65  *
66  * Revision 1.13 1999/12/03 21:39:22 levine
67  * ON encountering end of file, issue INFO message instead of ERROR
68  *
69  * Revision 1.12 1999/12/02 16:40:23 levine
70  * change test on ret value for read (line 230) to prevent looping behavior
71  * at end of file
72  *
73  * Revision 1.11 1999/11/20 00:13:09 fisyak
74  * Micheal LeVine update
75  *
76  * Revision 1.9 1999/07/28 16:08:23 levine
77  * modify EventReader so that ENDR does not cause error exit
78  *
79  * Revision 1.8 1999/07/21 21:33:09 levine
80  *
81  *
82  * changes to include error logging to file.
83  *
84  * There are now 2 constructors for EventReader:
85  *
86  * EventReader();
87  * EventReader(const char *logfilename);
88  *
89  * Constructed with no argument, there is no error logging. Supplying a file name
90  * sends all diagnostic output to the named file (N.B. opens in append mode)
91  *
92  * See example in client.cxx for constructing a log file name based on the
93  * datafile name.
94  *
95  * It is strongly advised to use the log file capability. You can grep it for
96  * instances of "ERROR:" to trap anything noteworthy (i.e., corrupted data files).
97  *
98  * Revision 1.7 1999/07/10 21:31:17 levine
99  * Detectors RICH, EMC, TRG now have their own (defined by each detector) interfaces.
100  * Existing user code will not have to change any calls to TPC-like detector
101  * readers.
102  *
103  * Revision 1.6 1999/07/04 01:47:58 levine
104  * minor changes to make solaris CC compiler happy
105  *
106  * Revision 1.5 1999/07/02 04:37:41 levine
107  * Many changes - see change logs in individual programs
108  *
109  **************************************************************************/
110 
111 #include <sys/types.h>
112 #include <sys/stat.h>
113 #include <sys/mman.h>
114 #include <time.h>
115 #include <fcntl.h>
116 #include <stdlib.h>
117 #include <sys/uio.h>
118 #include <unistd.h>
119 #include "RichEventReader.hh"
120 #include "RICH_Reader.hh"
121 
122 using namespace OLDEVP;
123 
124 RichEventReader *getRichEventReader(int fd, long offset, int MMap)
125 {
126  RichEventReader *er = new RichEventReader();
127  if (MMap) {
128  er->InitEventReader(fd, offset, MMap); // invoke the mapped version
129  if(er->errorNo())
130  {
131  cout << er->errstr().c_str() << endl;
132  cout << (er->err_string[er->errorNo()-1]) << endl;
133  delete er;
134  return NULL;
135  }
136  }
137  else {
138  er->InitEventReader(fd, offset); // invoke the mapped version
139  if(er->errorNo())
140  {
141  cout << er->errstr().c_str() << endl;
142  cout << (er->err_string[er->errorNo()-1]) << endl;
143  delete er;
144  return NULL;
145  }
146  }
147 
148  return er;
149 }
150 
151 
152 //Memory mapped version
153 void RichEventReader::InitEventReader(int fdes, long offset, int MMap)
154 {//InitER
155  //#define MX_MAP_SIZE 0x20000000
156 #define MX_MAP_SIZE 32768*4 /*max event size in RICH*/
157 
158  off_t FileLength;
159 
160  // cout << "Initializing EventReader with a MAPPED file" << endl;
161 
162  //initialize the error strings
163  strcpy(err_string[0],"ERROR: FILE");
164  strcpy(err_string[1],"ERROR: CRC");
165  strcpy(err_string[2],"ERROR: SWAP");
166  strcpy(err_string[3],"ERROR: BANK");
167  strcpy(err_string[4],"ERROR: MEM");
168  strcpy(err_string[5],"ERROR: NOT DATA BANK");
169  strcpy(err_string[6],"ERROR: BAD ARG");
170  strcpy(err_string[7],"ERROR: ENDR ENCOUNTERED");
171  strcpy(err_string[8],"ERROR: BAD HEADER");
172  strcpy(err_string[9],"INFO: MISSING BANK");
173  strcpy(err_string[10],"INFO: END OF FILE");
174 
175 
176  fd = fdes;
177  struct stat buf;
178  next_event_offset = 0;
179  if (fstat(fd,&buf)<0){
180  perror("error in DaqOpenTag");
181  ERROR(ERR_FILE);
182  next_event_offset = -1;
183  }
184  FileLength = buf.st_size;
185 
186  Bank_RICP lr;
187 
188  // Calculate the mmap offset - must be aligned to pagesize
189  long pagesize = sysconf(_SC_PAGESIZE);
190  int mmap_offset = (offset/pagesize)*pagesize;
191 
192  if(mmap_offset < 0) ERROR(ERR_FILE);
193 
194  int mapsize = buf.st_size - offset + pagesize;
195  //round up to the next page boundary
196  if (mapsize<=0) {// <0 means previous event size exceeded file length
197  if (verbose) printf("end of file encountered\n");
198  ERROR(INFO_END_FILE) ;
199  next_event_offset= -1;
200  }
201  // if (verbose) printf( "pagesize = %d mapsize %d offset %d\n",(int)pagesize, mapsize, offset);
202  if (mapsize>MX_MAP_SIZE) mapsize = MX_MAP_SIZE;
203  event_size = mapsize ; //needed for munmap() in destructor
204 
205  DATAP = NULL;
206  // map to a file
207  if((MMAPP = (char *)mmap(0, mapsize, PROT_READ | PROT_WRITE,
208  MAP_PRIVATE, fd, mmap_offset)) == (caddr_t) -1) {
209  char myerr[100];
210  sprintf(myerr,"mapping file request 0x%x bytes 0x%x",mapsize,mmap_offset);
211  perror(myerr);
212  ERROR(ERR_MEM);
213  next_event_offset=-1;
214  }
215  // if (verbose) printf("mapping file request 0x%x bytes 0x%x with page 0x%x at 0x%x\n",mapsize,mmap_offset,pagesize,MMAPP);
216 
217  // Set DATAP to the real value
218  DATAP = MMAPP + (offset-mmap_offset);
219 
220  if (offset>=buf.st_size) {
221  ERROR(ERR_FILE) ;
222  next_event_offset = -1;
223  }
224 
225  if (strncmp(DATAP,"RICP", 4) == 0) {
226  // copy the logical record into local struct lr
227  if (!memcpy(&lr,DATAP,sizeof(lr))) perror("error in memcpy");
228  // check the CRC
229  if (!lr.test_CRC()) ERROR(ERR_CRC);
230  // swap bytes
231  if (lr.swap() < 0) ERROR(ERR_SWAP);
232  // zero CRC
233  lr.header.CRC = 0;
234 
235  char lcopy[10];
236 
237  strncpy(lcopy,lr.header.BankType,8);
238  lcopy[8] = 0;
239  // printf("lr.header.BankType: %s\n",lcopy);
240 
241  if(strncmp(lr.header.BankType, "RICP", 4) != 0) { //not DATA
242  perror("Have problem will the file\n");
243  next_event_offset = -1;
244  }
245  else { // DATA record. Skip LR
246 
247  // save run number
248  runnum = 0;
249  // DATAP +=sizeof(lr);
250  next_event_offset = 4 * lr.Reserved[0].off+offset;
251 
252  if (lr.header.Token==0){ // hack
253  next_event_offset = -1;
254  printf("hack: do not know how to deal with token==0\n");
255  DATAP = NULL;
256  }
257 
258  // break; //no need to loop any further
259  }
260  }
261  printf("======= Event number: %d with size %d============\n",lr.header.Token,lr.Reserved[0].off);
262 }
263 
264 RichEventReader::RichEventReader()
265 {
266  DATAP = NULL;
267  MMAPP = NULL;
268  errnum = 0;
269  runnum = 0;
270  memset(errstr0, '\0', sizeof(errstr0));
271  event_size = 0;
272  fd = -1;
273  next_event_offset = -1;
274  verbose = 0;
275  logfd = NULL; //no error logging
276 }
277 
278 // unmapped version
279 void RichEventReader::InitEventReader(int fdes, long offset)
280 {//InitER
281  long c_offset = offset;
282  next_event_offset = -1;
283 
284  if (verbose) cout << "Initializing RichEventReader with a file" << endl;
285 
286  //initialize the error strings
287  strcpy(err_string[0],"ERROR: FILE");
288  strcpy(err_string[1],"ERROR: CRC");
289  strcpy(err_string[2],"ERROR: SWAP");
290  strcpy(err_string[3],"ERROR: BANK");
291  strcpy(err_string[4],"ERROR: MEM");
292  strcpy(err_string[5],"ERROR: NOT DATA BANK");
293  strcpy(err_string[6],"ERROR: BAD ARG");
294  strcpy(err_string[7],"ERROR: ENDR ENCOUNTERED");
295  strcpy(err_string[8],"ERROR: BAD HEADER");
296  strcpy(err_string[9],"INFO: MISSING BANK");
297  strcpy(err_string[10],"INFO: END OF FILE");
298 
299 
300  fd = fdes;
301  int DATAPEVENTLENGTH=0; // hack, the event length is not yet in datap
302 
303  char bank[9];
304  memset(bank,'\0',sizeof(bank));
305 
306  int ret = lseek(fd, offset, SEEK_SET);
307  if(ret < 0) {
308  next_event_offset = -1;
309  ERROR(ERR_FILE);
310  }
311 
312  ret = read(fd,bank,8);
313  if(ret < 0) {
314  next_event_offset = -1;
315  ERROR(ERR_FILE);
316  }
317 
318  ret = lseek(fd, offset, SEEK_SET); // set pointer back to top of bank
319  if(ret < 0) ERROR(ERR_FILE);
320  // printf("%s::%d offset=0x%x BANK %s\n",__FILE__,__LINE__,offset,bank);
321 
322  Bank_RICP lr;
323 
324  if (strncmp(bank,"RICP", 4) == 0) {
325  // read the logical record
326  ret = read(fd,&lr,sizeof(lr));
327  if(ret < 0) ERROR(ERR_FILE);
328  ret = lseek(fd, offset, SEEK_SET); // set pointer back to top of bank
329  if(ret < 0) ERROR(ERR_FILE);
330  c_offset += sizeof(lr);
331  if (!lr.test_CRC()) ERROR(ERR_CRC);
332  if (lr.swap() < 0) ERROR(ERR_SWAP);
333  lr.header.CRC = 0;
334 
335 
336  // get event length
337  DATAPEVENTLENGTH = lr.Reserved[0].off; // Hack for event len
338  // save run number
339  runnum = 0;
340  next_event_offset = offset+lr.Reserved[0].off * 4;
341 
342 
343  // check that the file contains the entire event
344  struct stat statbuf;
345  if(fstat(fd, &statbuf) < 0) ERROR(ERR_FILE);
346 
347  DATAP = (char *)malloc(DATAPEVENTLENGTH * 4);
348  if(!DATAP) ERROR(ERR_MEM);
349 
350  ret = read(fd, DATAP, DATAPEVENTLENGTH*4);
351  if(ret < 0) ERROR(ERR_FILE);
352  // check CRC, swap
353  if (!((Bank_RICP *)DATAP)->test_CRC()) ERROR(ERR_CRC);
354  if (((Bank_RICP *)DATAP)->swap() < 0) ERROR(ERR_SWAP);
355 
356  event_size = DATAPEVENTLENGTH;
357 
358  }
359  if (lr.header.Token==0){ // hack
360  next_event_offset = -1;
361  printf("hack: do not know how to deal with token==0\n");
362  free(DATAP);
363  DATAP = NULL;
364  }
365  printf("======= Event number: %d size %d============\n",lr.header.Token, DATAPEVENTLENGTH);
366 
367 }
368 
369 RichEventReader::~RichEventReader()
370 {
371  // cout << "Destroying event reader" << endl;
372 
373  if(fd == -1) // Pointer construction ... their data
374  {
375  // Nothing needs done
376  }
377  else if(MMAPP != NULL) // Memory Mapped file
378  {
379  // Unmap memory
380  // if (verbose) printf("0x%x of size 0x%x\n",MMAPP,event_size);
381  munmap(MMAPP,event_size); //unmap
382  }
383  else // file buffer
384  {
385  // free my malloc
386  free(DATAP);
387  }
388  if (logfd!=NULL) fclose(logfd);
389 }
390 
391 EventInfo RichEventReader::getEventInfo()
392 {
393  //cout << "Getting event info" << endl;
394  EventInfo ei;
395  Bank_RICP *dp = (Bank_RICP *)DATAP;
396  ei.EventLength = dp->Reserved[0].off;
397  ei.EventSeqNo = dp->header.Token;
398  ei.RICHPresent = (0x80);
399  return ei;
400 }
401 
402 void RichEventReader::printEventInfo(FILE * fd)
403 {
404  EventInfo ei = getEventInfo();
405  // ei.printEventInfo(fd);
406 }
407 
408 long RichEventReader::NextEventOffset()
409 {
410  return next_event_offset;
411 }
412 
413 int RichEventReader::MemUsed()
414 {
415  return event_size;
416 }
417 
418 void RichEventReader::setVerbose(int v)
419 {
420  verbose = v;
421 }
422 
423 char * RichEventReader::findBank(const char *bankid)
424 {
425  // Fix up DATAP
426  Bank_RICP *pBankDATAP = (Bank_RICP *)this->getDATAP();
427  return (char *)pBankDATAP;
428 
429 }
430 
431 void RichEventReader::fprintError(int err, char *file, int line, char *userstring)
432 {
433  if (logfd==NULL) return; //no file designated
434  if (err<0 || err>MX_MESSAGE) return; //protect against bad error code
435  fprintf(logfd,"%s %s::%d %s\n",err_string[err-1],file,line,userstring);
436  fflush(logfd);
437 }