Belle II Software  release-08-01-10
DeSerializerCOPPER.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <daq/rawdata/modules/copper.h>
10 #include <daq/rawdata/modules/DeSerializerCOPPER.h>
11 #include <rawdata/dataobjects/PreRawCOPPERFormat_latest.h>
12 
13 #include <sys/ioctl.h>
14 
15 #define CHECKEVT 10000
16 //#define CHECK_SUM
17 //#define DUMMY
18 //#define MAXEVTSIZE 400000000
19 //#define TIME_MONITOR
20 //#define NO_DATA_CHECK
21 //#define WO_FIRST_EVENUM_CHECK
22 //#define YAMADA_DUMMY
23 #define USE_PCIE40
24 
25 
26 using namespace std;
27 using namespace Belle2;
28 
29 #ifdef NONSTOP
30 int g_run_resuming = 0;
31 int g_run_pause = 0;
32 int g_run_error = 0;
33 #endif
34 
35 //-----------------------------------------------------------------
36 // Register the Module
37 //-----------------------------------------------------------------
38 REG_MODULE(DeSerializerCOPPER)
39 
40 //-----------------------------------------------------------------
41 // Implementation
42 //-----------------------------------------------------------------
43 
45 {
46  //Set module properties
47  setDescription("Encode DataStore into RingBuffer");
48 
49  // setPropertyFlags(c_Input | c_ParallelProcessingCertified);
50  addParam("FinesseBitFlag", m_finesse_bit_flag, "finesse (A,B,C,D) -> bit (0,1,2,3)", 15);
51 
52  //Parameter definition
53  B2INFO("DeSerializerCOPPER: Constructor done.");
54  m_prev_ftsweve32 = 0xFFFFFFFF;
55 
56  m_cpr_fd = -1;
57 }
58 
59 
60 DeSerializerCOPPERModule::~DeSerializerCOPPERModule()
61 {
62 }
63 
64 void DeSerializerCOPPERModule::initialize()
65 {
66  B2INFO("DeSerializerCOPPER: initialize() started.");
67  // allocate buffer
68  for (int i = 0 ; i < NUM_PREALLOC_BUF; i++) {
69  m_bufary[i] = new int[ BUF_SIZE_WORD ];
70  }
71  m_buffer = new int[ BUF_SIZE_WORD ];
72 
73  //
74  // Initialize basf2 related
75  //
76  for (int i = 0 ; i < NUM_PREALLOC_BUF; i++) {
77  memset(m_bufary[i], 0, BUF_SIZE_WORD * sizeof(int));
78  }
79 
80  // Initialize EvtMetaData
81  m_eventMetaDataPtr.registerInDataStore();
82 
83  // Initialize Array of RawCOPPER
84  // rawcprarray.registerInDataStore();
85  raw_dblkarray.registerInDataStore();
86 
87  if (m_dump_fname.size() > 0) {
88  openOutputFile();
89  }
90  memset(time_array0, 0, sizeof(time_array0));
91  memset(time_array1, 0, sizeof(time_array1));
92  memset(time_array2, 0, sizeof(time_array2));
93  memset(time_array3, 0, sizeof(time_array3));
94  memset(time_array4, 0, sizeof(time_array4));
95  memset(time_array5, 0, sizeof(time_array5));
96 
97  // initialize COPPER
98  initializeCOPPER();
99 
100  //
101  // report ready to SLC
102  //
103  if (m_shmflag > 0) {
104  if (m_nodename.size() == 0 || m_nodeid < 0) {
105  m_shmflag = 0;
106  } else {
107  printf("nodename = %s\n", m_nodename.c_str());
108  g_status.open(m_nodename, m_nodeid);
109  g_status.reportReady();
110  }
111  }
112 
113 #ifdef NONSTOP
114  openRunPauseNshm();
115 #endif
116 
117  B2INFO("DeSerializerCOPPER: initialize() done.");
118 }
119 
120 
121 
122 
123 void DeSerializerCOPPERModule::initializeCOPPER()
124 {
125 
126 #ifndef DUMMY
127  m_use_slot = 0; /* bit mask */
128  int slot_shift;
129 
130  if ((m_finesse_bit_flag & 0x1) == 1) {
131  slot_shift = 0; // a:0, b:1, c:2, d:3
132  m_use_slot |= 1 << slot_shift; //
133  }
134 
135  if (((m_finesse_bit_flag >> 1) & 0x1) == 1) {
136  slot_shift = 1; // a:0, b:1, c:2, d:3
137  m_use_slot |= 1 << slot_shift; //
138  }
139 
140  if (((m_finesse_bit_flag >> 2) & 0x1) == 1) {
141  slot_shift = 2; // a:0, b:1, c:2, d:3
142  m_use_slot |= 1 << slot_shift; //
143  }
144 
145  if (((m_finesse_bit_flag >> 3) & 0x1) == 1) {
146  slot_shift = 3; // a:0, b:1, c:2, d:3
147  m_use_slot |= 1 << slot_shift; //
148  }
149  //
150  // Present slots to use
151  //
152  if (! m_use_slot) {
153  char err_buf[100] = "[FATAL] Slot is not specified. Exiting...";
154  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
155  exit(1);
156  } else {
157  int slot;
158  printf("[DEBUG] ");
159  for (slot = 0; slot < 4; slot++) {
160  if (m_use_slot & (1 << slot)) printf(" %c", 'A' + slot);
161  }
162  printf("\n");
163  }
164 
165 
166 #endif
167 
168 #ifndef YAMADA_DUMMY
169  B2INFO("Opening COPPER...");
170  fflush(stderr);
171  openCOPPER();
172  B2INFO("Done.\n");
173  fflush(stderr);
174 #endif
175 
176 
177 
178 }
179 
180 
181 int* DeSerializerCOPPERModule::readOneEventFromCOPPERFIFO(const int /*entry*/, int* /*delete_flag*/, int* /*m_size_word*/)
182 {
183 #ifdef USE_PCIE40
184  char err_buf[500];
185  sprintf(err_buf, "[FATAL] This function is not supported. Exiting...: \n%s %s %d\n",
186  __FILE__, __PRETTY_FUNCTION__, __LINE__);
187  print_err.PrintError(err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
188  exit(1);
189 #else
190  // prepare buffer
191  *m_size_word = 0;
192  int* temp_buf = m_bufary[ entry ];
193  temp_buf[0] = BUF_SIZE_WORD ;
194  *delete_flag = 0;
195 
196  //
197  // Read data from HSLB
198  //
199 #ifndef DUMMY
200  int recvd_byte = (m_pre_rawcpr.tmp_header.RAWHEADER_NWORDS) * sizeof(int);
201  // Firstly, read data with an allocated buffer.
202  while (1) {
203  int read_size = 0;
204  if ((read_size = read(m_cpr_fd, (char*)m_bufary[entry] + recvd_byte, sizeof(int) * BUF_SIZE_WORD - recvd_byte)) < 0) {
205  if (errno == EINTR) {
206  continue;
207  } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
208 
209  if (recvd_byte > (int)((m_pre_rawcpr.tmp_header.RAWHEADER_NWORDS) * sizeof(int))) {
210  char err_buf[500];
211  sprintf(err_buf, "[FATAL] EAGAIN return in the middle of an event( COPPER driver should't do this.). Exting...");
212  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
213  exit(-1);
214  }
215 
216 #ifdef NONSTOP
217  // Check run-pause request from SLC
218  string err_str;
219  callCheckRunPause(err_str);
220 #endif
221  continue;
222 
223  } else {
224  char err_buf[500];
225  sprintf(err_buf, "[FATAL] Failed to read data from COPPER. Exiting...");
226  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
227  exit(-1);
228  }
229  } else {
230  recvd_byte += read_size;
231  if (recvd_byte - (m_pre_rawcpr.tmp_header.RAWHEADER_NWORDS) * sizeof(int) > (int)(sizeof(int) *
232  (m_pre_rawcpr.POS_DATA_LENGTH + 1)))break;
233  }
234  }
235 
236  //
237  // Calcurate data size
238  //
239  *m_size_word = m_bufary[ entry ][ m_pre_rawcpr.POS_DATA_LENGTH + (m_pre_rawcpr.tmp_header.RAWHEADER_NWORDS) ]
240  + m_pre_rawcpr.SIZE_COPPER_DRIVER_HEADER + m_pre_rawcpr.SIZE_COPPER_DRIVER_TRAILER
241  + m_pre_rawcpr.tmp_header.RAWHEADER_NWORDS +
242  m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS; // 9 words are COPPER haeder and trailer size.
243 
244  //
245  // If there are data remaining to be read, continue reading
246  //
247  if ((int)((*m_size_word - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS) * sizeof(int)) > recvd_byte) {
248 
249  // If event size is larger than BUF_SIZE_WORD, allocate a new buffer
250  if (*m_size_word > BUF_SIZE_WORD) {
251  *delete_flag = 1;
252  temp_buf = new int[ *m_size_word ];
253  memcpy(temp_buf, m_bufary[ entry ], recvd_byte);
254  recvd_byte += readFD(m_cpr_fd, (char*)temp_buf + recvd_byte,
255  (*m_size_word - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS) * sizeof(int) - recvd_byte, *delete_flag);
256  } else {
257 
258  recvd_byte += readFD(m_cpr_fd, (char*)(m_bufary[ entry ]) + recvd_byte,
259  (*m_size_word - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS) * sizeof(int) - recvd_byte, *delete_flag);
260  }
261 
262  if ((int)((*m_size_word - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS) * sizeof(int)) != recvd_byte) {
263  char err_buf[500];
264 
265  sprintf(err_buf, "[FATAL] CORRUPTED DATA: Read less bytes(%d) than expected(%d:%d). Exiting...\n",
266  recvd_byte,
267  *m_size_word * sizeof(int) - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS * sizeof(int),
268  m_bufary[ entry ][ m_pre_rawcpr.POS_DATA_LENGTH ]);
269  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
270  exit(-1);
271  }
272  } else if ((int)((*m_size_word - m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS) * sizeof(int)) < recvd_byte) {
273  char err_buf[500];
274  sprintf(err_buf, "[FATAL] CORRUPTED DATA: Read more than data size. Exiting...: %d %d %d %d %d\n",
275  recvd_byte, *m_size_word * sizeof(int), m_pre_rawcpr.tmp_trailer.RAWTRAILER_NWORDS * sizeof(int),
276  m_bufary[ entry ][ m_pre_rawcpr.POS_DATA_LENGTH ], m_pre_rawcpr.POS_DATA_LENGTH);
277  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
278  exit(-1);
279  }
280 #else
281  //
282  // Make dummy data
283  //
284  *m_size_word = 256 + entry;
285  m_bufary[entry][0] = *m_size_word;
286 #endif
287 
288  //
289  // Fill Data length
290  //
291  temp_buf[ 0 ] = *m_size_word;
292 
293 
294 #ifdef TIME_MONITOR
295  if (n_basf2evt >= 50000 && n_basf2evt < 50500) {
296  cur_time = getTimeSec();
297  time_array2[ n_basf2evt - 50000 ] = cur_time - m_start_time;
298  }
299 #endif
300 
301 #ifdef CHECK_SUM
302  unsigned int checksum = 0;
303  for (int i = 0; i < m_bufary[entry][0]; i++) {
304  if (i != 2) checksum += m_bufary[entry][i];
305  }
306  m_bufary[entry][2] = checksum;
307 #endif
308  return temp_buf;
309 #endif
310 }
311 
312 
313 
314 
315 void DeSerializerCOPPERModule::openCOPPER()
316 {
317 
318  if (m_cpr_fd != -1) {
319  close(m_cpr_fd);
320  m_cpr_fd = -1;
321  }
322  //
323  // Open a finesse device
324  //
325  if ((m_cpr_fd = open("/dev/copper/copper", O_RDONLY)) == -1) {
326  char err_buf[500];
327  sprintf(err_buf, "[FATAL] Failed to open /dev/copper/copper. Exiting... ");
328  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
329  exit(1);
330  }
331 
332  int set_regval = 15; // How many events to be stored in COPPER FIFO before request for DMA
333  // int set_regval=1;
334  ioctl(m_cpr_fd, CPRIOSET_LEF_WA_FF, &set_regval);
335  ioctl(m_cpr_fd, CPRIOSET_LEF_WB_FF, &set_regval);
336  ioctl(m_cpr_fd, CPRIOSET_LEF_WC_FF, &set_regval);
337  ioctl(m_cpr_fd, CPRIOSET_LEF_WD_FF, &set_regval);
338  ioctl(m_cpr_fd, CPRIOSET_FINESSE_STA, &m_use_slot, sizeof(m_use_slot));
339 
340  int v = 511 - 32;
341 
342  ioctl(m_cpr_fd, CPRIOSET_LEF_WA_AF, &v, sizeof(v));
343  ioctl(m_cpr_fd, CPRIOSET_LEF_WB_AF, &v, sizeof(v));
344  ioctl(m_cpr_fd, CPRIOSET_LEF_WC_AF, &v, sizeof(v));
345  ioctl(m_cpr_fd, CPRIOSET_LEF_WD_AF, &v, sizeof(v));
346 
347 
348  B2INFO("DeSerializerCOPPER: openCOPPER() done.");
349 
350 }
351 
352 
353 
354 int DeSerializerCOPPERModule::readFD(int fd, char* buf, int data_size_byte, int /*delete_flag*/)
355 {
356 
357  int n = 0;
358  while (1) {
359  int read_size = 0;
360  if ((read_size = read(fd, (char*)buf + n, data_size_byte - n)) < 0) {
361  if (errno == EINTR) {
362  continue;
363  } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
364  if (n > 0) {
365  char err_buf[500];
366  sprintf(err_buf, "[FATAL] Return due to EAGAIN in the middle of an event( COPPER driver would't do this.). Exting...");
367  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
368  exit(-1);
369  }
370 #ifdef NONSTOP
371  // Check run-pause request from SLC
372  string err_str;
373  try {
374  callCheckRunPause(err_str);
375  } catch (string err_str) {
376  if (delete_flag) {
377  // Delete allocated buffer
378  B2WARNING("Delete buffer before going to Run-pause state");
379  delete buf;
380  }
381  throw (err_str);
382  }
383 #endif
384  continue;
385  } else {
386 #ifdef NONSTOP
387  g_run_error = 1;
388  printf("[ERROR] Failed to read data from COPPER. %s %s %d",
389  __FILE__, __PRETTY_FUNCTION__, __LINE__);
390  string err_str = "RUN_ERROR";
391  throw (err_str);
392 #endif
393  char err_buf[500];
394  sprintf(err_buf, "[FATAL] Failed to read data from COPPER. %s %s %d",
395  __FILE__, __PRETTY_FUNCTION__, __LINE__);
396  print_err.PrintError(m_shmflag, &g_status, err_buf, __FILE__, __PRETTY_FUNCTION__, __LINE__);
397  exit(-1);
398  }
399  } else {
400  n += read_size;
401  if (n == data_size_byte)break;
402  }
403  }
404  return n;
405 }
406 
407 #ifdef NONSTOP
408 void DeSerializerCOPPERModule::resumeRun()
409 {
410 #ifdef NONSTOP_DEBUG
411  printf("\033[31m");
412  printf("###########(DesCpr) Resume from PAUSE ###############\n");
413  printf("\033[0m");
414  fflush(stdout);
415 #endif
416  initializeCOPPER();
417  g_run_error = 0;
418  g_run_resuming = 1;
419  m_start_flag = 0;
420  return;
421 }
422 
423 void DeSerializerCOPPERModule::waitResume()
424 {
425  // First, wait for run_pause
426  if (g_run_pause == 0 && g_run_error == 1) {
427  while (true) {
428 #ifdef NONSTOP_DEBUG
429  printf("\033[31m");
430  printf("###########(DesCpr) Error stop. Waiting for RUNPAUSE ###############\n");
431  printf("\033[0m");
432  fflush(stdout);
433 #endif
434  if (checkRunPause()) break;
435  sleep(1);
436  }
437  }
438 
439  // close COPPER FIFO
440  if (m_cpr_fd != -1) close(m_cpr_fd);
441  m_cpr_fd = -1;
442  while (true) {
443  if (checkRunRecovery()) {
444  g_run_pause = 0;
445  g_run_error = 0;
446  g_run_resuming = 1;
447  resumeRun();
448 
449 #ifdef NONSTOP_DEBUG
450  printf("\033[31m");
451  printf("###########(DesCpr) Resume detected ###############\n");
452  printf("\033[0m");
453  fflush(stdout);
454 #endif
455  break;
456  }
457 #ifdef NONSTOP_DEBUG
458  printf("\033[31m");
459  printf("###########(DesCpr) Waiting for RESUME ###############\n");
460  printf("\033[0m");
461  fflush(stdout);
462 #endif
463  sleep(1);
464  }
465  return;
466 }
467 
468 #endif
469 
470 void DeSerializerCOPPERModule::event()
471 {
472 
473 #ifdef NONSTOP
474  // Check run-pause request
475  if (g_run_pause > 0 || g_run_error > 0) {
476  waitResume(); // Stand-by loop
477  m_eventMetaDataPtr.create(); // Otherwise endRun() is called.
478  return;
479  }
480 #endif
481 
482  if (m_start_flag == 0) {
483  // Use shared memory to start(for HSLB dummy data)
484 
485  if (g_status.isAvailable()) {
486  B2INFO("DeSerializerCOPPER: Waiting for Start...\n");
487  g_status.reportRunning();
488  }
489 
490  m_start_time = getTimeSec();
491  n_basf2evt = 0;
492 #ifdef YAMADA_DUMMY
493  B2INFO("Opening COPPER...");
494  fflush(stderr);
495  openCOPPER();
496  B2INFO("Done.\n");
497  fflush(stderr);
498 #endif
499  }
500 
501 
502  for (int j = 0; j < NUM_EVT_PER_BASF2LOOP_COPPER; j++) {
503  int m_size_word = 0;
504  int delete_flag = 0;
505  if (m_start_flag == 0) {
506  B2INFO("DeSerializerCOPPER: Reading the 1st event from COPPER FIFO...");
507  }
508 
509  int* temp_buf;
510  try {
511  temp_buf = readOneEventFromCOPPERFIFO(j, &delete_flag, &m_size_word);
512  g_status.copyEventHeader(temp_buf);
513  } catch (string err_str) {
514 
515 #ifdef NONSTOP
516  if (err_str == "RUN_PAUSE" || err_str == "RUN_ERROR") {
517  // Create EventMetaData otherwise endRun() is called.
518  m_eventMetaDataPtr.create();
519  return;
520  }
521 #endif
522  print_err.PrintError(m_shmflag, &g_status, err_str);
523  exit(1);
524  }
525 
526  if (m_start_flag == 0) {
527  B2INFO("DeSerializerCOPPER: Done. the size of the 1st event is " << m_size_word << "words");
528  m_start_flag = 1;
529  }
530 
531  const int num_nodes = 1;
532  const int num_events = 1;
533  RawDataBlock* temp_rawdblk = raw_dblkarray.appendNew();
534  temp_rawdblk->SetBuffer(temp_buf, m_size_word, delete_flag, num_events, num_nodes);
535  // Fill Header and Trailer
536 
537  PreRawCOPPERFormat_latest temp_rawcopper;
538  temp_rawcopper.SetBuffer(temp_buf, m_size_word, 0, num_events, num_nodes);
539 
540  // Fill header and trailer
541  try {
542  m_prev_ftsweve32 = temp_rawcopper.FillTopBlockRawHeader(m_nodeid, m_prev_ftsweve32, m_prev_exprunsubrun_no, &m_exprunsubrun_no);
543  m_prev_exprunsubrun_no = m_exprunsubrun_no;
544  // fillNewRawCOPPERHeader( &temp_rawcopper );
545  } catch (string err_str) {
546  print_err.PrintError(m_shmflag, &g_status, err_str);
547  exit(1);
548  }
549 
550  if (m_dump_fname.size() > 0) {
551  dumpData((char*)temp_buf, m_size_word * sizeof(int));
552  }
553  m_totbytes += m_size_word * sizeof(int);
554  }
555 
556 
557  //
558  // Update EventMetaData
559  //
560  m_eventMetaDataPtr.create();
561  m_eventMetaDataPtr->setExperiment(0);
562  m_eventMetaDataPtr->setRun(0);
563  m_eventMetaDataPtr->setEvent(n_basf2evt);
564 
565  //
566  // Monitor
567  //
568  if (max_nevt >= 0 || max_seconds >= 0.) {
569  if ((n_basf2evt * NUM_EVT_PER_BASF2LOOP_PC >= max_nevt && max_nevt > 0)
570  || (getTimeSec() - m_start_time > max_seconds && max_seconds > 0.)) {
571  printf("[DEBUG] RunPause was detected. ( Setting: Max event # %d MaxTime %lf ) Processed Event %d Elapsed Time %lf[s]\n",
572  max_nevt, max_seconds, n_basf2evt * NUM_EVT_PER_BASF2LOOP_PC, getTimeSec() - m_start_time);
573  m_eventMetaDataPtr->setEndOfData();
574  }
575  }
576 
577  //
578  // Print current status
579  //
580  // if (n_basf2evt % 100 == 0 || n_basf2evt < 10) {
581  if (n_basf2evt % 100 == 0) {
582  RateMonitor(m_prev_ftsweve32, m_prev_exprunsubrun_no & RawHeader_latest::SUBRUNNO_MASK,
583  (m_prev_exprunsubrun_no & RawHeader_latest::RUNNO_MASK) >> RawHeader_latest::RUNNO_SHIFT);
584  }
585  n_basf2evt++;
586  if (g_status.isAvailable()) {
587  g_status.setInputNBytes(m_totbytes);
588  g_status.setInputCount(m_prev_ftsweve32 + 1);
589  }
590  return;
591 }
592 
A class definition of an input module for Sequential ROOT I/O.
A class definition of an input module for Sequential ROOT I/O.
Definition: DeSerializer.h:36
The Raw COPPER class ver.1 ( the latest version since May, 2014 ) This class stores data received by ...
unsigned int FillTopBlockRawHeader(unsigned int m_node_id, unsigned int prev_eve32, unsigned int prev_exprunsubrun_no, unsigned int *cur_exprunsubrun_no) OVERRIDE_CPP17
should be called by DeSerializerCOPPER.cc and fill contents in RawHeader
virtual void SetBuffer(int *bufin, int nwords, int delete_flag, int num_events, int num_nodes)
set buffer ( delete_flag : m_buffer is freeed( = 0 )/ not freeed( = 1 ) in Destructer )
The RawDataBlock class Base class for rawdata handling.
Definition: RawDataBlock.h:27
virtual void SetBuffer(int *bufin, int nwords, int delete_flag, int num_events, int num_nodes)
set buffer ( delete_flag : m_buffer is freeed( = 0 )/ not freeed( = 1 ) in Destructer )
Definition: RawDataBlock.cc:35
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.