1+ // Copyright CERN and copyright holders of ALICE O2. This software is
2+ // distributed under the terms of the GNU General Public License v3 (GPL
3+ // Version 3), copied verbatim in the file "COPYING".
4+ //
5+ // See http://alice-o2.web.cern.ch/license for full licensing information.
6+ //
7+ // In applying this license CERN does not waive the privileges and immunities
8+ // granted to it by virtue of its status as an Intergovernmental Organization
9+ // or submit itself to any jurisdiction.
10+
11+ #include < gsl/span>
12+ #include < TSystem.h>
13+ #include " DataFormatsEMCAL/Constants.h"
14+ #include " EMCALBase/Geometry.h"
15+ #include " EMCALSimulation/RawWriter.h"
16+ #include " Headers/RAWDataHeader.h"
17+
18+ using namespace o2 ::emcal;
19+
20+ void RawWriter::setTriggerRecords (std::vector<o2::emcal::TriggerRecord>* triggers)
21+ {
22+ mTriggers = triggers;
23+ mCurrentTrigger = triggers->begin ();
24+ }
25+
26+ void RawWriter::init ()
27+ {
28+ mOutputStream .open ();
29+
30+ // initialize mappers
31+ std::array<char , 4 > sides = {{' A' , ' C' }};
32+ for (auto iside = 0 ; iside < sides.size (); iside++) {
33+ for (auto isru = 0 ; isru < 20 ; isru++) {
34+ mMappers [iside * 2 + isru].setMapping (Form (" %s/share/Detectors/EMC/file/RCU%d%c.data" , gSystem ->Getenv (" O2_ROOT" ), isru, sides[iside]));
35+ }
36+ }
37+
38+ // initialize containers for SRU
39+ for (auto isru = 0 ; isru < 40 ; isru++) {
40+ SRUDigitContainer srucont;
41+ srucont.mSRUid = isru;
42+ mSRUdata .push_back (srucont);
43+ }
44+ }
45+
46+ void RawWriter::processNextTrigger ()
47+ {
48+ for (auto srucont : mSRUdata )
49+ srucont.mChannels .clear ();
50+ std::vector<o2::emcal::Digit*>* bunchDigits;
51+ int lasttower = -1 ;
52+ for (auto & dig : gsl::span (&mDigits ->data ()[mCurrentTrigger ->getFirstEntry ()], mCurrentTrigger ->getNumberOfObjects ())) {
53+ auto tower = dig.getTower ();
54+ if (tower != lasttower) {
55+ lasttower = tower;
56+ auto onlineindices = getOnlineID (tower);
57+ int sruID = std::get<0 >(onlineindices);
58+ auto towerdata = mSRUdata [sruID].mChannels .find (tower);
59+ if (towerdata == mSRUdata [sruID].mChannels .end ()) {
60+ mSRUdata [sruID].mChannels [tower] = {std::get<1 >(onlineindices), std::get<2 >(onlineindices), std::vector<o2::emcal::Digit*>(mNADCSamples )};
61+ bunchDigits = &(mSRUdata [sruID].mChannels [tower].mDigits );
62+ memset (bunchDigits->data (), 0 , sizeof (o2::emcal::Digit*) * mNADCSamples );
63+ } else {
64+ bunchDigits = &(towerdata->second .mDigits );
65+ }
66+ (*bunchDigits)[int (dig.getTimeStamp ())] = &dig;
67+ }
68+ }
69+
70+ // Create and fill DMA pages for each channel
71+ std::vector<char > payload;
72+ for (auto srucont : mSRUdata ) {
73+ o2::header::RAWDataHeaderV4 rawheader;
74+ rawheader.triggerBC = mCurrentTrigger ->getBCData ().bc ;
75+ rawheader.triggerOrbit = mCurrentTrigger ->getBCData ().orbit ;
76+ // @TODO: Set trigger type
77+ rawheader.feeId = srucont.mSRUid ;
78+
79+ for (const auto & [tower, channel] : srucont.mChannels ) {
80+ // Find out hardware address of the channel
81+ auto hwaddress = mMappers [srucont.mSRUid ].getHardwareAddress (channel.mRow , channel.mCol , ChannelType_t::HIGH_GAIN ); // @TODO distinguish between high- and low-gain cells
82+
83+ std::vector<int > rawbunches;
84+ for (auto & bunch : findBunches (channel.mDigits )) {
85+ rawbunches.push_back (bunch.mStarttime );
86+ rawbunches.push_back (bunch.mADCs .size ());
87+ for (auto adc : bunch.mADCs ) {
88+ rawbunches.push_back (adc);
89+ }
90+ }
91+ auto encodedbunches = encodeBunchData (rawbunches);
92+ auto chanhead = createChannelHeader (hwaddress, encodedbunches.size () * 3 - 2 , false ); // / bad channel status eventually to be added later
93+ char * chanheadwords = reinterpret_cast <char *>(&chanhead);
94+ for (int iword = 0 ; iword < sizeof (ChannelHeader) / sizeof (char ); iword++) {
95+ payload.emplace_back (chanheadwords[iword]);
96+ }
97+ char * channelwords = reinterpret_cast <char *>(encodedbunches.data ());
98+ for (auto iword = 0 ; iword < encodedbunches.size () * sizeof (int ) / sizeof (char ); iword++) {
99+ payload.emplace_back (channelwords[iword]);
100+ }
101+ }
102+
103+ // Create RCU trailer
104+ auto trailerwords = createRCUTrailer ();
105+ for (auto word : trailerwords)
106+ payload.emplace_back (word);
107+
108+ // write DMA page to stream
109+ mOutputStream .writeData (rawheader, payload);
110+ }
111+ }
112+
113+ std::vector<AltroBunch> RawWriter::findBunches (const std::vector<o2::emcal::Digit*>& channelDigits)
114+ {
115+ std::vector<AltroBunch> result;
116+ AltroBunch* currentBunch = nullptr ;
117+ int starttime = 0 ;
118+ for (auto ien = channelDigits.size () - 1 ;; ien--) {
119+ auto dig = channelDigits[ien];
120+ if (!dig) {
121+ starttime++;
122+ continue ;
123+ }
124+ int adc = dig->getEnergy () / constants::EMCAL_ADCENERGY ; // / conversion Energy <-> ADC := 16 MeV/ADC
125+ if (adc < mPedestal ) {
126+ // Stop bunch
127+ currentBunch = nullptr ;
128+ starttime++;
129+ continue ;
130+ }
131+ if (!currentBunch) {
132+ // start new bunch
133+ AltroBunch bunch;
134+ bunch.mStarttime = starttime;
135+ result.push_back (bunch);
136+ currentBunch = &(result.back ());
137+ }
138+ currentBunch->mADCs .emplace_back (adc);
139+ starttime++;
140+ }
141+ return result;
142+ }
143+
144+ std::tuple<int , int , int > RawWriter::getOnlineID (int towerID)
145+ {
146+ auto cellindex = mGeometry ->GetCellIndex (towerID);
147+ auto supermoduleID = std::get<0 >(cellindex);
148+ auto etaphi = mGeometry ->GetCellPhiEtaIndexInSModule (supermoduleID, std::get<1 >(cellindex), std::get<2 >(cellindex), std::get<3 >(cellindex));
149+ auto etaphishift = mGeometry ->ShiftOfflineToOnlineCellIndexes (supermoduleID, std::get<0 >(etaphi), std::get<1 >(etaphi));
150+ int row = std::get<0 >(etaphishift), col = std::get<1 >(etaphishift);
151+
152+ int sruID = -1 ;
153+ if (0 <= row && row < 8 )
154+ sruID = 0 ; // first cable row
155+ else if (8 <= row && row < 16 && 0 <= col && col < 24 )
156+ sruID = 0 ; // first half;
157+ else if (8 <= row && row < 16 && 24 <= col && col < 48 )
158+ sruID = 1 ; // second half;
159+ else if (16 <= row && row < 24 )
160+ sruID = 1 ; // third cable row
161+ if (supermoduleID % 2 == 1 )
162+ sruID = 1 - sruID; // swap for odd=C side, to allow us to cable both sides the same
163+
164+ return std::make_tuple (sruID, row, col);
165+ }
166+
167+ std::vector<int > RawWriter::encodeBunchData (const std::vector<int >& data)
168+ {
169+ std::vector<int > encoded;
170+ CaloBunchWord currentword;
171+ int wordnumber = 0 ;
172+ for (auto adc : data) {
173+ switch (wordnumber) {
174+ case 0 :
175+ currentword.mWord0 = adc;
176+ break ;
177+ case 1 :
178+ currentword.mWord1 = adc;
179+ break ;
180+ case 2 :
181+ currentword.mWord2 = adc;
182+ break ;
183+ };
184+ if (wordnumber == 2 ) {
185+ // start new word;
186+ encoded.push_back (currentword.mDataWord );
187+ currentword.mDataWord = 0 ;
188+ wordnumber = 0 ;
189+ } else {
190+ wordnumber++;
191+ }
192+ }
193+ return encoded;
194+ }
195+
196+ ChannelHeader RawWriter::createChannelHeader (int hardwareAddress, int payloadSize, bool isBadChannel)
197+ {
198+ ChannelHeader header;
199+ header.mHardwareAddress = hardwareAddress;
200+ header.mPayloadSize = payloadSize;
201+ header.mBadChannel = isBadChannel ? 1 : 0 ;
202+ return header;
203+ }
204+
205+ std::vector<char > RawWriter::createRCUTrailer ()
206+ {
207+ std::vector<char > trailerwords;
208+ return trailerwords;
209+ }
0 commit comments