PennMicroSlice.cc
Go to the documentation of this file.
4 
6 #include "cetlib_except/exception.h"
7 
8 #include <bitset>
9 #include <iostream>
10 #include <iomanip>
11 #include <stdio.h>
12 #include <boost/asio.hpp>
13 
14 //#define __DEBUG_sampleCount__
15 //#define __DEBUG_sampleTimeSplit__
16 //#define __DEBUG_sampleTimeSplitAndCount__
17 //#define __DEBUG_sampleTimeSplitAndCountTwice__
18 
19 dune::PennMicroSlice::PennMicroSlice(uint8_t* address) : buffer_(address) , current_payload_(address), current_word_id_(0)
20 {
21 }
22 
24 {
25  // microslice_size_t raw_payload_words = raw_payload_words_uncompressed;
26  // return (dune::PennMicroSlice::microslice_size_t)((Header::raw_header_words + raw_payload_words)* sizeof(raw_data_word_t));
27  return block_size();
28 }
29 
31 {
32  //uint8_t header_format_version = (header_()->raw_header_data[0] >> 56) & 0xF;
33  //return static_cast<dune::PennMicroSlice::Header::format_version_t>(header_format_version);
34  return header_()->format_version;
35 }
36 
38 {
39  return header_()->sequence_id;
40 }
41 
43 {
44  //return ((header_()->block_size & 0xFF00) >> 8) | ((header_()->block_size & 0x00FF) << 8);
45  return header_()->block_size;
46 }
47 
48 uint8_t* dune::PennMicroSlice::get_next_payload(uint32_t& word_id,
51  size_t& payload_size,
52  bool swap_payload_header_bytes,
53  size_t override_uslice_size){
54  size_t pl_size = 0;
55  if(current_word_id_ == 0){
56  if(override_uslice_size) {
58  pl_size = override_uslice_size - sizeof(Header);
59  }
60  else {
61  current_payload_ = buffer_ + sizeof(Header);
62  pl_size = size();
63  }
64  }//if(current_word_id_ == 0)
65 
66  //Switch from network to host byte ordering //Copied from get_payload
67  if(swap_payload_header_bytes)
68  *((uint32_t*)current_payload_) = ntohl(*((uint32_t*)current_payload_));
69 
70  if(current_word_id_ != 0 ){
71  //current_payload_ points to the last payload served up
72  //We need to skip over this one
73  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(current_payload_);
75  switch(type)
76  {
79  break;
82  break;
85  break;
88  break;
91  break;
92  default:
93  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
94  return nullptr;
95  break;
96  }//switch(type)
97  }//(current_word_id_ != 0)
98 
99  //Now current_payload_ will point to the next payload. Process the information that we want
100 
101  //Need to make sure we have not gone off the end of the buffer
102 
103  if(current_payload_ >= (buffer_ + pl_size))
104  return nullptr;
105 
106 
107  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(current_payload_);
109 
110  //Set the variables passed as references
111  word_id = current_word_id_;
112  type = payload_header->data_packet_type;
113  data_packet_type = type;
114  short_nova_timestamp = payload_header->short_nova_timestamp;
115 
116  switch(type)
117  {
120  break;
123  break;
126  break;
129  break;
132  break;
133  default:
134  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
135  payload_size = 0;
136  break;
137  }//switch(type)
138 
140  //current_payload_ points at the Payload_Header of the next payload
141  //this function assumes that state is true the next time it is called (so it knows how to shift to the next payload)
142  //but the user is expecting just the payload data. Therefore return the buffer offset by the payload_header
143 
144  return (current_payload_ + dune::PennMicroSlice::Payload_Header::size_bytes);
145 }
146 
147 // word_id is the index of the word to remove the
150  size_t& payload_size,
151  bool swap_payload_header_bytes,
152  size_t override_uslice_size) const
153 {
154  uint32_t i = 0;
155 
156  //if we're overriding, we don't have a Header to offset by
157  uint8_t* pl_ptr = 0;
158  size_t pl_size = 0;
159  if(override_uslice_size) {
160  pl_ptr = buffer_;
161  pl_size = override_uslice_size - sizeof(Header);
162  }
163  else {
164  pl_ptr = buffer_ + sizeof(Header);
165  pl_size = size();
166  }
167 
168  while(pl_ptr < (buffer_ + pl_size)) {
169  if(swap_payload_header_bytes)
170  *((uint32_t*)pl_ptr) = ntohl(*((uint32_t*)pl_ptr));
171 
172  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(pl_ptr);
174 
175  // Found the requested word
176  if(i == word_id) {
177  data_packet_type = type;
178  short_nova_timestamp = payload_header->short_nova_timestamp;
179  // What is this doing here?
180 // pl_ptr += 4;
181  // Shift forward the size of the header
183 
184  switch(type)
185  {
188  break;
191  break;
194  break;
197  break;
200  break;
201  default:
202  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
203  mf::LogError("PennMicroSlice") << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
204 
205  payload_size = 0;
206  break;
207  }//switch(type)
208  return pl_ptr;
209  } else {
210  // Advance the pointer to the size of the next payload
211  switch(type)
212  {
215  break;
218  break;
221  break;
224  break;
227  break;
228  default:
229  mf::LogError("PennMicroSlice") << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
230  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
231  return nullptr;
232  break;
233  }//switch(type)
234  i++;
235  }
236  }
237 
238  mf::LogError("PennMicroSlice") << "Could not find payload with ID " << word_id << " (the data buffer has overrun)" << std::endl;
239  std::cerr << "Could not find payload with ID " << word_id << " (the data buffer has overrun)" << std::endl;
240  return nullptr;
241 }
242 
243 
244 // Returns the sample count in the microslice
246  dune::PennMicroSlice::sample_count_t &n_counter_words,
247  dune::PennMicroSlice::sample_count_t &n_trigger_words,
248  dune::PennMicroSlice::sample_count_t &n_timestamp_words,
249  dune::PennMicroSlice::sample_count_t &n_selftest_words,
250  dune::PennMicroSlice::sample_count_t &n_checksum_words,
251  bool swap_payload_header_bytes,
252  size_t override_uslice_size) const
253 {
254  throw cet::exception("PennMicroSlice") << "As of Jul-28-2015, dune::PennMicroSlice::sampleCount is deprecated";
255 
256  n_counter_words = n_trigger_words = n_timestamp_words = n_selftest_words = n_checksum_words = 0;
257 
258  //if we're overriding, we don't have a Header to offset by
259  uint8_t* pl_ptr = 0;
260  size_t pl_size = 0;
261  if(override_uslice_size) {
262  pl_ptr = buffer_;
263  pl_size = override_uslice_size - sizeof(Header);
264  }
265  else {
266  pl_ptr = buffer_ + sizeof(Header);
267  pl_size = size();
268  }
269 
270  while(pl_ptr < (buffer_ + pl_size)) {
271  if(swap_payload_header_bytes)
272  *((uint32_t*)pl_ptr) = ntohl(*((uint32_t*)pl_ptr));
273  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(pl_ptr);
275 #ifdef __DEBUG_sampleCount__
276  std::cout << "PennMicroSlice::sampleCount DEBUG type 0x" << std::hex << (unsigned int)type << " timestamp " << std::dec << payload_header->short_nova_timestamp << std::endl;
277 #endif
278  switch(type)
279  {
281  n_counter_words++;
283  break;
285  n_trigger_words++;
287  break;
289  n_timestamp_words++;
291  break;
293  n_selftest_words++;
295  break;
297  n_checksum_words++;
299  break;
300  default:
301  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
302  return 0;
303  break;
304  }//switch(type)
305  }
306  return n_counter_words + n_trigger_words + n_timestamp_words + n_selftest_words + n_checksum_words;
307 }
308 
309 //Returns a point to the first payload header AFTER boundary_time
310 uint8_t* dune::PennMicroSlice::sampleTimeSplit(uint64_t boundary_time, size_t& remaining_size,
311  bool swap_payload_header_bytes, size_t override_uslice_size) const
312 {
313 
314  throw cet::exception("PennMicroSlice") << "As of Jul-28-2015, dune::PennMicroSlice::sampleTimeSplit is deprecated";
315 
316  //need to mask to get the lowest 28 bits of the nova timestamp
317  //in order to compare with the 'short_nova_timestamp' in the Payload_Header
318  boundary_time = boundary_time & 0xFFFFFFF;
319 
320  //if we're overriding, we don't have a Header to offset by
321  uint8_t* pl_ptr;
322  size_t pl_size;
323  if(override_uslice_size) {
324  pl_ptr = buffer_;
325  pl_size = override_uslice_size - sizeof(Header);
326  }
327  else {
328  pl_ptr = buffer_ + sizeof(Header);
329  pl_size = size();
330  }
331 
332  //loop over the microslice
333  while(pl_ptr < (buffer_ + pl_size)) {
334  if(swap_payload_header_bytes)
335  *((uint32_t*)pl_ptr) = ntohl(*((uint32_t*)pl_ptr));
336  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(pl_ptr);
339 #ifdef __DEBUG_sampleTimeSplit__
340  std::cout << "PennMicroSlice::sampleTimeSplit DEBUG type 0x" << std::hex << (unsigned int)type << " timestamp " << std::dec << timestamp << std::endl;
341 #endif
342  //check the timestamp
343  if(timestamp > boundary_time) {
344  //need to be careful and make sure that boundary_time hasn't overflowed the 28 bits
345  //do this by checking whether timestamp isn't very large AND boundary_time isn't very small
346  //TODO a better way to catch rollovers?
348  remaining_size = (buffer_ + pl_size) - pl_ptr;
349  return pl_ptr;
350  }
351  }
352  //check the type, to increment
353  switch(type)
354  {
357  break;
360  break;
363  break;
366  break;
369  break;
370  default:
371 
372  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type << std::endl;
373  return nullptr;
374  break;
375  }//switch(type)
376  }
377  return nullptr;
378 }
379 
380 //Returns a pointer to the first payload header AFTER boundary_time, and also counts payload types before/after the boundary
381 uint8_t* dune::PennMicroSlice::sampleTimeSplitAndCount(uint64_t boundary_time, size_t& remaining_size,
383  dune::PennMicroSlice::sample_count_t &n_counter_words_b,
384  dune::PennMicroSlice::sample_count_t &n_trigger_words_b,
385  dune::PennMicroSlice::sample_count_t &n_timestamp_words_b,
386  dune::PennMicroSlice::sample_count_t &n_selftest_words_b,
387  dune::PennMicroSlice::sample_count_t &n_checksum_words_b,
389  dune::PennMicroSlice::sample_count_t &n_counter_words_a,
390  dune::PennMicroSlice::sample_count_t &n_trigger_words_a,
391  dune::PennMicroSlice::sample_count_t &n_timestamp_words_a,
392  dune::PennMicroSlice::sample_count_t &n_selftest_words_a,
393  dune::PennMicroSlice::sample_count_t &n_checksum_words_a,
394  bool swap_payload_header_bytes, size_t override_uslice_size) const
395 {
396  throw cet::exception("PennMicroSlice") << "As of Jul-28-2015, dune::PennMicroSlice::sampleTimeSplitAndCount is deprecated";
397 
398  n_words_b = n_counter_words_b = n_trigger_words_b = n_timestamp_words_b = n_selftest_words_b = n_checksum_words_b = 0;
399  n_words_a = n_counter_words_a = n_trigger_words_a = n_timestamp_words_a = n_selftest_words_a = n_checksum_words_a = 0;
400  remaining_size = 0;
401  uint8_t* remaining_data_ptr = nullptr;
402  bool is_before = true;
403 
404  //if we're overriding, we don't have a Header to offset by
405  uint8_t* pl_ptr;
406  size_t pl_size;
407  if(override_uslice_size) {
408  pl_ptr = buffer_;
409  pl_size = override_uslice_size - sizeof(Header);
410  }
411  else {
412  pl_ptr = buffer_ + sizeof(Header);
413  pl_size = size();
414  }
415 
416  //loop over the microslice
417  while(pl_ptr < (buffer_ + pl_size)) {
418  if(swap_payload_header_bytes)
419  *((uint32_t*)pl_ptr) = ntohl(*((uint32_t*)pl_ptr));
420  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(pl_ptr);
423 #ifdef __DEBUG_sampleTimeSplitAndCount__
424  std::cout << "PennMicroSlice::sampleTimeSplitAndCount DEBUG type 0x" << std::hex << (unsigned int)type << " timestamp " << std::dec << timestamp << std::endl;
425 #endif
426  //check the timestamp
427  if(is_before && (timestamp > boundary_time)) {
428  //need to be careful and make sure that boundary_time hasn't overflowed the 28 bits
429  //do this by checking whether timestamp isn't very large AND boundary_time isn't very small
430  //TODO a better way to catch rollovers?
432  remaining_size = (buffer_ + pl_size) - pl_ptr;
433  remaining_data_ptr = pl_ptr;
434  is_before = false;
435  }
436  }
437  //check the type to increment counters & the ptr
438  switch(type)
439  {
441  if(is_before)
442  n_counter_words_b++;
443  else
444  n_counter_words_a++;
446  break;
448  if(is_before)
449  n_trigger_words_b++;
450  else
451  n_trigger_words_a++;
453  break;
455  if(is_before)
456  n_timestamp_words_b++;
457  else
458  n_timestamp_words_a++;
460  break;
462  if(is_before)
463  n_selftest_words_b++;
464  else
465  n_selftest_words_a++;
467  break;
469  if(is_before)
470  n_checksum_words_b++;
471  else
472  n_checksum_words_a++;
474  break;
475  default:
476  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type
477  << std::dec << std::endl;
478  return nullptr;
479  break;
480  }//switch(type)
481  }
482  n_words_b = n_counter_words_b + n_trigger_words_b + n_timestamp_words_b + n_selftest_words_b + n_checksum_words_b;
483  n_words_a = n_counter_words_a + n_trigger_words_a + n_timestamp_words_a + n_selftest_words_a + n_checksum_words_a;
484 #ifdef __DEBUG_sampleTimeSplitAndCount__
485  std::cout << "PennMicroSlice::sampleTimeSplitAndCount DEBUG returning with remaining size " << remaining_size << " for boundary_time " << boundary_time
486  << std::endl
487  << "PennMicroSlice::sampleTimeSplitAndCount DEBUG returning with: "
488  << " Payloads before " << n_words_b << " = " << n_counter_words_b << " + " << n_trigger_words_b
489  << " + " << n_timestamp_words_b << " + " << n_selftest_words_b << " + " << n_checksum_words_b
490  << " Payloads after " << n_words_a << " = " << n_counter_words_a << " + " << n_trigger_words_a
491  << " + " << n_timestamp_words_a << " + " << n_selftest_words_a << " + " << n_checksum_words_a
492  << std::endl;
493 #endif
494  return remaining_data_ptr;
495 }
496 
497 //Returns a pointer to the first payload header AFTER boundary_time, and also counts payload types before/after the boundary
498 //Also checks the overlap_time, and does the same for that
499 
500 // JCF, Jul-28-2015
501 
502 // Sections in the code where, e.g., there's a timestamp rollover will now result in an exception throw
503 
504 // NFB Dec-06-2015 : For the moment there are no fragmented microslices.
505 // Always assume that a full timestamp is sent
506 uint8_t* dune::PennMicroSlice::sampleTimeSplitAndCountTwice(uint64_t boundary_time, size_t& remaining_size,
507  uint64_t overlap_time, size_t& overlap_size, uint8_t*& overlap_data_ptr,
509  dune::PennMicroSlice::sample_count_t &n_counter_words_b,
510  dune::PennMicroSlice::sample_count_t &n_trigger_words_b,
511  dune::PennMicroSlice::sample_count_t &n_timestamp_words_b,
512  dune::PennMicroSlice::sample_count_t &n_selftest_words_b,
513  dune::PennMicroSlice::sample_count_t &n_checksum_words_b,
515  dune::PennMicroSlice::sample_count_t &n_counter_words_a,
516  dune::PennMicroSlice::sample_count_t &n_trigger_words_a,
517  dune::PennMicroSlice::sample_count_t &n_timestamp_words_a,
518  dune::PennMicroSlice::sample_count_t &n_selftest_words_a,
519  dune::PennMicroSlice::sample_count_t &n_checksum_words_a,
521  dune::PennMicroSlice::sample_count_t &n_counter_words_o,
522  dune::PennMicroSlice::sample_count_t &n_trigger_words_o,
523  dune::PennMicroSlice::sample_count_t &n_timestamp_words_o,
524  dune::PennMicroSlice::sample_count_t &n_selftest_words_o,
525  dune::PennMicroSlice::sample_count_t &n_checksum_words_o,
526  uint32_t &checksum,
527  bool swap_payload_header_bytes, size_t override_uslice_size) const
528 {
529  // words counted before the split time
530  n_words_b = n_counter_words_b = n_trigger_words_b = n_timestamp_words_b = n_selftest_words_b = n_checksum_words_b = 0;
531  // words counted after the split time
532  n_words_a = n_counter_words_a = n_trigger_words_a = n_timestamp_words_a = n_selftest_words_a = n_checksum_words_a = 0;
533  //n_words_o = n_counter_words_o = n_trigger_words_o = n_timestamp_words_o = n_selftest_words_o = n_checksum_words_o = 0; //don't reset these, as there is likely multiple uslices contained in the overlap
534 
535  overlap_size = remaining_size = 0;
536  checksum = 0;
537  uint8_t* remaining_data_ptr = nullptr;
538  overlap_data_ptr = nullptr;
539  bool is_before_boundary = true, is_before_overlap = true, is_in_overlap = false;
540 
541  //if we're overriding, we don't have a Header to offset by
542  // In principle we're always overriding, right?
543  uint8_t* pl_ptr;
544  size_t pl_size;
545 
546  if(override_uslice_size) {
547  pl_ptr = buffer_;
548  pl_size = override_uslice_size - sizeof(Header);
549  }
550  else {
551  pl_ptr = buffer_ + sizeof(Header);
552  pl_size = size();
553  }
554 
555 #ifdef __DEBUG_sampleTimeSplitAndCountTwice__
556  mf::LogInfo("PennMicroSlice") << "Dumping the received microslice with " << pl_size << " bytes.";
557  display_bits(pl_ptr, pl_size, "PennMicroSlice");
558 #endif
559 
560  uint8_t* aux_ptr = pl_ptr;
561  // First thing: Grab the checksum word as a crosscheck
563  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast<dune::PennMicroSlice::Payload_Header*>(aux_ptr);
565  mf::LogError("PennMicroSlice") << "Last word in the microslice is not a checksum :" << std::bitset<3>(payload_header->data_packet_type);
566  }
568  payload_header = reinterpret_cast<dune::PennMicroSlice::Payload_Header*>(aux_ptr);
570  mf::LogError("PennMicroSlice") << "Failed to find the timestamp :" << std::bitset<3>(payload_header->data_packet_type);
571  }
572 
573  // -- Assign the payload and get the timestamp to make sure that we are doing things right.
575  uint64_t microslice_boundary = pl_ts->nova_timestamp;
576 
577  uint64_t frame_timestamp = 0;
578 
579  //loop over the microslice
580  while(pl_ptr < (buffer_ + pl_size)) {
581 #ifdef __DEBUG_sampleTimeSplitAndCountTwice__
582 
583  mf::LogInfo("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG microslice_boundary = " << microslice_boundary;
584  mf::LogInfo("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG pointers."
585  << " Payload " << (unsigned int*)pl_ptr
586  << "\tOverlap " << (unsigned int*)overlap_data_ptr
587  << "\tRemaining " << (unsigned int*)remaining_data_ptr;
588 #endif
589 
590  // JCF, Jul-29-2015: is this "if" block necessary any longer?
591  if(swap_payload_header_bytes) {
592  *((uint32_t*)pl_ptr) = ntohl(*((uint32_t*)pl_ptr));
593  }
594 
595  dune::PennMicroSlice::Payload_Header* payload_header = reinterpret_cast_checked<dune::PennMicroSlice::Payload_Header*>(pl_ptr);
598 
599  // We know that only one rollover can occur within a microslice.
600  // Therefore if the rollover from the boundary is smaller than the timestamp
601  // it indeed rolled over
603  frame_timestamp = 0;
604  } else if ((microslice_boundary & 0x7FFFFFF) == timestamp) {
605  frame_timestamp = microslice_boundary;
606  } else if ((microslice_boundary & 0x7FFFFFF) > timestamp) {
607  frame_timestamp = microslice_boundary - ((microslice_boundary & 0x7FFFFFF) - timestamp);
608  } else {
609  // it rolled over.
610  // Be sure of the values being set
611  frame_timestamp = microslice_boundary - ((microslice_boundary & 0x7FFFFFF) + (0x7FFFFFF - timestamp));
612  }
613 
614 #ifdef __DEBUG_sampleTimeSplitAndCountTwice__
615  mf::LogInfo("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG >> frame_timestamp : " << frame_timestamp << " type " << std::bitset<3>(type);
616  // mf::LogDebug("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG type " << std::bitset<3>(type) << " timestamp " << static_cast<uint32_t>(timestamp) << " ["<< std::hex << timestamp << std::dec << "]";
617  // mf::LogDebug("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG full header [";
618  // display_bits(pl_ptr,4,"PennMicroSlice");
619  // mf::LogDebug("PennMicroSlice") << "]";
620  switch (type) {
621  case dune::PennMicroSlice::DataTypeCounter: // counter word
622 
623  mf::LogInfo("PennMicroSlice") << "Sample type: counter : [" << std::bitset<3>(type) << "]";
624  // mf::LogDebug("PennMicroSlice") << "Contents : [";
625  // display_bits(pl_ptr+dune::PennMicroSlice::Payload_Header::size_bytes,dune::PennMicroSlice::payload_size_counter,"PennMicroSlice");
626  // mf::LogDebug("PennMicroSlice") << "]";
627  break;
628  case dune::PennMicroSlice::DataTypeTrigger: // trigger word
629  mf::LogInfo("PennMicroSlice") << "Sample type: trigger : [" << std::bitset<3>(type) << "]";
630  // mf::LogDebug("PennMicroSlice") << "Contents : [";
631  // display_bits(pl_ptr+dune::PennMicroSlice::Payload_Header::size_bytes,dune::PennMicroSlice::payload_size_trigger,"PennMicroSlice");
632  // mf::LogDebug("PennMicroSlice") << "]";
633  break;
635  mf::LogInfo("PennMicroSlice") << "Sample type: checksum : [" << std::bitset<3>(type) << "]";
636  break;
637  case dune::PennMicroSlice::DataTypeTimestamp: // timestamp word
638  mf::LogInfo("PennMicroSlice") << "Sample type: timestamp : [" << std::bitset<3>(type) << "]";
639  // mf::LogDebug("PennMicroSlice") << "Contents : [";
640  // display_bits(pl_ptr+dune::PennMicroSlice::Payload_Header::size_bytes,dune::PennMicroSlice::payload_size_timestamp,"PennMicroSlice");
641  // mf::LogDebug("PennMicroSlice") << "]";
642  break;
643  case dune::PennMicroSlice::DataTypeWarning: //self test
644  mf::LogInfo("PennMicroSlice") << "Sample type: WARNING : [" << std::bitset<3>(type) << "]";
645  // mf::LogDebug("PennMicroSlice") << "Contents : [";
646  // display_bits(pl_ptr+dune::PennMicroSlice::Payload_Header::size_bytes,dune::PennMicroSlice::payload_size_warning,"PennMicroSlice");
647  // mf::LogDebug("PennMicroSlice") << "]";
648  break;
649  default:
650  mf::LogError("PennMicroSlice") << "Unexpected header type...something is going to fail [" << std::bitset<3>(type) << "]";
651  }
652 
653  // mf::LogDebug("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG: boundary_time == " <<
654  // boundary_time << ", overlap_time == " << overlap_time << ", is_before_boundary == " << is_before_boundary << ", overlap_size ==" << overlap_size <<
655  // ", is_before_overlap == " << is_before_overlap << ", is_in_overlap == " << is_in_overlap;
656 #endif
657 
658 
659  //check the timestamp
660  // Keep in mind that the timestamp should be incremented from the latest full timestamp received
661 
662  if (is_before_boundary && (frame_timestamp > boundary_time)) {
663  remaining_size = (buffer_ + pl_size) - pl_ptr;
664  remaining_data_ptr = pl_ptr;
665  is_before_boundary = false;
666  is_before_overlap = false;
667  is_in_overlap = false;
668  if (overlap_size) {
669  //take off the bytes after the overlap started,
670  // and after the end of the current millislice
671  overlap_size -= remaining_size;
672  }
673  } else if (is_before_overlap & (frame_timestamp > overlap_time)) {
674  overlap_size = (buffer_ + pl_size) - pl_ptr;
675  overlap_data_ptr = pl_ptr;
676  is_in_overlap = true;
677  is_before_overlap = false;
678  }
679  // otherwise it is still inside the millislice
680 
681 /**
682 
683 
684  // this logic is no longer needed
685  if(is_before_boundary && (frame_timestamp > boundary_time)) {
686  //need to be careful and make sure that boundary_time hasn't overflowed the 28 bits
687  //do this by checking whether timestamp isn't very large AND boundary_time isn't very small
688  //TODO a better way to catch rollovers?
689  if(!((boundary_time < dune::PennMicroSlice::ROLLOVER_LOW_VALUE) && (timestamp > dune::PennMicroSlice::ROLLOVER_HIGH_VALUE))) {
690  remaining_size = (buffer_ + pl_size) - pl_ptr;
691  remaining_data_ptr = pl_ptr;
692  is_before_boundary = false;
693  is_before_overlap = false;
694  is_in_overlap = false;
695 
696  if(overlap_size) {
697  overlap_size -= remaining_size; //take off the bytes after the overlap started, and after the end of the current millislice
698  }
699  } else {
700 
701  // JCF, Oct-20-2015
702 
703  // I need to use "loval" and "highval" in the cet::exception
704  // statement, otherwise debug builds will fail
705 
706  auto loval = dune::PennMicroSlice::ROLLOVER_LOW_VALUE;
707  auto highval = dune::PennMicroSlice::ROLLOVER_HIGH_VALUE;
708 
709  throw cet::exception("PennMicroSlice") << "Error: one or both of the following is true: boundary time of " <<
710  boundary_time << " is greater than ROLLOVER_LOW_VALUE time of " << loval <<
711  ", timestamp value of " << timestamp << " is less than ROLLOVER_HIGH_VALUE time of " << highval;
712  }
713  }
714  //'else' is to make sure we don't have data in both the 'overlap' and 'remaining' buffers
715  else if(is_before_overlap && (timestamp > overlap_time)) {
716 
717  //need to be careful and make sure that boundary_time hasn't overflowed the 28 bits
718  //do this by checking whether timestamp isn't very large AND boundary_time isn't very small
719  //TODO a better way to catch rollovers?
720  if(!((overlap_time < dune::PennMicroSlice::ROLLOVER_LOW_VALUE) && (timestamp > dune::PennMicroSlice::ROLLOVER_HIGH_VALUE))) {
721  overlap_size = (buffer_ + pl_size) - pl_ptr;
722  overlap_data_ptr = pl_ptr;
723  is_in_overlap = true;
724  is_before_overlap = false;
725  } else {
726 
727  // JCF, Oct-20-2015
728 
729  // I need to use "loval" and "highval" in the cet::exception
730  // statement, otherwise debug builds will fail
731 
732  auto loval = dune::PennMicroSlice::ROLLOVER_LOW_VALUE;
733  auto highval = dune::PennMicroSlice::ROLLOVER_HIGH_VALUE;
734 
735  throw cet::exception("PennMicroSlice") << "Error: one or both of the following is true: overlap time of " <<
736  overlap_time << " is greater than ROLLOVER_LOW_VALUE time of " << loval <<
737  ", timestamp value of " << timestamp << " is less than ROLLOVER_HIGH_VALUE time of " <<
738  highval;
739  }
740  }
741 
742 **/
743  //check the type to increment counters & the ptr
744  switch(type)
745  {
747  if(is_before_boundary)
748  n_counter_words_b++;
749  else
750  n_counter_words_a++;
751  if(is_in_overlap)
752  n_counter_words_o++;
754  break;
756  if(is_before_boundary)
757  n_trigger_words_b++;
758  else
759  n_trigger_words_a++;
760  if(is_in_overlap)
761  n_trigger_words_o++;
763  break;
765  if(is_before_boundary)
766  n_timestamp_words_b++;
767  else
768  n_timestamp_words_a++;
769  if(is_in_overlap)
770  n_timestamp_words_o++;
772  // mf::LogInfo("PennMicroSlice") << "JCF, sampleTimeSplitAndCountTwice: now have n_timestamp_words_b == " <<
773  // n_timestamp_words_b << ", n_timestamp_words_a == " << n_timestamp_words_a <<
774  // ", n_timestamp_words_o == " << n_timestamp_words_o;
775  break;
777  {
778  dune::PennMicroSlice::Warning_Word *wh = reinterpret_cast_checked<dune::PennMicroSlice::Warning_Word *>(pl_ptr);
779  switch(wh->warning_type) {
780  /// Issue the warning HERE:
782  mf::LogWarning("PennMicroSlice") << "The DMA timed out. Possible data loss after this point."; break;
784  mf::LogWarning("PennMicroSlice") << "Unknown data type received."; break;
786  mf::LogWarning("PennMicroSlice") << "FIFO reached half full state. Stop run recommended.";
787  break;
789  mf::LogError("PennMicroSlice") << "FIFO reached full state. Data after this point is unreliable.";
790  break;
791  default:
792  mf::LogError("PennMicroSlice") << "Unknown FIFO warning type " << std::bitset<5>(wh->warning_type);
793  }
794  if(is_before_boundary)
795  n_selftest_words_b++;
796  else
797  n_selftest_words_a++;
798  if(is_in_overlap)
799  n_selftest_words_o++;
801  break;
802  }
804  if(is_before_boundary)
805  n_checksum_words_b++;
806  else
807  n_checksum_words_a++;
808  if(is_in_overlap)
809  n_checksum_words_o++;
810 
811  // mf::LogInfo("PennMicroSlice") << "JCF, sampleTimeSplitAndCountTwice: now have n_checksum_words_b == " <<
812  // n_checksum_words_b << ", n_checksum_words_a == " << n_checksum_words_a <<
813  // ", n_checksum_words_o == " << n_checksum_words_o;
814 
815  // It is correct. The checksum is stored in the 2 lsB
816  checksum = *( reinterpret_cast<uint16_t*>(pl_ptr) );
817 
819  break;
820  default:
821  mf::LogError("PennMicroSlice") << "Unknown data packet type found 0x" << std::hex << (unsigned int)type
822  << std::dec;
823 
824  std::cerr << "Unknown data packet type found 0x" << std::hex << (unsigned int)type
825  << std::dec << std::endl;
826  return nullptr;
827  break;
828  }//switch(type)
829  }
830  n_words_b = n_counter_words_b + n_trigger_words_b + n_timestamp_words_b + n_selftest_words_b + n_checksum_words_b;
831  n_words_a = n_counter_words_a + n_trigger_words_a + n_timestamp_words_a + n_selftest_words_a + n_checksum_words_a;
832  n_words_o = n_counter_words_o + n_trigger_words_o + n_timestamp_words_o + n_selftest_words_o + n_checksum_words_o;
833 #ifdef __DEBUG_sampleTimeSplitAndCountTwice__
834  mf::LogInfo("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG returning with:"
835  << " remaining size " << remaining_size << " for boundary_time " << boundary_time
836  << " overlap size " << overlap_size << " for overlap_time " << overlap_time;
837 
838  mf::LogInfo("PennMicroSlice") << "PennMicroSlice::sampleTimeSplitAndCountTwice DEBUG returning with: "
839  << " Payloads before " << n_words_b << " = " << n_counter_words_b << " + " << n_trigger_words_b
840  << " + " << n_timestamp_words_b << " + " << n_selftest_words_b << " + " << n_checksum_words_b
841  << " Payloads after " << n_words_a << " = " << n_counter_words_a << " + " << n_trigger_words_a
842  << " + " << n_timestamp_words_a << " + " << n_selftest_words_a << " + " << n_checksum_words_a
843  << " Overlap payloads " << n_words_o << " = " << n_counter_words_o << " + " << n_trigger_words_o
844  << " + " << n_timestamp_words_o << " + " << n_selftest_words_o << " + " << n_checksum_words_o ;
845 #endif
846  return remaining_data_ptr;
847 }
848 
849 // Returns a pointer to the raw data words in the microslice for diagnostics
850 uint32_t* dune::PennMicroSlice::raw() const
851 {
852  return reinterpret_cast_checked<uint32_t*>(buffer_);
853 }
854 
855 // Returns a pointer to the microslice header
857 {
858  return reinterpret_cast_checked<Header const *>(buffer_);
859 }
860 
861 // Returns a pointer to the first payload data word in the microslice
862 // Careful. The payloads are tricky because they still have to recover a bit from the header
863 // This logic might not be correct
864 uint32_t const* dune::PennMicroSlice::data_() const
865 {
866  return reinterpret_cast_checked<uint32_t const*>(buffer_ + sizeof(dune::PennMicroSlice::Header));
867 }
static microslice_size_t const payload_size_trigger
static microslice_size_t const payload_size_timestamp
static const Warning_Word::warning_type_t WarnFIFOHalfFull
static const Payload_Header::data_packet_type_t DataTypeWarning
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
static microslice_size_t const payload_size_checksum
Header::sequence_id_t sequence_id() const
uint8_t * get_payload(uint32_t word_id, Payload_Header::data_packet_type_t &data_packet_type, Payload_Header::short_nova_timestamp_t &short_nova_timestamp, size_t &size, bool swap_payload_header_bytes, size_t override_uslice_size=0) const
static const uint64_t ROLLOVER_HIGH_VALUE
QTextStream & hex(QTextStream &s)
void display_bits(void *memstart, size_t nbytes, std::string sourcename)
Definition: Utilities.cc:10
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
static const Payload_Header::data_packet_type_t DataTypeTimestamp
sample_count_t sampleCount(sample_count_t &n_counter_words, sample_count_t &n_trigger_words, sample_count_t &n_timestamp_words, sample_count_t &n_selftest_words, sample_count_t &n_checksum_words, bool swap_payload_header_bytes, size_t override_uslice_size=0) const
static microslice_size_t const payload_size_counter
Header const * header_() const
short_nova_timestamp_t short_nova_timestamp
static const Warning_Word::warning_type_t WarnUnknownDataType
PennMicroSlice(uint8_t *address)
Header::block_size_t microslice_size_t
dune::PennMicroSlice::microslice_size_t size() const
static const Payload_Header::data_packet_type_t DataTypeChecksum
Header::format_version_t format_version() const
QTextStream & dec(QTextStream &s)
uint8_t * sampleTimeSplitAndCountTwice(uint64_t boundary_time, size_t &remaining_size, uint64_t overlap_time, size_t &overlap_size, uint8_t *&overlap_data_ptr, sample_count_t &n_words_b, sample_count_t &n_counter_words_b, sample_count_t &n_trigger_words_b, sample_count_t &n_timestamp_words_b, sample_count_t &n_selftest_words_b, sample_count_t &n_checksum_words_b, sample_count_t &n_words_a, sample_count_t &n_counter_words_a, sample_count_t &n_trigger_words_a, sample_count_t &n_timestamp_words_a, sample_count_t &n_selftest_words_a, sample_count_t &n_checksum_words_a, sample_count_t &n_words_o, sample_count_t &n_counter_words_o, sample_count_t &n_trigger_words_o, sample_count_t &n_timestamp_words_o, sample_count_t &n_selftest_words_o, sample_count_t &n_checksum_words_o, uint32_t &checksum, bool swap_payload_header_bytes, size_t override_uslice_size=0) const
static const Payload_Header::data_packet_type_t DataTypeTrigger
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
static QCString type
Definition: declinfo.cpp:672
Frame header : Common header to everything except warning words.
uint32_t * raw() const
Header::block_size_t block_size() const
uint32_t const * data_() const
static const Warning_Word::warning_type_t WarnTimeout
Header of ethernet packet.
static const Warning_Word::warning_type_t WarnFIFOFull
uint8_t * get_next_payload(uint32_t &word_id, Payload_Header::data_packet_type_t &data_packet_type, Payload_Header::short_nova_timestamp_t &short_nova_timestamp, size_t &size, bool swap_payload_header_bytes, size_t override_uslice_size=0)
static const uint32_t ROLLOVER_LOW_VALUE
static microslice_size_t const payload_size_warning
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
static const Payload_Header::data_packet_type_t DataTypeCounter
QTextStream & endl(QTextStream &s)
uint8_t * sampleTimeSplit(uint64_t boundary_time, size_t &remaining_size, bool swap_payload_header_bytes, size_t override_uslice_size=0) const
uint8_t * sampleTimeSplitAndCount(uint64_t boundary_time, size_t &remaining_size, sample_count_t &n_words_b, sample_count_t &n_counter_words_b, sample_count_t &n_trigger_words_b, sample_count_t &n_timestamp_words_b, sample_count_t &n_selftest_words_b, sample_count_t &n_checksum_words_b, sample_count_t &n_words_a, sample_count_t &n_counter_words_a, sample_count_t &n_trigger_words_a, sample_count_t &n_timestamp_words_a, sample_count_t &n_selftest_words_a, sample_count_t &n_checksum_words_a, bool swap_payload_header_bytes, size_t override_uslice_size=0) const