]>
Commit | Line | Data |
---|---|---|
e3a2b9c9 | 1 | /************************************************************************** |
2 | * This file is property of and copyright by the ALICE HLT Project * | |
3 | * All rights reserved. * | |
4 | * * | |
5 | * Primary Authors: * | |
6 | * Artur Szostak <artursz@iafrica.com> * | |
7 | * * | |
8 | * Permission to use, copy, modify and distribute this software and its * | |
9 | * documentation strictly for non-commercial purposes is hereby granted * | |
10 | * without fee, provided that the above copyright notice appears in all * | |
11 | * copies and that both the copyright notice and this permission notice * | |
12 | * appear in the supporting documentation. The authors make no claims * | |
13 | * about the suitability of this software for any purpose. It is * | |
14 | * provided "as is" without express or implied warranty. * | |
15 | **************************************************************************/ | |
16 | ||
17 | /* $Id$*/ | |
18 | ||
19 | /// | |
20 | /// \file AliMUONRawStreamTrackerHP.cxx | |
21 | /// \author Artur Szostak <artursz@iafrica.com> | |
22 | /// \date 29-11-2007 | |
23 | /// \brief Implementation of the the high performance decoder AliMUONRawStreamTrackerHP. | |
24 | /// | |
25 | ||
26 | //----------------------------------------------------------------------------- | |
27 | /// \ingroup raw | |
28 | /// \class AliMUONRawStreamTrackerHP | |
29 | /// \brief A high performance stream decoder for muon tracking DDL streams. | |
30 | /// | |
31 | /// This is the raw stream class which interfaces between the high performance | |
32 | /// core decoder and the AliRawReader class. | |
33 | /// To gain the most out of the decoder, the Next() method which returns batches | |
34 | /// of decoded digit / channel information should be used. That is: | |
35 | /// \code | |
36 | /// UInt_t Next(const AliChannelInfo*& channels); | |
37 | /// \endcode | |
38 | /// | |
39 | /// \author Artur Szostak <artursz@iafrica.com> | |
40 | //----------------------------------------------------------------------------- | |
41 | ||
42 | #include "AliMUONRawStreamTrackerHP.h" | |
43 | #include "AliRawReader.h" | |
44 | #include "AliLog.h" | |
45 | #include <cassert> | |
46 | ||
47 | /// \cond CLASSIMP | |
48 | ClassImp(AliMUONRawStreamTrackerHP) | |
49 | /// \endcond | |
50 | ||
51 | ||
52 | AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() : | |
53 | AliMUONVRawStreamTracker(), | |
54 | fDecoder(), | |
55 | fDDL(0), | |
56 | fCurrentChannel(0), | |
57 | fBufferSize(8192), | |
58 | fBuffer(new UChar_t[8192]), | |
59 | fHadError(kFALSE) | |
60 | { | |
61 | /// | |
62 | /// Default constructor. | |
63 | /// | |
64 | } | |
65 | ||
66 | ||
67 | AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) : | |
68 | AliMUONVRawStreamTracker(rawReader), | |
69 | fDecoder(), | |
70 | fDDL(0), | |
71 | fCurrentChannel(0), | |
72 | fBufferSize(8192), | |
73 | fBuffer(new UChar_t[8192]), | |
74 | fHadError(kFALSE) | |
75 | { | |
76 | /// | |
77 | /// Constructor with AliRawReader as argument. | |
78 | /// | |
79 | ||
80 | fDecoder.GetHandler().SetRawStream(this); | |
81 | } | |
82 | ||
83 | ||
84 | AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP() | |
85 | { | |
86 | /// | |
87 | /// Default destructor. | |
88 | /// | |
89 | ||
90 | if (fBuffer != NULL) | |
91 | { | |
92 | delete [] fBuffer; | |
93 | } | |
94 | } | |
95 | ||
96 | ||
97 | void AliMUONRawStreamTrackerHP::First() | |
98 | { | |
99 | /// Initialise or reset the iterator. | |
100 | /// The first DDL will be found and decoded. | |
101 | ||
102 | assert( GetReader() != NULL ); | |
103 | ||
104 | fDDL = 0; | |
105 | NextDDL(); | |
106 | } | |
107 | ||
108 | ||
109 | Bool_t AliMUONRawStreamTrackerHP::NextDDL() | |
110 | { | |
111 | /// Reading the next tracker DDL and decode the payload with the | |
112 | /// high performance decoder. | |
113 | /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise. | |
114 | ||
115 | assert( GetReader() != NULL ); | |
116 | ||
117 | if (IsDone()) return kFALSE; | |
118 | ||
119 | do | |
120 | { | |
121 | GetReader()->Reset(); | |
122 | GetReader()->Select("MUONTRK", fDDL, fDDL); // Select the DDL file to be read. | |
123 | if (GetReader()->ReadHeader()) break; | |
124 | AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1)); | |
125 | fDDL++; | |
126 | } | |
127 | while (fDDL < GetMaxDDL()); | |
128 | ||
129 | AliDebug(3, Form("DDL Number %d\n", fDDL)); | |
130 | ||
131 | Int_t dataSize = GetReader()->GetDataSize(); // in bytes | |
132 | // Check if we have enough buffer space already in fBuffer. If we do then | |
133 | // just continue reading otherwise we need to resize the buffer. | |
134 | if (fBufferSize < dataSize) | |
135 | { | |
136 | if (fBuffer != NULL) | |
137 | { | |
138 | delete [] fBuffer; | |
139 | fBuffer = NULL; | |
140 | fBufferSize = 0; | |
141 | } | |
142 | try | |
143 | { | |
144 | fBuffer = new UChar_t[dataSize]; | |
145 | fBufferSize = dataSize; | |
146 | } | |
147 | catch (const std::bad_alloc&) | |
148 | { | |
149 | AliError("Could not allocate more buffer space. Cannot decode DDL."); | |
150 | return kFALSE; | |
151 | } | |
152 | } | |
153 | ||
154 | if (not GetReader()->ReadNext(fBuffer, dataSize)) | |
155 | { | |
156 | return kFALSE; | |
157 | } | |
158 | ||
159 | #ifndef R__BYTESWAP | |
160 | Swap(fBuffer, dataSize); // Swap needed for mac power pc. | |
161 | #endif | |
162 | ||
163 | bool result = false; | |
164 | try | |
165 | { | |
166 | // Since we might allocate memory inside OnNewBuffer in the event | |
167 | // handler we need to trap any memory allocation exception to be robust. | |
168 | result = fDecoder.Decode(fBuffer, dataSize); | |
169 | } | |
170 | catch (const std::bad_alloc&) | |
171 | { | |
172 | AliError("Could not allocate more buffer space. Cannot decode DDL."); | |
173 | return kFALSE; | |
174 | } | |
175 | ||
176 | fCurrentChannel = 0; | |
177 | fDDL++; // Remember to increment index to next DDL. | |
178 | return result; | |
179 | } | |
180 | ||
181 | ||
182 | Bool_t AliMUONRawStreamTrackerHP::IsDone() const | |
183 | { | |
184 | /// Indicates whether the iteration is finished or not. | |
185 | /// \return kTRUE if we already read all the digits and kFALSE if not. | |
186 | ||
187 | return fDDL == GetMaxDDL(); | |
188 | } | |
189 | ||
190 | ||
191 | Bool_t AliMUONRawStreamTrackerHP::Next( | |
192 | Int_t& busPatchId, UShort_t& manuId, UChar_t& manuChannel, | |
193 | UShort_t& adc | |
194 | ) | |
195 | { | |
196 | /// Advance one step in the iteration. Returns false if finished. | |
197 | /// [out] \param busPatchId This is filled with the bus patch ID of the digit. | |
198 | /// [out] \param manuId This is filled with the MANU ID of the digit. | |
199 | /// [out] \param manuChannel This is filled with the MANU channel ID of the digit. | |
200 | /// [out] \param adc This is filled with the ADC signal value of the digit. | |
201 | /// \return kTRUE if we read another digit and kFALSE if we have read all the | |
202 | /// digits already, i.e. at the end of the iteration. | |
203 | ||
204 | if (fCurrentChannel < fDecoder.GetHandler().ChannelCount()) | |
205 | { | |
206 | const AliChannelInfo& channel = fDecoder.GetHandler().Channels()[fCurrentChannel]; | |
207 | busPatchId = channel.BusPatchId(); | |
208 | manuId = channel.ManuId(); | |
209 | manuChannel = channel.ChannelId(); | |
210 | adc = channel.ADC(); | |
211 | fCurrentChannel++; | |
212 | return kTRUE; | |
213 | } | |
214 | else | |
215 | { | |
216 | if (NextDDL()) | |
217 | { | |
218 | if (fCurrentChannel < fDecoder.GetHandler().ChannelCount()) | |
219 | { | |
220 | const AliChannelInfo& channel = fDecoder.GetHandler().Channels()[fCurrentChannel]; | |
221 | busPatchId = channel.BusPatchId(); | |
222 | manuId = channel.ManuId(); | |
223 | manuChannel = channel.ChannelId(); | |
224 | adc = channel.ADC(); | |
225 | fCurrentChannel++; | |
226 | return kTRUE; | |
227 | } | |
228 | } | |
229 | } | |
230 | return kFALSE; | |
231 | } | |
232 | ||
233 | ||
234 | UInt_t AliMUONRawStreamTrackerHP::Next(const AliChannelInfo*& channels) | |
235 | { | |
236 | /// Returns the next batch of decoded channel data. | |
237 | /// [out] \param channels This is filled with a pointer to an array of | |
238 | /// channels / digits that were decoded. This method does not | |
239 | /// modify 'channels' if zero is returned. | |
240 | /// \return The number of elements in the array pointed to by 'channels' | |
241 | /// is returned. If zero is returned then there are no more channels to read. | |
242 | ||
243 | // Check if we are already at the end of the channels array. If so then we | |
244 | // need to fetch the next non empty DDL. | |
245 | if (fCurrentChannel >= fDecoder.GetHandler().ChannelCount()) | |
246 | { | |
247 | do | |
248 | { | |
249 | if (not NextDDL()) return 0; | |
250 | } | |
251 | // Make sure to keep going even for empty DDL payloads: | |
252 | while (fDecoder.GetHandler().ChannelCount() == 0); | |
253 | } | |
254 | channels = fDecoder.GetHandler().Channels() + fCurrentChannel; | |
255 | return fDecoder.GetHandler().ChannelCount() - fCurrentChannel; | |
256 | } | |
257 | ||
258 | /////////////////////////////////////////////////////////////////////////////// | |
259 | ||
260 | AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() : | |
261 | fBusPatchId(0), | |
262 | fChannelCount(0), | |
263 | fMaxChannels(8192), | |
264 | fChannelBuffer(new AliChannelInfo[8192]), | |
265 | fRawStream(NULL), | |
266 | fBufferStart(NULL) | |
267 | { | |
268 | /// Default constructor initialises the internal buffer to store decoded | |
269 | /// channel / digit data to 8192 elements. | |
270 | /// This array will grow dynamically if needed. | |
271 | } | |
272 | ||
273 | ||
274 | AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler() | |
275 | { | |
276 | /// Default destructor cleans up the allocated memory. | |
277 | ||
278 | if (fChannelBuffer != NULL) | |
279 | { | |
280 | delete [] fChannelBuffer; | |
281 | } | |
282 | } | |
283 | ||
284 | void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer( | |
285 | const void* buffer, UInt_t bufferSize | |
286 | ) | |
287 | { | |
288 | /// This is called by the high performance decoder when a new DDL payload | |
289 | /// is about to be decoded. | |
290 | /// \param buffer The pointer to the buffer storing the DDL payload. | |
291 | /// \param bufferSize The size of the buffer in bytes. | |
292 | ||
293 | // remember the start of the buffer to be used in OnError. | |
294 | fBufferStart = buffer; | |
295 | ||
296 | // Reset the number of channels found. | |
297 | fChannelCount = 0; | |
298 | ||
299 | // Check if we will have enough space in the fChannelBuffer array. | |
300 | // If we do not then we need to resize the array. | |
301 | // bufferSize / sizeof(UInt_t) will be a safe over estimate of the | |
302 | // number of channels that we will find. | |
303 | UInt_t maxPossibleChannels = bufferSize / sizeof(UInt_t); | |
304 | if (maxPossibleChannels > fMaxChannels) | |
305 | { | |
306 | if (fChannelBuffer != NULL) | |
307 | { | |
308 | delete [] fChannelBuffer; | |
309 | fChannelBuffer = NULL; | |
310 | fMaxChannels = 0; | |
311 | } | |
312 | fChannelBuffer = new AliChannelInfo[maxPossibleChannels]; | |
313 | fMaxChannels = maxPossibleChannels; | |
314 | } | |
315 | } | |
316 | ||
317 | ||
318 | void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBusPatch( | |
319 | const AliMUONBusPatchHeaderStruct* header, const void* /*data*/ | |
320 | ) | |
321 | { | |
322 | /// This is called by the high performance decoder when a new bus patch | |
323 | /// is found within the DDL payload. All we do is remember the bus patch ID. | |
324 | /// \param header The bus patch header structure. | |
325 | /// \param data The bus patch data (not used in this method). | |
326 | ||
327 | fBusPatchId = header->fBusPatchId; | |
328 | } | |
329 | ||
330 | ||
331 | void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnData(UInt_t data) | |
332 | { | |
333 | /// This is called by the high performance decoder when a new bus patch | |
334 | /// is found within the DDL payload. All we do is remember the bus patch ID. | |
335 | /// \param data The bus patch data (not used in this method). | |
336 | ||
337 | assert( fChannelCount < fMaxChannels ); | |
338 | ||
339 | UShort_t manuId; UChar_t channelId; UShort_t adc; | |
340 | UnpackADC(data, manuId, channelId, adc); | |
341 | fChannelBuffer[fChannelCount] = AliChannelInfo(fBusPatchId, manuId, channelId, adc); | |
342 | fChannelCount++; | |
343 | } | |
344 | ||
345 | ||
346 | void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError( | |
347 | ErrorCode error, const void* location | |
348 | ) | |
349 | { | |
350 | /// This is called by the high performance decoder when a error occurs | |
351 | /// when trying to decode the DDL payload. This indicates corruption in | |
352 | /// the data. This method converts the error code to a descriptive message | |
353 | /// and log this with the raw reader. | |
354 | /// \param error The error code indicating the problem. | |
355 | /// \param location A pointer to the location within the DDL payload buffer | |
356 | /// being decoded where the problem with the data was found. | |
357 | ||
358 | assert( fRawStream != NULL ); | |
359 | assert( fRawStream->GetReader() != NULL ); | |
360 | ||
361 | const char* msg = ErrorCodeToMessage(error); | |
362 | unsigned long pos = (unsigned long)location - (unsigned long)fBufferStart; | |
363 | ||
364 | switch (error) | |
365 | { | |
366 | case kBadPaddingWord: | |
367 | case kParityError: | |
368 | fRawStream->GetReader()->AddMinorErrorLog(error, Form("%s [At byte: %d]", msg, pos)); | |
369 | break; | |
370 | default: | |
371 | fRawStream->GetReader()->AddMajorErrorLog(error, Form("%s [At byte: %d]", msg, pos)); | |
372 | break; | |
373 | } | |
374 | } | |
375 |