12 #include "art/Framework/Core/EDProducer.h"
13 #include "art/Framework/Core/ModuleMacros.h"
14 #include "art/Framework/Principal/Event.h"
15 #include "art/Framework/Principal/Handle.h"
16 #include "art/Framework/Principal/Run.h"
17 #include "art/Framework/Principal/SubRun.h"
18 #include "canvas/Utilities/InputTag.h"
19 #include "fhiclcpp/ParameterSet.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "canvas/Utilities/Exception.h"
22 #include "canvas/Persistency/Common/Ptr.h"
23 #include "canvas/Persistency/Common/PtrVector.h"
24 #include "canvas/Persistency/Common/FindManyP.h"
25 #include "art/Persistency/Common/PtrMaker.h"
27 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTFragment.hh"
28 #include "artdaq-core/Data/Fragment.hh"
29 #include "artdaq-core/Data/ContainerFragment.hh"
30 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
31 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTTranslator.hh"
40 #include "art_root_io/TFileService.h"
41 #include "art_root_io/TFileDirectory.h"
81 bool IsSideCRT(icarus::crt::BernCRTTranslator & hit);
99 "FragmentTagPatterns",
100 std::vector<std::string>{
"daq:(Container)?BERNCRT.*" }
103 , fDropRawDataAfterUse{
p.get<
bool>(
"DropRawDataAfterUse",
true) }
105 fChannelMap = art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get();
106 produces< std::vector<icarus::crt::CRTData> >();
108 mayConsumeMany<artdaq::Fragments>();
111 std::vector<std::vector<int32_t> > delays =
p.get<std::vector<std::vector<int32_t> > >(
"FEB_delay_side");
112 for(
auto & feb : delays) {
113 int32_t & mac = feb[0];
114 int32_t & d = feb[1];
115 FEB_delay_side[mac] = d;
120 std::vector<std::vector<int32_t> > delays =
p.get<std::vector<std::vector<int32_t> > >(
"FEB_delay_top");
121 for(
auto & feb : delays) {
122 int32_t & mac = feb[0];
123 int32_t & d = feb[1];
133 return (hit.fragment_ID & 0x3100) == 0x3100;
136 if(!hit.IsReference_TS0() && !hit.IsReference_TS1()) {
140 delay = FEB_delay_side.at(hit.mac5);
146 hit.ts0 %= 1
'000'000
'000;
147 if(hit.ts0 < 0) hit.ts0 += 1000'000
'000; //just in case the cable offset is negative (should be positive normally)
149 } catch(const std::out_of_range & e) {
150 TLOG(TLVL_ERROR)<<"CRT MAC "<<(int)(hit.mac5)<<" not found in the FEB_delay array!!! Please update FEB_delay FHiCL file";
151 throw cet::exception("DecoderICARUSCRT")
152 << "CRT MAC "<<(int)(hit.mac5)<<" not found in the FEB_delay array!!! Please update FEB_delay FHiCL file\n";
157 uint64_t crt::DecoderICARUSCRT::CalculateTimestamp(icarus::crt::BernCRTTranslator& hit) {
162 int32_t ts0 = hit.ts0; //must be signed int
164 uint64_t mean_poll_time = hit.last_poll_start/2 + hit.this_poll_end/2;
165 int mean_poll_time_ns = mean_poll_time % (1000'000
'000);
167 return mean_poll_time - mean_poll_time_ns + ts0
168 + (ts0 - mean_poll_time_ns < -500'000
'000) * 1000'000
'000
169 - (ts0 - mean_poll_time_ns > 500'000
'000) * 1000'000
'000;
172 void crt::DecoderICARUSCRT::produce(art::Event& evt)
175 util::LocalArtHandleTrackerManager dataCacheRemover
176 (evt, fDropRawDataAfterUse);
178 std::vector<art::Handle<artdaq::Fragments>> fragmentHandles
179 = evt.getMany<artdaq::Fragments>(fInputTagPatterns);
182 mf::LogDebug log { "DecoderICARUSCRT" };
183 log << "Found " << fragmentHandles.size()
184 << " CRT fragment data product candidates:";
185 for (auto const& handle: fragmentHandles)
186 log << "\n - '" << handle.provenance()->inputTag().encode() << '"';
189 std::vector<icarus::crt::BernCRTTranslator> hit_vector;
191 for (auto const& handle : fragmentHandles) {
192 if (!handle.isValid()) continue;
194 dataCacheRemover.registerHandle(handle);
196 if (handle->empty()) continue;
198 auto this_hit_vector = icarus::crt::BernCRTTranslator::getCRTData(*handle);
200 hit_vector.insert(hit_vector.end(),this_hit_vector.begin(),this_hit_vector.end());
206 unsigned int destMac5;
207 unsigned int firstSourceChannel;
208 unsigned int lastSourceChannel;
209 unsigned int firstDestChannel;
210 unsigned int lastDestChannel;
212 int direction; // +1 or -1
216 // vector: Mac5 -> its CRT data
217 std::vector<icarus::crt::CRTData> allCRTdata;
219 for (auto & hit : hit_vector){
220 CorrectForCableDelay(hit); //add PPS cable length
223 std::array<Recipe_t, 3U> allRecipes;
228 if (!((hit.mac5 >= 88 && hit.mac5 <= 91)
229 || hit.mac5 == 96 || hit.mac5 == 97
230 || hit.mac5 == 1 || hit.mac5 == 3
231 || hit.mac5 == 6 || hit.mac5 == 7)) { // look for FEB those are not between 88 to 91
233 int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
238 // first block of 10 channels from source
240 recipe.destMac5 = destMac5;
242 recipe.firstSourceChannel = 2;
243 recipe.lastSourceChannel = 11;
245 recipe.firstDestChannel = 0;
246 recipe.lastDestChannel = 9;
247 recipe.direction = +1;
248 allRecipes[0] = recipe;
251 // second block of 10 channels from source
253 recipe.destMac5 = destMac5;
254 recipe.firstSourceChannel = 12;
255 recipe.lastSourceChannel = 21;
257 recipe.firstDestChannel = 10;
258 recipe.lastDestChannel = 19;
259 recipe.direction = +1;
260 allRecipes[1] = recipe;
263 // third block of 10 channels from source
265 recipe.destMac5 = destMac5;
266 recipe.firstSourceChannel = 22;
267 recipe.lastSourceChannel = 31;
269 recipe.firstDestChannel = 20;
270 recipe.lastDestChannel = 29;
271 recipe.direction = +1;
272 allRecipes[2] = recipe;
275 } // "normal assignment"
276 else if (hit.mac5 == 97) { // south wall - east side top horizontal module channels are reversed
278 int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
283 // first block of 10 channels from source
285 recipe.destMac5 = destMac5;
287 recipe.firstSourceChannel = 2;
288 recipe.lastSourceChannel = 11;
290 recipe.firstDestChannel = 0;
291 recipe.lastDestChannel = 9;
292 recipe.direction = +1;
293 allRecipes[0] = recipe;
296 // second block of 10 channels from source
298 recipe.destMac5 = destMac5;
299 recipe.firstSourceChannel = 12;
300 recipe.lastSourceChannel = 21;
302 recipe.firstDestChannel = 10;
303 recipe.lastDestChannel = 19;
304 recipe.direction = +1;
305 allRecipes[1] = recipe;
308 // third block of 10 channels from source
310 recipe.destMac5 = destMac5;
311 recipe.firstSourceChannel = 22;
312 recipe.lastSourceChannel = 31;
314 recipe.firstDestChannel = 29;
315 recipe.lastDestChannel = 20;
316 recipe.direction = -1;
317 allRecipes[2] = recipe;
321 else if (hit.mac5 == 1 || hit.mac5 == 3 ||
322 hit.mac5 == 6 || hit.mac5 == 7 ||
323 hit.mac5 == 96) { // north wall inner layer and south wall west side top three horizontal layer orientation is reversed
325 int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
330 // first block of 10 channels from source
332 recipe.destMac5 = destMac5;
334 recipe.firstSourceChannel = 2;
335 recipe.lastSourceChannel = 11;
337 recipe.firstDestChannel = 9;
338 recipe.lastDestChannel = 0;
339 recipe.direction = -1;
340 allRecipes[0] = recipe;
343 // second block of 10 channels from source
345 recipe.destMac5 = destMac5;
346 recipe.firstSourceChannel = 12;
347 recipe.lastSourceChannel = 21;
349 recipe.firstDestChannel = 19;
350 recipe.lastDestChannel = 10;
351 recipe.direction = -1;
352 allRecipes[1] = recipe;
355 // third block of 10 channels from source: special mapping
357 recipe.destMac5 = destMac5;
358 recipe.firstSourceChannel = 22;
359 recipe.lastSourceChannel = 31;
361 recipe.firstDestChannel = 29;
362 recipe.lastDestChannel = 20;
363 recipe.direction = -1;
364 allRecipes[2] = recipe;
367 else if (hit.mac5 == 88) {
369 int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
374 // first block of 10 channels from source
376 recipe.destMac5 = 79;
378 recipe.firstSourceChannel = 2;
379 recipe.lastSourceChannel = 11;
381 recipe.firstDestChannel = 29;
382 recipe.lastDestChannel = 20;
383 recipe.direction = -1;
384 allRecipes[0] = recipe;
387 // second block of 10 channels from source
389 recipe.destMac5 = destMac5;
390 recipe.firstSourceChannel = 12;
391 recipe.lastSourceChannel = 21;
393 recipe.firstDestChannel = 10;
394 recipe.lastDestChannel = 19;
395 recipe.direction = +1;
396 allRecipes[1] = recipe;
399 // third block of 10 channels from source: special mapping
401 recipe.destMac5 = destMac5;
402 recipe.firstSourceChannel = 22;
403 recipe.lastSourceChannel = 31;
405 recipe.firstDestChannel = 0;
406 recipe.lastDestChannel = 9;
407 recipe.direction = +1;
408 allRecipes[2] = recipe;
411 else if ((hit.mac5 >= 89) && (hit.mac5 <= 91)) {
413 int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
418 // first block of 10 channels from source
420 recipe.destMac5 = destMac5;
422 recipe.firstSourceChannel = 2;
423 recipe.lastSourceChannel = 11;
425 recipe.firstDestChannel = 19;
426 recipe.lastDestChannel = 10;
427 recipe.direction = -1;
428 allRecipes[0] = recipe;
431 // second block of 10 channels from source
434 recipe.destMac5 = destMac5;
435 recipe.firstSourceChannel = 12;
436 recipe.lastSourceChannel = 21;
438 recipe.firstDestChannel = 9;
439 recipe.lastDestChannel = 0;
440 recipe.direction = -1;
441 allRecipes[1] = recipe;
444 // third block of 10 channels from source: special mapping
446 recipe.destMac5 = destMac5 - 1;
447 recipe.firstSourceChannel = 22;
448 recipe.lastSourceChannel = 31;
450 recipe.firstDestChannel = 29;
451 recipe.lastDestChannel = 20;
452 recipe.direction = -1;
454 allRecipes[2] = recipe;
461 for (Recipe_t const& recipe: allRecipes) {
462 if (recipe.firstSourceChannel == recipe.lastSourceChannel) continue;
464 icarus::crt::CRTData data;
465 data.fMac5 = recipe.destMac5;
466 data.fTs0 = CalculateTimestamp(hit);
468 data.fFlags = hit.flags;
469 data.fThisPollStart = hit.this_poll_start;
470 data.fLastPollStart = hit.last_poll_start;
471 data.fHitsInPoll = hit.hits_in_poll;
472 data.fCoinc = hit.coinc;
473 data.fLastAcceptedTimestamp = hit.last_accepted_timestamp;
474 data.fLostHits = hit.lost_hits;
476 unsigned destCh = recipe.firstDestChannel;
477 for (unsigned srcCh = recipe.firstSourceChannel; srcCh <= recipe.lastSourceChannel; ++srcCh) {
479 data.fAdc[destCh] = hit.adc[srcCh];
480 destCh += recipe.direction; // increase or decrease the source
483 allCRTdata.push_back(data);
486 else { //not side CRT, therefore top CRT
487 //this code needs review by the TOP CRT group!!!
488 icarus::crt::CRTData data;
489 data.fMac5 = fChannelMap->gettopSimMacAddress(hit.mac5);
490 data.fTs0 = CalculateTimestamp(hit);
492 data.fFlags = hit.flags;
493 data.fThisPollStart = hit.this_poll_start;
494 data.fLastPollStart = hit.last_poll_start;
495 data.fHitsInPoll = hit.hits_in_poll;
496 data.fCoinc = hit.coinc;
497 data.fLastAcceptedTimestamp = hit.last_accepted_timestamp;
498 data.fLostHits = hit.lost_hits;
500 memcpy(data.fAdc, hit.adc, 32*sizeof(hit.adc[0]));
502 allCRTdata.push_back(data);
505 } // loop over all hits in an event
507 // move the data which is actually present in the final data product
508 auto crtdata = std::make_unique<std::vector<icarus::crt::CRTData>>();
509 for (icarus::crt::CRTData& crtDataElem: allCRTdata) {
510 if (crtDataElem.fMac5 == 0) continue; // not a valid Mac5, data is not present
511 crtdata->push_back(std::move(crtDataElem));
514 evt.put(std::move(crtdata));
518 DEFINE_ART_MODULE(crt::DecoderICARUSCRT)
Matches products by regex on process, module label and instance name.
std::map< uint8_t, int32_t > FEB_delay_top
This provides an art tool interface definition for tools which "decode" artdaq fragments into LArSoft...
DecoderICARUSCRT & operator=(DecoderICARUSCRT const &)=delete
static std::vector< ProductRegex > makePatterns(SpecColl const &specs)
Parses a sequence of input tags to create data product patterns.
bool fDropRawDataAfterUse
Clear fragment data product cache after use.
std::map< uint8_t, int32_t > FEB_delay_side
Helpers to pass to art::Event::getMany() and similar.
void produce(art::Event &evt) override
void CorrectForCableDelay(icarus::crt::BernCRTTranslator &hit)
bool IsSideCRT(icarus::crt::BernCRTTranslator &hit)
util::RegexDataProductSelector const fInputTagPatterns
Selector object detecting all the suitable data products.
DecoderICARUSCRT(fhicl::ParameterSet const &p)
uint64_t CalculateTimestamp(icarus::crt::BernCRTTranslator &hit)
BEGIN_PROLOG FEB_delay_top
const icarusDB::IICARUSChannelMap * fChannelMap
Tracks handles for cache deletion.