File indexing completed on 2025-08-03 08:20:48
0001 #include "oncsSub_idmvtxv2.h"
0002 #include <cstring>
0003 #include <bitset>
0004 #include <map>
0005 #include <vector>
0006 #include <functional>
0007
0008 #include <arpa/inet.h>
0009
0010 using namespace std;
0011
0012 oncsSub_idmvtxv2::oncsSub_idmvtxv2(subevtdata_ptr data)
0013 :oncsSubevent_w4 (data)
0014 {
0015 _is_decoded = 0;
0016 _highest_ruid = -1;
0017 _decoder_error = 0;
0018 for (int ruid=0; ruid<IDMVTXV2_MAXRUID+1; ruid++)
0019 {
0020 _bad_ruchns[ruid] = 0;
0021 _lanes_active[ruid] = -1;
0022 _lane_stops[ruid] = -1;
0023 _lane_timeouts[ruid] = -1;
0024 _inconsistent_bc[ruid] = -1;
0025 for ( int ruchn = 0; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0026 {
0027 _chip_id[ruid][ruchn] = -1;
0028 _bad_bytes[ruid][ruchn] = 0;
0029 _excess_bytes[ruid][ruchn] = 0;
0030 _bunchcounter[ruid][ruchn] = -1;
0031 _header_found[ruid][ruchn] = false;
0032 _trailer_found[ruid][ruchn] = false;
0033 _readout_flags[ruid][ruchn] = -1;
0034 }
0035 }
0036 _unexpected_felix_counters = 0;
0037 _bad_ruids = 0;
0038 }
0039
0040 oncsSub_idmvtxv2::~oncsSub_idmvtxv2()
0041 {
0042
0043 }
0044
0045
0046 typedef struct
0047 {
0048 unsigned char d0[3][10];
0049 unsigned char counter;
0050 unsigned char ruid;
0051 } data32;
0052
0053
0054 void oncsSub_idmvtxv2::print_stuff(OSTREAM& out, unsigned int data, int width, int shift, bool blank) const
0055 {
0056 unsigned int mask = 0xffffffff;
0057 if (width<8) mask = ((1 << width*4)-1);
0058 if (blank)
0059 for (int i=0;i<width;i++) out << " ";
0060 else
0061 out << std::hex << SETW(width) << std::setfill('0') << ((data>>shift) & mask);
0062 }
0063
0064 int oncsSub_idmvtxv2::encode_hit(unsigned short row, unsigned short col) const
0065 {
0066 return (row << 16) + col;
0067 }
0068
0069 unsigned short oncsSub_idmvtxv2::decode_row(int hit) const
0070 {
0071 return hit >> 16;
0072 }
0073
0074 unsigned short oncsSub_idmvtxv2::decode_col(int hit) const
0075 {
0076 return hit & 0xffff;
0077 }
0078
0079 bool oncsSub_idmvtxv2::mask_contains_ruchn ( int mask, int ruchn )
0080 {
0081 if (ruchn<=0) return false;
0082 if (mask<0) return false;
0083 return (((mask >> (ruchn-1)) & 1) == 1);
0084 }
0085
0086 int *oncsSub_idmvtxv2::decode ()
0087 {
0088 if ( _is_decoded) return 0;
0089 _is_decoded = 1;
0090 _decoder_error = 0;
0091
0092 unsigned int *payload = (unsigned int *) &SubeventHdr->data;
0093
0094 int dlength = getDataLength() - getPadding() - 1;
0095 unsigned char *the_end = ( unsigned char *) &payload[dlength];
0096
0097 unsigned char *pos = (unsigned char *) payload;
0098
0099 unsigned char b;
0100
0101 vector<unsigned char> ruchn_stream[IDMVTXV2_MAXRUID+1][IDMVTXV2_MAXRUCHN+1];
0102
0103 unsigned char felix_counter [IDMVTXV2_MAXRUID+1];
0104
0105 for( int i=0; i < IDMVTXV2_MAXRUID+1; i++)
0106 {
0107 felix_counter[i] = 0;
0108 }
0109
0110 while ( pos < the_end )
0111 {
0112
0113 data32 *d32 = ( data32*) pos;
0114
0115
0116 if (d32->ruid > IDMVTXV2_MAXRUID)
0117 {
0118 cout << __FILE__ << " " << __LINE__ << " --- invalid ruid " << hex << (int) d32->ruid << " at pos " << (long) pos << dec << endl;
0119 _bad_ruids++;
0120 _decoder_error |= ( 1 << 0 );
0121 break;
0122 }
0123 else if (d32->ruid > _highest_ruid)
0124 {
0125 _highest_ruid = d32->ruid;
0126 }
0127
0128
0129 int counter_increment = (d32->counter + 256 - felix_counter[d32->ruid])%256;
0130 if (counter_increment > 3)
0131 {
0132 if (d32->counter != 0)
0133 {
0134
0135 _unexpected_felix_counters++;
0136 }
0137 break;
0138 }
0139 felix_counter[d32->ruid] = d32->counter;
0140
0141
0142 for (int ichnk = 0; ichnk < counter_increment; ichnk++)
0143 {
0144 unsigned char ruchn = d32->d0[ichnk][9];
0145 if (ruchn >> 4 == 0x2) {
0146 ruchn &= 0x1F;
0147 ruchn += 1;
0148 }
0149 if (ruchn == IDMVTXV2_RUHEADER)
0150 {
0151 memcpy(&_lanes_active[d32->ruid],&d32->d0[ichnk][2],4);
0152 }
0153 else if (ruchn == IDMVTXV2_RUTRAILER)
0154 {
0155 memcpy(&_lane_stops[d32->ruid],&d32->d0[ichnk][0],4);
0156 memcpy(&_lane_timeouts[d32->ruid],&d32->d0[ichnk][4],4);
0157 }
0158 else if (ruchn > IDMVTXV2_MAXRUCHN)
0159 {
0160 _bad_ruchns[d32->ruid]++;
0161 cout << __FILE__ << " " << __LINE__ << " --- invalid ruchn " << hex << ruchn << ", full RU word: ";
0162 _decoder_error |= ( 1 << 1 );
0163 for (int ibyte=9;ibyte>=0;ibyte--)
0164 {
0165 cout << setfill('0') << setw(2) << hex << (unsigned int) d32->d0[ichnk][ibyte] << " ";
0166 }
0167 cout << setfill(' ') << setw(0) << dec << endl;
0168 }
0169 else for ( int ibyte = 0; ibyte < 9; ibyte++)
0170 {
0171
0172 ruchn_stream[d32->ruid][ruchn].push_back(d32->d0[ichnk][ibyte]);
0173 }
0174 }
0175
0176 pos += sizeof(*d32);
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 for ( int ruid = 1; ruid < IDMVTXV2_MAXRUID+1; ruid++)
0188 {
0189 for ( int ruchn = 1; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0190 {
0191
0192 bool header_seen=false;
0193 int status = 0;
0194 int ibyte_endofdata = -1;
0195 int the_region = -1;
0196 unsigned int address = 0;
0197 unsigned int encoder_id = 0;
0198 for (unsigned int ibyte = 0; ibyte < ruchn_stream[ruid][ruchn].size(); ibyte++)
0199 {
0200 b = ruchn_stream[ruid][ruchn].at(ibyte);
0201
0202
0203
0204 if (status)
0205
0206 {
0207 switch (status)
0208 {
0209 case CHIPHEADER:
0210
0211 _bunchcounter[ruid][ruchn] = b;
0212
0213 status = 0;
0214 _header_found[ruid][ruchn] = true;
0215 break;
0216
0217 case CHIPEMPTYFRAME:
0218
0219 _bunchcounter[ruid][ruchn] = b;
0220
0221 ibyte_endofdata = ibyte;
0222 _header_found[ruid][ruchn] = true;
0223 _trailer_found[ruid][ruchn] = true;
0224 status = 0;
0225 break;
0226
0227 case DATASHORT:
0228 address += b;
0229
0230
0231
0232
0233
0234
0235 if ( the_region >= 0 && encoder_id >=0 )
0236 {
0237 unsigned int row = (address >> 1);
0238 unsigned int col = (the_region * 32);
0239 col += (encoder_id * 2) + ( (row & 1) ? ( (address & 1) ^ 1 ) : (address & 1) );
0240 if ( row < 0 || row >= NROW || col < 0 || col >= NCOL )
0241 {
0242 cout << __FILE__ << " " << __LINE__ << " impossible pixel coord: " << row
0243 << ", " << col << "." << endl;
0244 cout << "Check region " << the_region << ", encoder " << encoder_id
0245 << ", addr " << address << endl;
0246 _decoder_error |= ( 1 << 2);
0247 }
0248 _hit_vectors[ruid][ruchn].push_back(encode_hit(row,col));
0249 }
0250
0251
0252 status = 0;
0253 break;
0254
0255 case DATALONG0:
0256 address += b;
0257 status = DATALONG1;
0258 break;
0259
0260 case DATALONG1:
0261 if ( (b & 0x80) != 0)
0262 {
0263
0264 _bad_bytes[ruid][ruchn]++;
0265 }
0266
0267
0268
0269
0270 for (int ihit = 0; ihit<8; ihit++)
0271 {
0272 if (ihit==0 || ((b >> (ihit-1)) & 1))
0273 {
0274 int hit_address = address + ihit;
0275 if ( the_region >= 0 && encoder_id >=0 )
0276 {
0277 unsigned int row = (hit_address >> 1);
0278 unsigned int col = the_region*32;
0279 col += (encoder_id * 2) + ( (row & 1) ? ( (hit_address & 1) ^ 1 ) : (hit_address & 1) );
0280 if ( row < 0 || row >= NROW || col < 0 || col >= NCOL )
0281 {
0282 cout << __FILE__ << " " << __LINE__ << " impossible pixel coord: " << row
0283 << ", " << col << "." << endl;
0284 cout << "Check region " << the_region << ", encoder " << encoder_id
0285 << ", addr " << hit_address << endl;
0286 _decoder_error |= ( 1 << 2);
0287 }
0288 _hit_vectors[ruid][ruchn].push_back(encode_hit(row,col));
0289 }
0290 }
0291 }
0292 status = 0;
0293 break;
0294 }
0295 continue;
0296 }
0297
0298 if (ibyte_endofdata != -1) break;
0299
0300 if ( b == 0xff)
0301 {
0302
0303 status = 0;
0304 }
0305
0306 else if ( ( b >> 4) == 0xa)
0307 {
0308 _chip_id[ruid][ruchn] = ( b & 0xf);
0309 header_seen = true;
0310 status = CHIPHEADER;
0311 }
0312
0313 else if ( ( b >> 4) == 0xb)
0314 {
0315
0316
0317 ibyte_endofdata = ibyte;
0318 _trailer_found[ruid][ruchn] = true;
0319 if (!_header_found[ruid][ruchn])
0320 {
0321 _bad_bytes[ruid][ruchn]++;
0322 }
0323 else
0324 {
0325 _readout_flags[ruid][ruchn] = (b & 0xf);
0326 }
0327 break;
0328 }
0329
0330 else if ( ( b >> 4) == 0xE)
0331 {
0332 _chip_id[ruid][ruchn] = ( b & 0xf);
0333 header_seen = true;
0334 status = CHIPEMPTYFRAME;
0335 }
0336
0337 else if ( ( b >> 5) == 0x6)
0338 {
0339 unsigned int region_id = (b & 0x1f);
0340 if ( region_id <32)
0341 {
0342 the_region = region_id;
0343 }
0344 else
0345 {
0346 cout << __FILE__ << " " << __LINE__ << " wrong region header, id= " << hex << region_id << dec << endl;
0347 _decoder_error |= ( 1 << 3);
0348 }
0349 }
0350
0351 else if ( ( b >> 6) == 0x1)
0352 {
0353 encoder_id = ( b>>2) & 0xf;
0354 address = (b & 0x3) << 8;
0355 status = DATASHORT;
0356 }
0357
0358 else if ( ( b >> 6) == 0x0)
0359 {
0360 encoder_id = ( b>>2) & 0xf;
0361 address = (b & 0x3) << 8;
0362 status = DATALONG0;
0363 }
0364
0365 else if ( b == 0xF1)
0366 {
0367
0368 }
0369
0370 else if ( b == 0xF0)
0371 {
0372
0373 }
0374
0375 else
0376 {
0377 cout << __FILE__ << " " << __LINE__ << " unexpected word " << hex << (unsigned int) b << dec << " at ibyte " << ibyte << endl;
0378 _bad_bytes[ruid][ruchn]++;
0379 _decoder_error |= ( 1 << 4 );
0380 }
0381
0382 if (ibyte==0 && !header_seen)
0383 {
0384 cout << __FILE__ << " " << __LINE__ << " " << "first byte of the ALPIDE stream must be a chip header or chip empty;" <<endl;
0385 cout << "Aborting so we don't get confused by bad data." << endl;
0386 _decoder_error |= ( 1 << 5 );
0387 break;
0388 }
0389
0390 }
0391
0392
0393 for (unsigned int ibyte = ibyte_endofdata+1; ibyte < ruchn_stream[ruid][ruchn].size(); ibyte++)
0394 {
0395 b = ruchn_stream[ruid][ruchn].at(ibyte);
0396 if (b!=0)
0397 {
0398
0399 _excess_bytes[ruid][ruchn]++;
0400 }
0401 }
0402 }
0403 if (_lanes_active[ruid] != -1)
0404 {
0405 _inconsistent_bc[ruid] = this->checkBC(ruid);
0406 }
0407 }
0408
0409
0410 return 0;
0411 }
0412
0413 int oncsSub_idmvtxv2::iValue(const int ruid, const char *what)
0414 {
0415 decode();
0416 if ( strcmp(what, "DECODER_ERROR") == 0 )
0417 {
0418 return _decoder_error;
0419 }
0420 if ( strcmp(what,"UNEXPECTED_FELIX_COUNTERS") == 0 )
0421 {
0422 return _unexpected_felix_counters;
0423 }
0424
0425 else if ( strcmp(what,"BAD_RUIDS") == 0 )
0426 {
0427 return _bad_ruids;
0428 }
0429
0430 if (ruid > _highest_ruid) return -1;
0431 if (_lanes_active[ruid]==-1) return -1;
0432
0433 if ( strcmp(what,"BAD_RUCHNS") == 0 )
0434 {
0435 return _bad_ruchns[ruid];
0436 }
0437
0438 else if ( strcmp(what,"LANE_STOPS") == 0 )
0439 {
0440 return _lane_stops[ruid];
0441 }
0442
0443 else if ( strcmp(what,"LANE_TIMEOUTS") == 0 )
0444 {
0445 return _lane_timeouts[ruid];
0446 }
0447
0448 else if ( strcmp(what,"CHECK_BC") == 0 )
0449 {
0450 return _inconsistent_bc[ruid];
0451 }
0452
0453 return 0;
0454 }
0455
0456 int oncsSub_idmvtxv2::iValue(const int ruid)
0457 {
0458 decode();
0459
0460 if (ruid > _highest_ruid) return -1;
0461 return _lanes_active[ruid];
0462 }
0463
0464 int oncsSub_idmvtxv2::iValue(const int ruid, const int ruchn, const char *what)
0465 {
0466 decode();
0467
0468 if (ruid > _highest_ruid) return -1;
0469 if (_lanes_active[ruid]==-1) return -1;
0470
0471 if ( strcmp(what,"CHIP_ID") == 0 )
0472 {
0473 return _chip_id[ruid][ruchn];
0474 }
0475
0476 else if ( strcmp(what,"BAD_BYTES") == 0 )
0477 {
0478 return _bad_bytes[ruid][ruchn];
0479 }
0480
0481 else if ( strcmp(what,"EXCESS_BYTES") == 0 )
0482 {
0483 return _excess_bytes[ruid][ruchn];
0484 }
0485
0486 else if ( strcmp(what,"BUNCHCOUNTER") == 0 )
0487 {
0488 return _bunchcounter[ruid][ruchn];
0489 }
0490
0491 else if ( strcmp(what,"HEADER_FOUND") == 0 )
0492 {
0493 return _header_found[ruid][ruchn]?1:0;
0494 }
0495
0496 else if ( strcmp(what,"TRAILER_FOUND") == 0 )
0497 {
0498 return _trailer_found[ruid][ruchn]?1:0;
0499 }
0500
0501 else if ( strcmp(what,"READOUT_FLAGS") == 0 )
0502 {
0503 return _readout_flags[ruid][ruchn];
0504 }
0505
0506 return 0;
0507 }
0508
0509 int oncsSub_idmvtxv2::iValue(const int ruid, const int ruchn)
0510 {
0511 decode();
0512
0513 if (ruid > _highest_ruid) return -1;
0514 if (_lanes_active[ruid]==-1) return -1;
0515 if (!mask_contains_ruchn(_lanes_active[ruid],ruchn)) return -1;
0516 return _hit_vectors[ruid][ruchn].size();
0517 }
0518
0519 int oncsSub_idmvtxv2::iValue(const int ruid, const int ruchn, const int i)
0520 {
0521 decode();
0522
0523 if (ruid > _highest_ruid) return -1;
0524 if (_lanes_active[ruid]==-1) return -1;
0525 if (!mask_contains_ruchn(_lanes_active[ruid],ruchn)) return -1;
0526 return _hit_vectors[ruid][ruchn].at(i);
0527 }
0528
0529 void oncsSub_idmvtxv2::dump ( OSTREAM& os )
0530 {
0531
0532 identify(os);
0533
0534 decode();
0535 bool first;
0536 for (int ruid=0; ruid<IDMVTXV2_MAXRUID+1; ruid++)
0537 {
0538 if (iValue(ruid)!=-1)
0539 {
0540 os << "RU ID: " << ruid;
0541 os << ", bad_ruchns=" << iValue(ruid,"BAD_RUCHNS");
0542 os << hex << setfill('0');
0543 os << ", lanes_active 0x" << setw(7) << iValue(ruid);
0544 os << dec;
0545 first=true;
0546 os << " (";
0547 for ( int ruchn = 0; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0548 {
0549 if (mask_contains_ruchn(iValue(ruid),ruchn))
0550 {
0551 if (!first)
0552 os << ", ";
0553 os << ruchn;
0554 first = false;
0555 }
0556 }
0557 os << "), inconsistent_bc=" << setw(1) << iValue(ruid,"CHECK_BC");
0558 os << hex << setfill('0');
0559 os << ", lane_stops=0x" << setw(7) << iValue(ruid,"LANE_STOPS");
0560 os << dec;
0561 first=true;
0562 os << " (";
0563 for ( int ruchn = 0; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0564 {
0565 if (mask_contains_ruchn(iValue(ruid,"LANE_STOPS"),ruchn))
0566 {
0567 if (!first)
0568 os << ", ";
0569 os << ruchn;
0570 first = false;
0571 }
0572 }
0573 os << hex << setfill('0');
0574 os << "), lane_timeouts=0x" << setw(7) << iValue(ruid,"LANE_TIMEOUTS");
0575 os << dec;
0576 first=true;
0577 os << " (";
0578 for ( int ruchn = 0; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0579 {
0580 if (mask_contains_ruchn(iValue(ruid,"LANE_TIMEOUTS"),ruchn))
0581 {
0582 if (!first)
0583 os << ", ";
0584 os << ruchn;
0585 first = false;
0586 }
0587 }
0588 os << ")";
0589 os << dec << setfill(' ') << endl;
0590 for ( int ruchn = 0; ruchn < IDMVTXV2_MAXRUCHN+1; ruchn++)
0591 {
0592 if (iValue(ruid,ruchn)!=-1)
0593 {
0594 os << "RU channel " << setw(2) << ruchn;
0595 os << " bad_bytes=" << iValue(ruid,ruchn,"BAD_BYTES") << " excess_bytes=" << iValue(ruid,ruchn,"EXCESS_BYTES") <<" header_found=" << iValue(ruid,ruchn,"HEADER_FOUND") << " trailer_found=" << iValue(ruid,ruchn,"TRAILER_FOUND");
0596 os << " bunchcounter=" << setw(3) << iValue(ruid,ruchn,"BUNCHCOUNTER") << " flags=" << iValue(ruid,ruchn,"READOUT_FLAGS");
0597 os << ", chip ID " << iValue(ruid,ruchn,"CHIP_ID") << ", " << iValue(ruid,ruchn) << " hits: ";
0598 for (int i=0;i<iValue(ruid,ruchn);i++)
0599 {
0600 int hit = iValue(ruid,ruchn,i);
0601 os << "(row " << decode_row(hit) << ", col " << decode_col(hit) << ") ";
0602 }
0603 os << endl;
0604 }
0605 }
0606 }
0607 }
0608 }
0609
0610
0611 void oncsSub_idmvtxv2::gdump(const int i, OSTREAM& out) const
0612 {
0613
0614 int *SubeventData = &SubeventHdr->data;
0615 unsigned int j,l;
0616 identify(out);
0617
0618 int current_offset;
0619 const int DWORDS_PER_WORD = 8;
0620
0621 switch (i)
0622 {
0623 case (EVT_HEXADECIMAL):
0624
0625 current_offset = 0;
0626 while (1)
0627 {
0628
0629 int dwords_remaining = getLength()-SEVTHEADERLENGTH - getPadding() - current_offset;
0630
0631 out << SETW(5) << current_offset << " | ";
0632
0633
0634
0635 print_stuff(out, SubeventData[current_offset+7], 4, 16, (dwords_remaining<=7));
0636 out << " ";
0637
0638
0639 print_stuff(out, SubeventData[current_offset+7], 4, 0, (dwords_remaining<=7));
0640 print_stuff(out, SubeventData[current_offset+6], 8, 0, (dwords_remaining<=6));
0641 print_stuff(out, SubeventData[current_offset+5], 8, 0, (dwords_remaining<=5));
0642 out << " ";
0643
0644
0645 print_stuff(out, SubeventData[current_offset+4], 8, 0, (dwords_remaining<=4));
0646 print_stuff(out, SubeventData[current_offset+3], 8, 0, (dwords_remaining<=3));
0647 print_stuff(out, SubeventData[current_offset+2], 4, 16, (dwords_remaining<=2));
0648 out << " ";
0649
0650
0651 print_stuff(out, SubeventData[current_offset+2], 4, 0, (dwords_remaining<=2));
0652 print_stuff(out, SubeventData[current_offset+1], 8, 0, (dwords_remaining<=1));
0653 print_stuff(out, SubeventData[current_offset+0], 8, 0, (dwords_remaining<=0));
0654 out << " " << std::dec << std::endl << std::setfill(' ');
0655
0656 if (dwords_remaining<8) break;
0657
0658 current_offset += DWORDS_PER_WORD;
0659 }
0660 break;
0661
0662 case (EVT_DECIMAL):
0663 j = 0;
0664 while (1)
0665 {
0666 out << std::dec << std::endl << SETW(5) << j << " | ";
0667
0668 for (l=0;l<6;l++)
0669 {
0670 out << SETW(10) << SubeventData[j++] << " ";
0671 if (j >= SubeventHdr->sub_length-SEVTHEADERLENGTH - SubeventHdr->sub_padding) break;
0672 }
0673 if (j>=SubeventHdr->sub_length-SEVTHEADERLENGTH - SubeventHdr->sub_padding) break;
0674 }
0675 break;
0676
0677 default:
0678 break;
0679 }
0680 out << std::endl;
0681
0682 }
0683
0684 bool oncsSub_idmvtxv2::checkBC(const int ruid)
0685 {
0686 bool first_active = true;
0687 unsigned int first_active_lane;
0688 for (int iruchn = 0; iruchn < IDMVTXV2_MAXRUCHN+1; ++iruchn)
0689 {
0690 if (this->mask_contains_ruchn(_lanes_active[ruid], iruchn))
0691 {
0692 if (first_active)
0693 {
0694 first_active_lane = iruchn;
0695 first_active = false;
0696 }
0697 else if (_bunchcounter[ruid][iruchn] != _bunchcounter[ruid][first_active_lane])
0698 return true;
0699 }
0700 }
0701
0702 return false;
0703 }