MiniballSort
Loading...
Searching...
No Matches
MidasConverter.cc
Go to the documentation of this file.
1#include "MidasConverter.hh"
2
3
4// Function to copy the header from a DataSpy, for example
5void MiniballMidasConverter::SetBlockHeader( char *input_header ){
6
7 // Copy header
8 for( unsigned int i = 0; i < HEADER_SIZE; i++ )
9 block_header[i] = input_header[i];
10
11 return;
12
13}
14
15// Function to process header words
17
18 // For each new header, reset the swap mode
19 swap = 0;
20
21 // Flag when we find the end of the data
22 flag_terminator = false;
23
24 // Process header.
25 for( UInt_t i = 0; i < 8; i++ )
26 header_id[i] = block_header[i];
27
29 (block_header[8] & 0xFF) << 24 | (block_header[9]& 0xFF) << 16 |
30 (block_header[10]& 0xFF) << 8 | (block_header[11]& 0xFF);
31
32 header_stream = (block_header[12] & 0xFF) << 8 | (block_header[13]& 0xFF);
33
34 header_tape = (block_header[14] & 0xFF) << 8 | (block_header[15]& 0xFF);
35
36 header_MyEndian = (block_header[16] & 0xFF) << 8 | (block_header[17]& 0xFF);
37
38 header_DataEndian = (block_header[18] & 0xFF) << 8 | (block_header[19]& 0xFF);
39
41 (block_header[20] & 0xFF) | (block_header[21]& 0xFF) << 8 |
42 (block_header[22] & 0xFF) << 16 | (block_header[23]& 0xFF) << 24 ;
43
44 if( std::string(header_id).substr(0,8) != "EBYEDATA" ) {
45
46 std::cerr << "Bad header in block " << nblock << std::endl;
47 exit(0);
48
49 }
50
51 return;
52
53}
54
55
56// Function to copy the main data from a DataSpy, for example
57void MiniballMidasConverter::SetBlockData( char *input_data ){
58
59 // Copy header
60 for( UInt_t i = 0; i < MAIN_SIZE; i++ )
61 block_data[i] = input_data[i];
62
63 return;
64
65}
66
67
68// Function to process data words
70
71 // Get the data in 64-bit words and check endieness and swap if needed
72 // Data format here: http://npg.dl.ac.uk/documents/edoc504/edoc504.html
73 // Unpack in to two 32-bit words for purposes of data format
74
75 // Swap mode is unknown for the first block of data, so let's work it out
76 if( (swap & SWAP_KNOWN) == 0 ) {
77
78 // See if we can figure out the swapping - the DataEndian word of the
79 // header is 256 if the endianness is correct, otherwise swap endianness
80 if( header_DataEndian != 256 ) swap |= SWAP_ENDIAN;
81
82 // However, that is not all, the words may also be swapped, so check
83 // for that. Bits 31:30 should always be zero in the timestamp word
84 for( UInt_t i = 0; i < WORD_SIZE; i++ ) {
85 ULong64_t word = (swap & SWAP_ENDIAN) ? Swap64(data[i]) : data[i];
86 if( word & 0xC000000000000000LL ) {
88 break;
89 }
90 if( word & 0x00000000C0000000LL ) {
93 break;
94 }
95 }
96
97 }
98
99 // If the previous buffer was full and we want to reject the
100 // next buffer, because of the readout bugs in September 2023,
101 // this is the place to do it. Next buffer might be good again!
102 if( buffer_full ){
103
104 buffer_full = false;
105 buffer_part = true;
106
107 }
108 else buffer_part = false;
109
110
111 // Get the size of real data
112 UInt_t real_DataLen = header_DataLen/sizeof(ULong64_t);
113
114 // Check if this is a full buffer
115 if( real_DataLen == WORD_SIZE ) buffer_full = true;
116
117 // Check if we should reject this event
118 if( ( buffer_full && set->GetBufferFullRejection() ) ||
119 ( buffer_part && set->GetBufferPartRejection() ) ) {
120
121 reject_ctr++;
122 return;
123
124 }
125
126 // Process data in the buffer
127 NewBuffer();
128 for( UInt_t i = 0; i < real_DataLen; i++ ) {
129
130 word = GetWord(i);
131 word_0 = (word & 0xFFFFFFFF00000000) >> 32;
132 word_1 = (word & 0x00000000FFFFFFFF);
133
134 // Data type is highest two bits
135 my_type = ( word_0 >> 30 ) & 0x3;
136
137 // ADC data - we always assume it comes from FEBEX
138 if( my_type == 0x3 ){
139
140 ProcessFebexData(nblock);
142 FinishFebexData(nblock);
143
144 }
145
146 // Information data
147 else if( my_type == 0x2 ){
148
149 ProcessInfoData(nblock);
150
151 }
152
153 // Trace header
154 else if( my_type == 0x1 ){
155
156 i = ProcessTraceData(i);
157 FinishFebexData(nblock);
158
159 }
160
161 else {
162
163 // output error message!
164 std::cerr << "WARNING: WRONG TYPE! word 0: " << std::bitset<32>{word_0};
165 std::cerr << ", my_type: " << (int)my_type;
166 std::cerr << ", in block: " << nblock << std::endl;
167
168 }
169
170 } // loop - i < header_DataLen
171
172 return;
173
174}
175
177
178 // ADCchannelIdent are bits 28:16 of word_0
179 // sfp_id= bit 11:10, board_id= bit 9:6, data_id= bit 5:4, ch_id= bit 3:0
180 // data_id: fast mode readout: =0 16 bit integer; =1 16 bit float;
181 // =2 32 bit float (low 16 bits); =3 32 bit float (high 16 bits)
182 // standard mode readout: 0= 16 bit integer
183 unsigned int ADCchanIdent = (word_0 >> 16) & 0x0FFF; // 12 bits from 16
184 my_sfp_id = (ADCchanIdent >> 10) & 0x0003; // 2 bits from 10
185 my_board_id = (ADCchanIdent >> 6) & 0x000F; // 4 bits from 6
186 my_data_id = (ADCchanIdent >> 4) & 0x0003; // 2 bits from 4
187 my_ch_id = ADCchanIdent & 0x000F; // 4 bits from 0
188
189 // Check things make sense
190 if( my_sfp_id >= set->GetNumberOfFebexSfps() ||
191 my_board_id >= set->GetNumberOfFebexBoards() ||
192 my_ch_id >= set->GetNumberOfFebexChannels() ) {
193
194 std::cerr << "Bad FEBEX event with SFP = " << (int)my_sfp_id;
195 std::cerr << ", board = " << (int)my_board_id;
196 std::cerr << ", ch_id = " << (int)my_ch_id;
197 std::cerr << ", data_id = " << (int)my_data_id << std::endl;
198 std::cerr << " word_0 = " << std::hex << word_0 << std::dec << " = ";
199 std::cerr << std::bitset<32>{word_0} << std::endl;
200 std::cerr << " word_1 = " << std::hex << word_1 << std::dec << " = ";
201 std::cerr << std::bitset<32>{word_1} << std::endl;
202
203 return false;
204
205 }
206
207 else return true;
208
209}
210
212
213 // Channel ID, etc
214 if( !GetFebexChanID() ) return pos;
215
216 // reconstruct time stamp= MSB+LSB
217 my_tm_stp_lsb = word_1 & 0x0FFFFFFF; // 28 bits from 0
218 my_tm_stp = ( my_tm_stp_hsb << 48 ) | ( my_tm_stp_msb << 28 ) | my_tm_stp_lsb;
219
220 // FEBEX timestamps are in 10ns precision?
221 my_tm_stp = my_tm_stp*10;
222
223 // Make a FebexData item
224 febex_data->SetTime( my_tm_stp );
225 febex_data->SetSfp( my_sfp_id );
226 febex_data->SetBoard( my_board_id );
227 febex_data->SetChannel( my_ch_id );
228 febex_data->SetPileup( false );
229 febex_data->SetFlag( my_flagbit );
230
231 // sample length
232 nsamples = word_0 & 0xFFFF; // 16 bits from 0
233
234 // Get the samples from the trace
235 for( UInt_t j = 0; j < nsamples/4; j++ ){
236
237 // get next word
238 ULong64_t sample_packet = GetWord(++pos);
239
240 UInt_t block_test = ( sample_packet >> 32 ) & 0x00000000FFFFFFFF;
241
242 // Note from Carl Unsworth in elog:22769 referring to note in edoc504.
243 // Basically the trace_test as defined below is not applicable for FEBEX data.
244 // We test if the two uppermost bits are 00, but this isn't always the case.
245 // Therefore, we are hacking for now to define it as so in case we change our mind
246 // then at least the code still exists to go back to some type of test.
247 // unsigned char trace_test = ( sample_packet >> 62 ) & 0x0000000000000003;
248 unsigned char trace_test = 0;
249
250 if( trace_test == 0 && block_test != 0x5E5E5E5E ){
251
252 // Usually the top two bits are zero and we mask them off
253 //febex_data->AddSample( ( sample_packet >> 48 ) & 0x0000000000003FFF );
254 //febex_data->AddSample( ( sample_packet >> 32 ) & 0x0000000000003FFF );
255 //febex_data->AddSample( ( sample_packet >> 16 ) & 0x0000000000003FFF );
256 //febex_data->AddSample( sample_packet & 0x0000000000003FFF );
257
258 // FEBEX might not be masking the top two bits with zero
259 // And the pairs need to be swapped. First sample goes to lower bits
260 febex_data->AddSample( ( sample_packet >> 32 ) & 0x000000000000FFFF );
261 febex_data->AddSample( ( sample_packet >> 48 ) & 0x000000000000FFFF );
262 febex_data->AddSample( sample_packet & 0x000000000000FFFF );
263 febex_data->AddSample( ( sample_packet >> 16 ) & 0x000000000000FFFF );
264
265 }
266
267 else {
268
269 //std::cout << "This isn't a trace anymore..." << std::endl;
270 //std::cout << "Sample #" << j << " of " << nsamples << std::endl;
271 //std::cout << " trace_test = " << (int)trace_test << std::endl;
272
273 pos--;
274 break;
275
276 }
277
278 }
279
280 FebexMWD mwd = cal->DoMWD( my_sfp_id, my_board_id, my_ch_id, febex_data->GetTrace() );
281 febex_data->SetClipped( mwd.IsClipped() );
282
283 for( unsigned int i = 0; i < mwd.NumberOfTriggers(); ++i )
285
286 flag_febex_trace = true;
287
288 return pos;
289
290}
291
293
294 // Channel ID, etc
295 if( !GetFebexChanID() ) return;
296
297 // Febex data format
298 my_adc_data = word_0 & 0xFFFF; // 16 bits from 0
299
300 // Pileup and other info bits from James' firmware
301 my_pileup = (word_0 >> 29) & 0x0001;
302 my_clip = (word_0 >> 28) & 0x0001;
303
304 // reconstruct time stamp= MSB+LSB
305 my_tm_stp_lsb = word_1 & 0x0FFFFFFF; // 28 bits from 0
306 my_tm_stp = ( my_tm_stp_hsb << 48 ) | ( my_tm_stp_msb << 28 ) | my_tm_stp_lsb; // commented out 09/02/2023
307 //my_tm_stp = my_tm_stp_lsb; // matching Vic's format of 09/02/2023
308
309 // FEBEX timestamps are in 10ns precision?
310 my_tm_stp = my_tm_stp*10;
311
312 // If this is the first full data item of the buffer,
313 // we need to update the read timestamp to check things are good
314 if( first_data[my_sfp_id] ) {
315
316 // Update timestamp and set first data
318 first_data[my_sfp_id] = false;
319 //std::cout << std::hex << my_tm_stp << std::endl;
320
321 }
322
323 // First of the data items
326
327 // Make a FebexData item
328 febex_data->SetTime( my_tm_stp );
329 febex_data->SetSfp( my_sfp_id );
330 febex_data->SetBoard( my_board_id );
331 febex_data->SetChannel( my_ch_id );
332 febex_data->SetPileup( my_pileup );
333 febex_data->SetClipped( my_clip );
334 febex_data->SetFlag( my_flagbit );
335
336 }
337
338 // If we already have all the data items, then the next event has
339 // already occured before we found traces. This means that there
340 // is not trace data. So set the flag to be true and finish the
341 // event with an empty trace.
342 // Note 10/02/2022, we don't always get data type 1
343 else if( flag_febex_data0 &&
345
346 // Finish up the previous event
347 FinishFebexData(nblock);
348
349 // Then set the info correctly for this event
350 febex_data->SetTime( my_tm_stp );
351 febex_data->SetSfp( my_sfp_id );
352 febex_data->SetBoard( my_board_id );
353 febex_data->SetChannel( my_ch_id );
354 febex_data->SetPileup( my_pileup );
355 febex_data->SetClipped( my_clip );
356 febex_data->SetFlag( my_flagbit );
357
358 }
359
360 // If we're in the old readout mode, the next event will be with
361 // data_id of 0 again. So we close the event by faking a full set
362 else if( flag_febex_data0 && !flag_febex_data2 &&
363 !flag_febex_data3 && my_data_id == 0 ){
364
365 // Fake all other data items
366 flag_febex_data1 = true;
367 flag_febex_data2 = true;
368 flag_febex_data3 = true;
369
370 // Finish up the previous event
371 FinishFebexData(nblock);
372
373 // Then set the info correctly for this event
374 febex_data->SetTime( my_tm_stp );
375 febex_data->SetSfp( my_sfp_id );
376 febex_data->SetBoard( my_board_id );
377 febex_data->SetChannel( my_ch_id );
378 febex_data->SetPileup( my_pileup );
379 febex_data->SetClipped( my_clip );
380 febex_data->SetFlag( my_flagbit );
381
382 }
383
384 // 16-bit integer (energy but rebinned)
385 if( my_data_id == 0 ) {
386
387 my_adc_data = my_adc_data&0xFFFF;
388 febex_data->SetQshort( my_adc_data );
389 flag_febex_data0 = true;
390
391 }
392
393 // 16-bit integer (time difference to previous data group)
394 if( my_data_id == 1 ) {
395
396 my_tdiff_data = my_adc_data&0xFFFF;
397 flag_febex_data1 = true;
398
399 }
400
401 // 32-bit integer (low 16 bits of energy)
402 if( my_data_id == 2 ) {
403
405 flag_febex_data2 = true;
406
407 }
408
409 // 32-bit integer (high 16 bits of energy)
410 if( my_data_id == 3 ) {
411
413 flag_febex_data3 = true;
414
415 }
416
417 return;
418
419}
420
422
423 // Timestamp with offset
424 unsigned long long int time_corr;
425
426 // Got all items in fast readout mode or trace only mode
427 //if( ( flag_febex_data0 && flag_febex_data1 &&
428 // flag_febex_data2 && flag_febex_data3 ) || flag_febex_trace ){
429
430 // James says (22/08/2022) that we only get the 32-bit integer now
431 // Update, Carl reports that the two halves are in data_id = 0, 1, not 2, 3 as documented
432 // Update again on 10/02/2022, Vic has made edits to the format and we get 0, 2 and 3 always
433 // if( ( flag_febex_data0 && flag_febex_data1 ) || flag_febex_trace ){
435
436 // Add the time offset to this channel
437 time_corr = febex_data->GetTime();
438 time_corr += cal->FebexTime( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() );
439
440 // Timestamp checks
441 long long int sfp_check = febex_data->GetTime() - tm_stp_read[febex_data->GetSfp()];
442 long long int board_check = febex_data->GetTime() - tm_stp_febex[febex_data->GetSfp()][febex_data->GetBoard()];
443 long long int channel_check = febex_data->GetTime() - tm_stp_febex_ch[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()];
444
445 // Check how we compare to the first timestamp from this buffer (1000 seconds)
446 if( !first_data[febex_data->GetSfp()] && ( sfp_check > 1000e9 || sfp_check < -1000e9 ) && nblock > 1 ){
447
448 std::cerr << "Timestamp mash in SFP = " << std::dec << (int)febex_data->GetSfp();
449 std::cerr << ", board = " << (int)febex_data->GetBoard();
450 std::cerr << ", channel = " << (int)febex_data->GetChannel();
451 std::cerr << ":\n\t" << std::hex << febex_data->GetTime()/10;
452 std::cerr << " ~/~ " << tm_stp_read[febex_data->GetSfp()]/10;
453 std::cerr << std::dec << std::endl;
454
455 mash_ctr++;
456 data_ctr++;
457
458 }
459
460 // Skip large forwards time jumps in same board, maybe?
461 else if( tm_stp_febex[febex_data->GetSfp()][febex_data->GetBoard()] != 0 &&
462 board_check > 240e9 ) {
463
464 std::cerr << "Timestamp jump in SFP = " << std::dec << (int)febex_data->GetSfp();
465 std::cerr << ", board = " << (int)febex_data->GetBoard();
466 std::cerr << ", channel = " << (int)febex_data->GetChannel();
467 std::cerr << ":\n\t" << std::hex << febex_data->GetTime()/10;
468 std::cerr << " >> " << tm_stp_febex[febex_data->GetSfp()][febex_data->GetBoard()]/10;
469 std::cerr << std::dec << std::endl;
470
471 // Update board time in case of slow counting channels
472 // but don't update the channel time in case it's anomalous
473 tm_stp_febex[febex_data->GetSfp()][febex_data->GetBoard()] = febex_data->GetTime();
474
475 jump_ctr++;
476 data_ctr++;
477
478 }
479
480 // What if we jump backwards on an individual channel?
481 else if( tm_stp_febex_ch[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()] != 0 &&
482 channel_check < 0 ) {
483
484 std::cerr << "Timestamp warp in SFP = " << std::dec << (int)febex_data->GetSfp();
485 std::cerr << ", board = " << (int)febex_data->GetBoard();
486 std::cerr << ", channel = " << (int)febex_data->GetChannel();
487 std::cerr << ":\n\t" << std::hex << febex_data->GetTime()/10;
488 std::cerr << " < " << tm_stp_febex_ch[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]/10;
489 std::cerr << std::dec << std::endl;
490
491 warp_ctr++;
492 data_ctr++;
493
494 }
495
496 // Otherwise we can carry on because it's good data
497 else {
498
499 // Combine the two halfs of the 32-bit integer point ADC energy
500 my_adc_data_int = ( my_adc_data_hsb << 16 ) | ( my_adc_data_lsb & 0xFFFF );
501 febex_data->SetQint( my_adc_data_int );
502
503 // Bodge to match Vic's data format on 09/02/2023
504 //my_adc_data_int = my_adc_data_lsb & 0xFFFF;
505 //febex_data->SetQint( my_adc_data_int );
506
507 // Calibrate and set energies
508 unsigned int adc_tmp_value;
509 if( cal->FebexType( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) == "Qshort" )
510 adc_tmp_value = febex_data->GetQshort();
511
512 else if( cal->FebexType( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) == "Qint" )
513 adc_tmp_value = febex_data->GetQint();
514
515 else {
516
517 std::cerr << "Unrecognised data type: " << cal->FebexType( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() );
518 std::cerr << " in SFP " << (int)febex_data->GetSfp() << std::endl;
519 std::cerr << ", board " << (int)febex_data->GetBoard() << std::endl;
520 std::cerr << ", channel " << (int)febex_data->GetChannel() << std::endl;
521 std::cout << "\tDefault to Qshort" << std::endl;
522 adc_tmp_value = febex_data->GetQshort();
523
524 }
525
526 my_energy = cal->FebexEnergy( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel(), adc_tmp_value );
527 febex_data->SetEnergy( my_energy );
528
529 // Check if it's over threshold
530 if( adc_tmp_value > cal->FebexThreshold( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) )
531 febex_data->SetThreshold( true );
532 else febex_data->SetThreshold( false );
533
534 // Check if this is actually just a timestamp or info like event
535 flag_febex_info = false;
536 if( set->IsPulser( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() ) ) {
537
538 flag_febex_info = true;
539 unsigned int pulserID = set->GetPulser( febex_data->GetSfp(), febex_data->GetBoard(), febex_data->GetChannel() );
540 my_info_code = set->GetPulserCode() + pulserID;
541
542 }
543
544 else if( febex_data->GetSfp() == set->GetEBISSfp() &&
545 febex_data->GetBoard() == set->GetEBISBoard() &&
546 febex_data->GetChannel() == set->GetEBISChannel() ){
547
548 flag_febex_info = true;
549 my_info_code = 21; // EBIS is always 21 (defined here)
550
551 // Check EBIS time and period
552 if( ebis_tm_stp != 0 && ebis_period == 0 &&
553 febex_data->GetTime() > (long long)ebis_tm_stp ){
554
555 ebis_period = febex_data->GetTime() - ebis_tm_stp;
557 std::cout << "EBIS period detected = " << ebis_period;
558 std::cout << " ns" << std::endl;
559
560 }
561
562 ebis_tm_stp = febex_data->GetTime();
563
564 }
565
566 else if( febex_data->GetSfp() == set->GetT1Sfp() &&
567 febex_data->GetBoard() == set->GetT1Board() &&
568 febex_data->GetChannel() == set->GetT1Channel() ){
569
570 flag_febex_info = true;
571 my_info_code = 22; // T1 is always 22 (defined here)
572
573 }
574
575 else if( febex_data->GetSfp() == set->GetSCSfp() &&
576 febex_data->GetBoard() == set->GetSCBoard() &&
577 febex_data->GetChannel() == set->GetSCChannel() ){
578
579 flag_febex_info = true;
580 my_info_code = 23; // SC is always 23 (defined here)
581
582 }
583
584 else if( febex_data->GetSfp() == set->GetRILISSfp() &&
585 febex_data->GetBoard() == set->GetRILISBoard() &&
586 febex_data->GetChannel() == set->GetRILISChannel() ){
587
588 flag_febex_info = true;
589 my_info_code = 24; // RILIS is always 24 (defined here)
590
591 }
592
593 // If this is a timestamp, fill an info event
594 if( flag_febex_info ) {
595
596 info_data->SetTime( time_corr );
597 info_data->SetSfp( febex_data->GetSfp() );
598 info_data->SetBoard( febex_data->GetBoard() );
599 info_data->SetCode( my_info_code );
600
601 // Fill only if we are not doing a source run
602 if( !flag_source ) {
603 std::shared_ptr<MiniballDataPackets> data_packet =
604 std::make_shared<MiniballDataPackets>( info_data );
605 data_vector.emplace_back( data_packet );
606 data_map.push_back( std::make_pair<unsigned long,double>(
607 data_vector.size()-1, data_packet->GetTime() ) );
608 }
609 data_ctr++;
610
611 }
612
613 // Otherwise it is real data, so fill a FEBEX event
614 // but only if we are in an EBIS time window or we want all data
615 else if( !flag_ebis || EBISWindow( febex_data->GetTime() ) ) {
616
617 // Set this data and fill event to tree
618 // Also add the time offset when we do this
619 febex_data->SetTime( time_corr );
620
621 // Fill only if we are not doing a source run
622 if( !flag_source ) {
623 std::shared_ptr<MiniballDataPackets> data_packet =
624 std::make_shared<MiniballDataPackets>( febex_data );
625 data_vector.emplace_back( data_packet );
626 data_map.push_back( std::make_pair<unsigned long,double>(
627 data_vector.size()-1, data_packet->GetTime() ) );
628 }
629 data_ctr++;
630
631 }
632
633 // Fill histograms and check clipped etc
634 bool fillflag = true;
635 if( febex_data->IsClipped() && set->GetClippedRejection() )
636 fillflag = false;
637
638 if( febex_data->IsPileup() && set->GetPileupRejection() )
639 fillflag = false;
640
641 // Only fill if we haven't rejected it, but data still goes to the tree
642 if( fillflag ){
643
644 hfebex_qshort[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( febex_data->GetQshort() );
645 hfebex_qint[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( febex_data->GetQint() );
646 hfebex_cal[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()]->Fill( my_energy );
647
648 }
649
650 // Reset the latest board and channel timestamps
651 tm_stp_febex[febex_data->GetSfp()][febex_data->GetBoard()] = time_corr;
652 tm_stp_febex_ch[febex_data->GetSfp()][febex_data->GetBoard()][febex_data->GetChannel()] = time_corr;
653
654 } // not being rejecting for jumps or warps
655
656 }
657
658 // missing something
659 else if( (long long int)my_tm_stp != febex_data->GetTime() ) {
660
661 std::cerr << "Missing something in FEBEX data and new event occured" << std::endl;
662 std::cerr << " Current timestamp = " << std::hex << my_tm_stp << std::endl;
663 std::cerr << " Previous timestamp = " << std::hex << febex_data->GetTime() << std::endl;
664 std::cerr << " Qshort = " << std::boolalpha << flag_febex_data0 << std::endl;
665 std::cerr << " nonsense item = " << std::boolalpha << flag_febex_data1 << std::endl; // missing anyway
666 std::cerr << " Qint (low) = " << std::boolalpha << flag_febex_data2 << std::endl;
667 std::cerr << " Qint (high) = " << std::boolalpha << flag_febex_data3 << std::endl;
668 std::cerr << " trace data = " << std::boolalpha << flag_febex_trace << std::endl;
669 std::cerr << std::dec;
670
671 }
672
673 // This is normal, just not finished yet
674 else return;
675
676 // Fill histograms
677 if( febex_data->GetSfp() >= set->GetNumberOfFebexSfps() ||
678 febex_data->GetBoard() >= set->GetNumberOfFebexBoards() ||
679 febex_data->GetChannel() >= set->GetNumberOfFebexChannels() ) {
680
681 std::cerr << "Bad event ID: SFP = " << (int)febex_data->GetSfp();
682 std::cerr << ", board = " << (int)febex_data->GetBoard();
683 std::cerr << ", channel = " << (int)febex_data->GetChannel() << std::endl;
684 std::cerr << " word_0 = " << std::hex << word_0 << std::dec << " = ";
685 std::cerr << std::bitset<32>{word_0} << std::endl;
686 std::cerr << " word_1 = " << std::hex << word_1 << std::dec << " = ";
687 std::cerr << std::bitset<32>{word_1} << std::endl;
688
689 }
690
691 else {
692
693 hfebex_hit[febex_data->GetSfp()][febex_data->GetBoard()]->Fill(
694 ctr_febex_hit[febex_data->GetSfp()][febex_data->GetBoard()],
695 febex_data->GetTime(), 1 );
696
697 // Count the hit, even if it's bad
698 ctr_febex_hit[febex_data->GetSfp()][febex_data->GetBoard()]++;
699
700 }
701
702 // Assuming it did finish, in a good way or bad, clean up.
703 flag_febex_data0 = false;
704 flag_febex_data1 = false;
705 flag_febex_data2 = false;
706 flag_febex_data3 = false;
707 flag_febex_trace = false;
708 febex_data->ClearData();
709 info_data->ClearData();
710
711 return;
712
713}
714
716
717 // Module number from MIDAS
718 my_sfp_id = (word_0 >> 28) & 0x0003; // bits 28:29
719 my_board_id = (word_0 >> 24) & 0x000F; // bits 24:27
720
721 // MIDAS info data format
722 my_info_field = word_0 & 0x000FFFFF; // bits 0:19
723 my_info_code = (word_0 >> 20) & 0x0000000F; // bits 20:23
724 my_tm_stp_lsb = word_1 & 0x0FFFFFFF; // bits 0:27
725
726 // Error catching
727 if( my_sfp_id >= set->GetNumberOfFebexSfps() ||
728 my_board_id >= set->GetNumberOfFebexBoards() ) {
729
730 std::cerr << "Bad info event with SFP = " << (int)my_sfp_id;
731 std::cerr << ", board = " << (int)my_board_id;
732 std::cerr << ", code = " << (int)my_info_code;
733 std::cerr << ", field = " << (int)my_info_field << std::endl;
734 std::cerr << " word_0 = " << std::hex << word_0 << std::dec << " = ";
735 std::cerr << std::bitset<32>{word_0} << std::endl;
736 std::cerr << " word_1 = " << std::hex << word_1 << std::dec << " = ";
737 std::cerr << std::bitset<32>{word_1} << std::endl;
738
739 return;
740
741 }
742
743
744 // HSB of FEBEX extended timestamp
745 if( my_info_code == set->GetHsbTimestampCode() ) {
746
747 // Check that the timestamp isn't weird
748 int tmp_tm_stp = my_info_field & 0x0000FFFF;
749 if( tmp_tm_stp == 0x0000A5A5 &&
750 ( my_tm_stp_hsb & 0x0000FF00 ) == 0x0000A500 ) {
751
752 //my_tm_stp_hsb = tmp_tm_stp;
753 my_tm_stp_hsb = 0;
754
755 }
756
757 // Huh? What is this?
758 if( ( my_info_field & 0x0000FFFF ) > 0 )
759 my_flagbit = true;
760 else my_flagbit = false;
761
762 }
763
764 // MSB of FEBEX extended timestamp
765 if( my_info_code == set->GetMsbTimestampCode() ) {
766
767 //if(my_tm_stp_hsb>0)
768 // std::cout << my_tm_stp_hsb << " " << my_tm_stp_msb << std::endl;
769
770 // Check that the timestamp isn't weird
771 int tmp_tm_stp = my_info_field & 0x000FFFFF;
772 if( ( tmp_tm_stp & 0x00000FF0 ) == 0x00000A50 &&
773 ( my_tm_stp_msb & 0x0000FF0 ) != 0x0000A40 &&
774 ( my_tm_stp_msb & 0x0000FF0 ) != 0x0000A50 &&
775 ( my_tm_stp_msb & 0x0000FF0 ) != 0x0000A60 &&
776 my_tm_stp_msb > 0 ) {
777
778 long tmp_full = ( (long)tmp_tm_stp << 48 ) | ( my_tm_stp_msb << 28 ) | ( my_tm_stp_lsb & 0x0FFFFFFF );
779 std::cout << "Corrupt MSB timestamp? 0x" << std::hex;
780 std::cout << tmp_tm_stp << std::endl << "\t";
781 std::cout << tmp_full << std::dec << std::endl;
782
783 }
784
785 else {
786
787 // In FEBEX this would be the extended timestamp
788 my_tm_stp_msb = tmp_tm_stp;
789 my_tm_stp = ( my_tm_stp_hsb << 48 ) | ( my_tm_stp_msb << 28 ) | ( my_tm_stp_lsb & 0x0FFFFFFF );
790
791 }
792
793 }
794
795 // Pause
796 if( my_info_code == set->GetPauseCode() ) {
797
798 my_tm_stp_msb = my_info_field & 0x000FFFFF;
799 my_tm_stp = ( my_tm_stp_hsb << 48 ) | ( my_tm_stp_msb << 28 ) | ( my_tm_stp_lsb & 0x0FFFFFFF );
800
803
804 }
805
806 // Resume
807 if( my_info_code == set->GetResumeCode() ) {
808
809 my_tm_stp_msb = my_info_field & 0x000FFFFF;
810 my_tm_stp = ( my_tm_stp_hsb << 48 ) | ( my_tm_stp_msb << 28 ) | ( my_tm_stp_lsb & 0x0FFFFFFF );
811
814
815 }
816
817 // Sync pulse in FEBEX (HSB)
818 if( my_info_code == set->GetHsbSyncCode() ) {
819
820 sync_tm_stp_hsb = my_info_field & 0x000000FF;
821 my_tm_stp = ( sync_tm_stp_hsb << 48 ) | ( sync_tm_stp_msb << 28 ) | ( my_tm_stp_lsb & 0x0FFFFFFF );
823
826
827 }
828
829 // Sync pulse in FEBEX (MSB)
830 if( my_info_code == set->GetMsbSyncCode() ) {
831
832 sync_tm_stp_msb = my_info_field & 0x000FFFFF;
833
834 }
835
836 // Create an info event and fill the tree for external triggers and pause/resume
837 if( my_info_code != set->GetMsbTimestampCode() &&
838 my_info_code != set->GetHsbTimestampCode() &&
839 my_info_code != set->GetHsbSyncCode()) {
840
841 info_data->SetSfp( my_sfp_id );
842 info_data->SetBoard( my_board_id );
843 info_data->SetTime( my_tm_stp*10 );
844 info_data->SetCode( my_info_code );
845 std::shared_ptr<MiniballDataPackets> data_packet = std::make_shared<MiniballDataPackets>( info_data );
846
847 // Fill only if we are not doing a source run
848 // Or comment out if we want to skip them because we're not debugging
849 if( !flag_source ) {
850 std::shared_ptr<MiniballDataPackets> data_packet =
851 std::make_shared<MiniballDataPackets>( info_data );
852 data_vector.emplace_back( data_packet );
853 data_map.push_back( std::make_pair<unsigned long,double>(
854 data_vector.size()-1, data_packet->GetTime() ) );
855 }
856 info_data->Clear();
857
858 }
859
860 return;
861
862}
863
864// Common function called to process data in a block from file or DataSpy
866
867 // Process header.
868 ProcessBlockHeader( nblock );
869
870 // Process the main block data until terminator found
871 data = (ULong64_t *)(block_data);
872 ProcessBlockData( nblock );
873
874 // Note 08/11/2023 - This isn't the right thing to do
875 // Check once more after going over left overs....
876 //if( !flag_terminator ){
877 //
878 // std::cout << std::endl << __PRETTY_FUNCTION__ << std::endl;
879 // std::cout << "\tERROR - Terminator sequence not found in data.\n";
880 // return false;
881 //
882 //}
883
884 // Occassionally, sort the data vector to speed things up?
885 //if( (nblock+1) % 3000 == 0 && (BLOCKS_NUM-nblock) > 3000 ) SortDataVector();
886
887 return true;
888
889}
890
891// Function to convert a block of data from DataSpy
892int MiniballMidasConverter::ConvertBlock( char *input_block, long nblock ) {
893
894 // Get the header.
895 std::memmove( &block_header, &input_block[0], HEADER_SIZE );
896
897 // Get the block
898 std::memmove( &block_data, &input_block[HEADER_SIZE], MAIN_SIZE );
899
900 // Process the data
901 ProcessCurrentBlock( nblock );
902
903 return nblock+1;
904
905}
906
907// Function to run the conversion for a single file
908int MiniballMidasConverter::ConvertFile( std::string input_file_name,
909 unsigned long start_block,
910 long end_block ) {
911
912 // Uncomment to force only a few blocks - debug
913 //end_block = 1000;
914
915 // Read the file.
916 std::ifstream input_file( input_file_name, std::ios::in|std::ios::binary );
917 if( !input_file.is_open() ){
918
919 std::cout << "Cannot open " << input_file_name << std::endl;
920 return -1;
921
922 }
923
924 // Conversion starting
925 std::cout << "Converting MIDAS file: " << input_file_name;
926 std::cout << " from block " << start_block << std::endl;
927
928 // Reset counters and data vectors to zero for every file
929 StartFile();
930
931 // Calculate the size of the file.
932 input_file.seekg( 0, input_file.end );
933 unsigned long long int size_end = input_file.tellg();
934 input_file.seekg( 0, input_file.beg );
935 unsigned long long int size_beg = input_file.tellg();
936 unsigned long long int FILE_SIZE = size_end - size_beg;
937
938 // Calculate the number of blocks in the file.
939 BLOCKS_NUM = FILE_SIZE / DATA_BLOCK_SIZE;
940
941 // a sanity check for file size...
942 if( FILE_SIZE % DATA_BLOCK_SIZE != 0 ){
943
944 std::cout << " *WARNING* " << __PRETTY_FUNCTION__;
945 std::cout << "\tMissing data blocks?" << std::endl;
946
947 }
948
949 sslogs << "\t File size = " << FILE_SIZE << std::endl;
950 sslogs << "\tBlock size = " << DATA_BLOCK_SIZE << std::endl;
951 sslogs << "\t N blocks = " << BLOCKS_NUM << std::endl;
952
953 std::cout << sslogs.str() << std::endl;
954 sslogs.str( std::string() ); // clean up
955
956
957 // Data format: http://npg.dl.ac.uk/documents/edoc504/edoc504.html
958 // The information is split into 2 words of 32 bits (4 byte).
959 // We will collect the data in 64 bit words and split later
960
961 // Loop over all the blocks.
962 for( unsigned long nblock = 0; nblock < BLOCKS_NUM ; nblock++ ){
963
964 // Take one block each time and analyze it.
965 if( nblock % 200 == 0 || nblock+1 == BLOCKS_NUM ) {
966
967 // Percent complete
968 float percent = (float)(nblock+1)*100.0/(float)BLOCKS_NUM;
969
970 // Progress bar in GUI
971 if( _prog_ ){
972
973 prog->SetPosition( percent );
974 gSystem->ProcessEvents();
975
976 }
977
978 // Progress bar in terminal
979 std::cout << " " << std::setw(8) << std::setprecision(4);
980 std::cout << percent << "%\r";
981 std::cout.flush();
982
983 }
984
985
986 // Get the header.
987 input_file.read( (char*)&block_header, HEADER_SIZE );
988 // Get the block
989 input_file.read( (char*)&block_data, MAIN_SIZE );
990
991
992 // Check if we are before the start block or after the end block
993 if( nblock < start_block || ( (long)nblock > end_block && end_block > 0 ) )
994 continue;
995
996
997 // Process current block. If it's the end, stop.
998 if( !ProcessCurrentBlock( nblock ) ) break;
999
1000 } // loop - nblock < BLOCKS_NUM
1001
1002 input_file.close();
1003
1004 // Print the number of warps and jumps
1005 sslogs << "Number of timestamp jumps = " << jump_ctr;
1006 sslogs << " / " << data_ctr << " = ";
1007 sslogs << 100.0 * (double)jump_ctr / (double)data_ctr;
1008 sslogs << "\%" << std::endl;
1009
1010 sslogs << "Number of timestamp warps = " << warp_ctr;
1011 sslogs << " / " << data_ctr << " = ";
1012 sslogs << 100.0 * (double)warp_ctr / (double)data_ctr;
1013 sslogs << "\%" << std::endl;
1014
1015 sslogs << "Number of timestamp mashes = " << mash_ctr;
1016 sslogs << " / " << data_ctr << " = ";
1017 sslogs << 100.0 * (double)mash_ctr / (double)data_ctr;
1018 sslogs << "\%" << std::endl;
1019
1020 sslogs << "Number of rejected blocks = " << reject_ctr;
1021 sslogs << " / " << BLOCKS_NUM << " = ";
1022 sslogs << 100.0 * (double)reject_ctr / (double)BLOCKS_NUM;
1023 sslogs << "\%" << std::endl;
1024
1025 std::cout << sslogs.str() << std::endl;
1026 sslogs.str( std::string() ); // clean up
1027
1028 return BLOCKS_NUM;
1029
1030}
float GetEnergy(unsigned int i)
void DoMWD()
bool IsClipped()
unsigned int NumberOfTriggers()
std::shared_ptr< FebexData > febex_data
Definition Converter.hh:166
unsigned long sync_tm_stp_hsb
Definition Converter.hh:125
unsigned int my_adc_data_int
Definition Converter.hh:135
std::vector< std::vector< TProfile * > > hfebex_hit
Definition Converter.hh:193
std::vector< std::vector< TProfile * > > hfebex_resume
Definition Converter.hh:195
std::vector< std::vector< std::vector< long long int > > > tm_stp_febex_ch
Definition Converter.hh:213
unsigned int ebis_period
Definition Converter.hh:127
std::vector< std::vector< std::vector< TH1F * > > > hfebex_qint
Definition Converter.hh:202
unsigned long sync_tm_stp_msb
Definition Converter.hh:124
unsigned short my_adc_data_hsb
Definition Converter.hh:134
unsigned char my_board_id
Definition Converter.hh:138
unsigned short my_adc_data
Definition Converter.hh:132
std::vector< std::vector< TProfile * > > hfebex_pause
Definition Converter.hh:194
unsigned long int jump_ctr
Definition Converter.hh:187
unsigned char my_data_id
Definition Converter.hh:140
unsigned char my_type
Definition Converter.hh:130
std::vector< std::vector< std::vector< TH1F * > > > hfebex_mwd
Definition Converter.hh:205
long long ebis_tm_stp
Definition Converter.hh:119
std::vector< std::vector< unsigned long int > > ctr_febex_sync
Definition Converter.hh:186
unsigned char my_info_code
Definition Converter.hh:129
unsigned long my_tm_stp_lsb
Definition Converter.hh:121
unsigned char my_ch_id
Definition Converter.hh:139
std::shared_ptr< MiniballCalibration > cal
Definition Converter.hh:220
unsigned short my_adc_data_lsb
Definition Converter.hh:133
unsigned long int data_ctr
Definition Converter.hh:188
std::vector< std::vector< std::vector< TH1F * > > > hfebex_cal
Definition Converter.hh:204
unsigned short my_tdiff_data
Definition Converter.hh:131
std::shared_ptr< MiniballSettings > set
Definition Converter.hh:217
std::vector< std::shared_ptr< MiniballDataPackets > > data_vector
Definition Converter.hh:170
unsigned int ebis_first
Definition Converter.hh:128
unsigned int nsamples
Definition Converter.hh:149
std::vector< std::vector< unsigned long int > > ctr_febex_resume
Definition Converter.hh:185
unsigned long long sync_tm_stp
Definition Converter.hh:118
std::shared_ptr< InfoData > info_data
Definition Converter.hh:167
std::vector< std::pair< unsigned long, double > > data_map
Definition Converter.hh:171
std::vector< long long int > tm_stp_read
Definition Converter.hh:211
unsigned char my_sfp_id
Definition Converter.hh:137
std::stringstream sslogs
Definition Converter.hh:105
std::vector< std::vector< long long int > > tm_stp_febex
Definition Converter.hh:212
std::vector< std::vector< unsigned long int > > ctr_febex_pause
Definition Converter.hh:184
std::shared_ptr< TGProgressBar > prog
Definition Converter.hh:224
unsigned long int reject_ctr
Definition Converter.hh:189
std::vector< std::vector< unsigned long int > > ctr_febex_hit
Definition Converter.hh:183
unsigned long my_tm_stp_msb
Definition Converter.hh:122
unsigned long int mash_ctr
Definition Converter.hh:187
unsigned long int warp_ctr
Definition Converter.hh:187
bool EBISWindow(long long int t)
Definition Converter.hh:82
std::vector< bool > first_data
Definition Converter.hh:210
unsigned long my_tm_stp_hsb
Definition Converter.hh:123
unsigned long long my_tm_stp
Definition Converter.hh:117
unsigned int my_info_field
Definition Converter.hh:126
std::vector< std::vector< TProfile * > > hfebex_sync
Definition Converter.hh:196
std::vector< std::vector< std::vector< TH1F * > > > hfebex_qshort
Definition Converter.hh:203
void SetBlockData(char *input_data)
void ProcessFebexData(long nblock)
void ProcessBlockHeader(long nblock)
void FinishFebexData(long nblock)
static const int WORD_SIZE
char block_data[MAIN_SIZE]
static const int DATA_BLOCK_SIZE
void ProcessBlockData(long nblock)
static const int HEADER_SIZE
int ConvertFile(std::string input_file_name, unsigned long start_block=0, long end_block=-1)
bool ProcessCurrentBlock(long nblock)
ULong64_t GetWord(UInt_t n=0)
int ConvertBlock(char *input_block, long nblock)
void SetBlockHeader(char *input_header)
char block_header[HEADER_SIZE]
static const int MAIN_SIZE
ULong64_t Swap64(ULong64_t datum)
void ProcessInfoData(long nblock)