Adding the new high performance decoder.
[u/mrichter/AliRoot.git] / MUON / AliMUONRawStreamTrackerHP.cxx
CommitLineData
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
48ClassImp(AliMUONRawStreamTrackerHP)
49/// \endcond
50
51
52AliMUONRawStreamTrackerHP::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
67AliMUONRawStreamTrackerHP::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
84AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
85{
86 ///
87 /// Default destructor.
88 ///
89
90 if (fBuffer != NULL)
91 {
92 delete [] fBuffer;
93 }
94}
95
96
97void 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
109Bool_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
182Bool_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
191Bool_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
234UInt_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
260AliMUONRawStreamTrackerHP::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
274AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
275{
276 /// Default destructor cleans up the allocated memory.
277
278 if (fChannelBuffer != NULL)
279 {
280 delete [] fChannelBuffer;
281 }
282}
283
284void 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
318void 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
331void 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
346void 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