]>
Commit | Line | Data |
---|---|---|
e3a2b9c9 | 1 | #ifndef ALIMUONTRACKERDDLDECODEREVENTHANDLER_H |
2 | #define ALIMUONTRACKERDDLDECODEREVENTHANDLER_H | |
3 | /************************************************************************** | |
4 | * This file is property of and copyright by the ALICE HLT Project * | |
5 | * All rights reserved. * | |
6 | * * | |
7 | * Primary Authors: * | |
8 | * Artur Szostak <artursz@iafrica.com> * | |
9 | * * | |
10 | * Permission to use, copy, modify and distribute this software and its * | |
11 | * documentation strictly for non-commercial purposes is hereby granted * | |
12 | * without fee, provided that the above copyright notice appears in all * | |
13 | * copies and that both the copyright notice and this permission notice * | |
14 | * appear in the supporting documentation. The authors make no claims * | |
15 | * about the suitability of this software for any purpose. It is * | |
16 | * provided "as is" without express or implied warranty. * | |
17 | **************************************************************************/ | |
18 | ||
19 | /* $Id$ */ | |
20 | ||
21 | /// | |
22 | /// \file AliMUONTrackerDDLDecoderEventHandler.h | |
23 | /// \author Artur Szostak <artursz@iafrica.com> | |
24 | /// \date 28-11-2007 | |
25 | /// \brief Implementation of a high performance DDL decoder event handler | |
26 | /// for the muon tracking stations. | |
27 | /// | |
28 | ||
29 | #include <cassert> | |
30 | #include <ostream> | |
31 | #include <Rtypes.h> | |
32 | ||
33 | ||
34 | // We use C binding for the structures because C is more uniform with its application | |
35 | // binary interface (ABI) between compilers. | |
36 | extern "C" | |
37 | { | |
38 | ||
39 | // The following structures are the headers found in the DDL payload from the | |
40 | // muon tracking chambers. The specification is defined in ALICE-INT-2005-012 | |
41 | // (https://edms.cern.ch/file/591904/1/ALICE-INT-2005-012.pdf) | |
42 | ||
43 | /// The block header structure of the Tracker DDL payload. | |
44 | struct AliMUONBlockHeaderStruct | |
45 | { | |
46 | UInt_t fDataKey; ///< Data key word for CRT header | |
47 | UInt_t fTotalLength; ///< total length of block structure (w/o padding word) | |
48 | UInt_t fLength; ///< length of raw data | |
49 | UInt_t fDSPId; ///< DSP id | |
50 | UInt_t fL0Trigger; ///< L0 trigger word | |
51 | UInt_t fMiniEventId; ///< Bunch Crossing for mini-event id (see TDR chapter 8) | |
52 | UInt_t fEventId1; ///< Event Id in bunch crossing | |
53 | UInt_t fEventId2; ///< Event Id in orbit number | |
54 | }; | |
55 | ||
56 | /// The DSP header structure of the Tracker DDL payload. | |
57 | struct AliMUONDSPHeaderStruct | |
58 | { | |
59 | UInt_t fDataKey; ///< Data key word for FRT header | |
60 | UInt_t fTotalLength; ///< total length of block structure | |
61 | UInt_t fLength; ///< length of raw data | |
62 | UInt_t fDSPId; ///< DSP id | |
63 | UInt_t fBlkL1ATrigger; ///< L1 accept in Block Structure (CRT) | |
64 | UInt_t fMiniEventId; ///< Mini Event Id in bunch crossing | |
65 | UInt_t fL1ATrigger; ///< Number of L1 accept in DSP Structure (FRT) | |
66 | UInt_t fL1RTrigger; ///< Number of L1 reject in DSP Structure (FRT) | |
67 | UInt_t fPaddingWord; ///< padding dummy word for 64 bits transfer | |
68 | UInt_t fErrorWord; ///< Error word | |
69 | }; | |
70 | ||
71 | /// The bus patch header structure of the Tracker DDL payload. | |
72 | struct AliMUONBusPatchHeaderStruct | |
73 | { | |
74 | UInt_t fDataKey; ///< Data key word for bus patch header | |
75 | UInt_t fTotalLength; ///< total length of bus patch structure | |
76 | UInt_t fLength; ///< length of raw data | |
77 | UInt_t fBusPatchId; ///< bus patch id | |
78 | }; | |
79 | ||
80 | } // extern "C" | |
81 | ||
82 | ||
83 | /// \ingroup raw | |
84 | /// \class AliMUONTrackerDDLDecoderEventHandler | |
85 | /// \brief Callback event handler class for the AliMUONTrackerDDLDecoder. | |
86 | /// | |
87 | /// This class is the base class defining what methods the event handler for the | |
88 | /// high performance decoder should have. This handler actually does nothing. | |
89 | /// The user of this decoder will have to derive from this class a custom event | |
90 | /// handler that actually does something within the callback methods OnNewBusPatch, | |
91 | /// OnData, OnError etc... | |
92 | /// | |
93 | /// \author Artur Szostak <artursz@iafrica.com> | |
94 | ||
95 | class AliMUONTrackerDDLDecoderEventHandler | |
96 | { | |
97 | public: | |
98 | ||
99 | /// The only reason for a virtual destructor is to make -Weffc++ shutup. | |
8a0dae7c | 100 | /// This should not really be here since we do not need or use virtual methods. |
e3a2b9c9 | 101 | virtual ~AliMUONTrackerDDLDecoderEventHandler() {} |
102 | ||
103 | /// All the possible error codes for the parsing. | |
104 | enum ErrorCode | |
105 | { | |
106 | kNoError = 0, /// Decoding was successful. | |
107 | // Offset our error codes to stay clear of any common codes in AliMUONRawStreamTracker: | |
108 | kBufferTooBig = 10, /// The DDL raw data is larger than indicated by the headers; extra bytes are probably just garbage. | |
109 | kTooManyBlocks = 11, /// Too many block structures found. | |
110 | kTooManyDSPs = 12, /// Too many DSP structures found in the block. | |
111 | kTooManyBusPatches = 13, /// Too many bus patch structures found in the DSP structure. | |
112 | kNoBlockHeader = 14, /// Missing a block header. | |
113 | kBadBlockKey = 15, /// The block header key word does not contain the correct value. | |
114 | kBadBlockLength = 16, /// The block length field points past the end of the raw data size. | |
115 | kBadBlockTotalLength = 17, /// The total block length field points past the end of the raw data size. | |
116 | kBlockLengthMismatch = 18, /// The block length and total length fields do not correspond. One or both of these values is incorrect. | |
117 | kNoDSPHeader = 19, /// Missing a DSP header. | |
118 | kBadDSPKey = 20, /// The DSP header key word does not contain the correct value. | |
119 | kBadDSPLength = 21, /// The DSP structure length field points past the end of the block structure. | |
120 | kBadDSPTotalLength = 22, /// The total DSP structure length field points past the end of the block structure. | |
121 | kDSPLengthMismatch = 23, /// The DSP structure length and total length fields do not correspond. One or both of these values is incorrect. | |
122 | kNoBusPatchHeader = 24, /// Missing a bus patch header. | |
123 | kBadBusPatchKey = 25, /// The bus patch header key word does not contain the correct value. | |
124 | kBadBusPatchLength = 26, /// The bus patch length field points past the end of the DSP structure. | |
125 | kBadBusPatchTotalLength = 27, /// The total bus patch length field points past the end of the DSP structure. | |
126 | kBusPatchLengthMismatch = 28, /// The bus patch length and total length fields do not correspond. One or both of these values is incorrect. | |
29b6be6a | 127 | kNoDDLTrailerWords = 29, /// No end of DDL markers found in the trailer words. |
128 | kTooFewDDLTrailerWords = 30, /// Only one end of DDL marker trailer word found but expected two. | |
74585128 | 129 | kUnknownDspError = 31, /// The DSP error code is non-zero but of an unrecognised format. |
130 | kTokenLost = 32, /// The DSP contains a token lost error code that can affect the deadtime. | |
e3a2b9c9 | 131 | // match up error codes with AliMUONRawStreamTracker: |
132 | kGlitchFound = 1, /// Found a glitch. This means a 1 byte word has been randomly inserted into the raw data by mistake. | |
133 | kBadPaddingWord = 2, /// The padding word does not contain the correct value. | |
134 | kParityError = 3 /// Found a parity error in the data word. | |
135 | }; | |
136 | ||
137 | // The following methods should be overridden for specific processing to | |
138 | // take place in your event handler. | |
139 | ||
140 | /// The OnNewBuffer method will be called whenever a new buffer containing | |
141 | /// a DDL payload is about to be processed. | |
142 | /// The default behaviour of this method is to do nothing. | |
143 | /// - param const void* The pointer to the start of the memory buffer storing | |
144 | /// the DDL payload. | |
145 | /// - param UInt_t The size in bytes of the memory buffer. | |
146 | void OnNewBuffer(const void* /*buffer*/, UInt_t /*bufferSize*/) {} | |
147 | ||
e0173291 | 148 | /// The OnEndOfBuffer method will be called whenever the buffer containing |
149 | /// a DDL payload has been processed. For each OnNewBuffer method call a | |
150 | /// symmetric call to OnEndOfBuffer is made at the end of processing (after | |
151 | /// the last call to OnData) | |
152 | /// The default behaviour of this method is to do nothing. | |
153 | /// - param const void* The pointer to the start of the memory buffer storing | |
154 | /// the DDL payload. | |
155 | /// - param UInt_t The size in bytes of the memory buffer. | |
8a0dae7c | 156 | void OnEndOfBuffer(const void* /*buffer*/, UInt_t /*bufferSize*/) {} |
157 | ||
e3a2b9c9 | 158 | /// OnNewBlock is called whenever a new block header is found in the payload. |
159 | /// The default behaviour of this method is to do nothing. | |
e0173291 | 160 | /// - param const AliMUONBlockHeaderStruct* This is a pointer to the block header |
161 | /// as found in the DDL payload. | |
e3a2b9c9 | 162 | /// - param const void* This is a pointer to the start of the block's contents. |
e0173291 | 163 | /// Note: both pointers point into the memory buffer being parsed, so the |
e3a2b9c9 | 164 | /// contents must not be modified. On the other hand this is very efficient |
165 | /// because no memory copying is required. | |
166 | void OnNewBlock(const AliMUONBlockHeaderStruct* /*header*/, const void* /*data*/) {} | |
167 | ||
e0173291 | 168 | /// OnEndOfBlock is called whenever a block has been processed. Symmetric |
169 | /// calls are made to OnEndOfBlock after each call to OnNewBlock. This happens | |
170 | /// once all DSP structures contained inside the current block have been | |
171 | /// processed. | |
172 | /// The default behaviour of this method is to do nothing. | |
173 | /// - param const AliMUONBlockHeaderStruct* This is a pointer to the processed | |
174 | /// block header as found in the DDL payload. | |
175 | /// - param const void* This is a pointer to the start of the block's contents. | |
176 | /// Note: both pointers point into the memory buffer being parsed, so the | |
177 | /// contents must not be modified. On the other hand this is very efficient | |
178 | /// because no memory copying is required. | |
8a0dae7c | 179 | void OnEndOfBlock(const AliMUONBlockHeaderStruct* /*header*/, const void* /*data*/) {} |
180 | ||
e3a2b9c9 | 181 | /// OnNewDSP is called whenever a new DSP header is found in the payload. |
24a0fe9f | 182 | /// Every DSP header received by a call to OnNewDSP is associated to the |
e3a2b9c9 | 183 | /// block header received in the most recent call to OnNewBlock. |
184 | /// The default behaviour of this method is to do nothing. | |
e0173291 | 185 | /// - param const AliMUONDSPHeaderStruct* This is a pointer to the DSP header |
186 | /// as found in the DDL payload. | |
e3a2b9c9 | 187 | /// - param const void* This is a pointer to the start of the DSP's contents. |
e0173291 | 188 | /// Note: both pointers point into the memory buffer being parsed, so the |
e3a2b9c9 | 189 | /// contents must not be modified. On the other hand this is very efficient |
190 | /// because no memory copying is required. | |
191 | void OnNewDSP(const AliMUONDSPHeaderStruct* /*header*/, const void* /*data*/) {} | |
192 | ||
e0173291 | 193 | /// OnEndOfDSP is called whenever a DSP header has already been processed. |
194 | /// For every call to OnNewDSP a symmetric call to OnEndOfDSP is made once | |
195 | /// all the bus patch structured contained in the DSP are processed. | |
196 | /// The default behaviour of this method is to do nothing. | |
197 | /// - param const AliMUONDSPHeaderStruct* This is a pointer to the already | |
198 | /// processed DSP header as found in the DDL payload. | |
199 | /// - param const void* This is a pointer to the start of the DSP's contents. | |
200 | /// Note: both pointers point into the memory buffer being parsed, so the | |
201 | /// contents must not be modified. On the other hand this is very efficient | |
202 | /// because no memory copying is required. | |
8a0dae7c | 203 | void OnEndOfDSP(const AliMUONDSPHeaderStruct* /*header*/, const void* /*data*/) {} |
204 | ||
e3a2b9c9 | 205 | /// OnNewBusPatch is called whenever a new bus patch header is found in |
e0173291 | 206 | /// the payload. Every bus patch received by a call to OnNewBusPatch is |
e3a2b9c9 | 207 | /// associated to the DSP header received in the most recent call to OnNewDSP. |
208 | /// The default behaviour of this method is to do nothing. | |
e0173291 | 209 | /// - param const AliMUONBusPatchHeaderStruct* This is a pointer to the bus patch |
210 | /// header as found in the DDL payload. | |
e3a2b9c9 | 211 | /// - param const void* This is a pointer to the start of the bus patch's contents, |
212 | /// specifically the raw data words. | |
e0173291 | 213 | /// Note: both pointers point into the memory buffer being parsed, so the |
e3a2b9c9 | 214 | /// contents must not be modified. On the other hand this is very efficient |
215 | /// because no memory copying is required. | |
216 | void OnNewBusPatch(const AliMUONBusPatchHeaderStruct* /*header*/, const void* /*data*/) {} | |
217 | ||
e0173291 | 218 | /// OnEndOfBusPatch is called whenever a bus patch has been processed. |
219 | /// For every call to OnNewBusPatch a symmetric call to OnEndOfBusPatch is | |
220 | /// made once the bus patch is completely processed (no more OnData calls). | |
221 | /// The default behaviour of this method is to do nothing. | |
222 | /// - param const AliMUONBusPatchHeaderStruct* This is a pointer to the already | |
223 | /// processed bus patch header, as found in the DDL payload. | |
224 | /// - param const void* This is a pointer to the start of the bus patch's contents, | |
225 | /// specifically the raw data words. | |
226 | /// Note: both pointers point into the memory buffer being parsed so the | |
227 | /// contents must not be modified. On the other hand this is very efficient | |
228 | /// because no memory copying is required. | |
8a0dae7c | 229 | void OnEndOfBusPatch(const AliMUONBusPatchHeaderStruct* /*header*/, const void* /*data*/) {} |
230 | ||
e3a2b9c9 | 231 | /// OnData is called for every raw data word found within a bus patch. |
24a0fe9f | 232 | /// Every data ward received by a call to OnData is associated to the bus patch |
e3a2b9c9 | 233 | /// header received in the most recent call to OnNewBusPatch. |
234 | /// The default behaviour of this method is to do nothing. | |
235 | /// - param UInt_t This is the raw data word as found within the bus patch payload. | |
8a0dae7c | 236 | /// - param bool Flag indicating if the raw data word had a parity error. |
237 | /// This will always be set to false if fSendDataOnParityError in the | |
e843eb88 | 238 | /// AliMUONTrackerDDLDecoder class was set to false. |
8a0dae7c | 239 | void OnData(UInt_t /*data*/, bool /*parityError*/) {} |
e3a2b9c9 | 240 | |
241 | /// Whenever a parsing error of the DDL payload is encountered because of | |
242 | /// corruption of the raw data (eg. bit flips) the OnError method is called | |
24a0fe9f | 243 | /// immediately at the point this error is discovered. |
e3a2b9c9 | 244 | /// The default behaviour of this method is to do nothing. |
245 | /// - param ErrorCode This is an error code indicating the kind of problem | |
246 | /// encountered with the DDL payload. | |
247 | /// - param const void* This is a pointer into the DDL payload memory buffer | |
248 | /// indicating the exact location where the parsing error happened | |
249 | /// or i.e. the location of the corruption. | |
250 | /// Note that a relative offset in bytes from the start of the memory buffer | |
24a0fe9f | 251 | /// can be calculated by: storing the buffer pointer received in OnNewBuffer |
e3a2b9c9 | 252 | /// earlier in fBufferStart for example, and then the offset is given by: |
253 | /// offset = (unsigned long)location - (unsigned long)fBufferStart; | |
254 | void OnError(ErrorCode /*error*/, const void* /*location*/) {} | |
255 | ||
256 | /// This is a utility method which will unpack the MANU ID, channel ID and | |
257 | /// ADC signal value from a raw data word. It should normally be used in | |
258 | /// OnData() to unpack these fields. | |
259 | /// [in] \param data This is the raw data word found in the DDL payload. | |
260 | /// [out] \param manuId This is filled with the unpacked MANU ID. | |
261 | /// [out] \param channelId This is filled with the unpacked MANU channel ID. | |
262 | /// [out] \param adc This is filled with the unpacked ADC signal. | |
263 | static void UnpackADC( | |
264 | UInt_t data, | |
265 | UShort_t& manuId, UChar_t& channelId, UShort_t& adc | |
266 | ) | |
267 | { | |
268 | manuId = (UShort_t)(data >> 18) & 0x7FF; | |
269 | channelId = (Char_t)(data >> 12) & 0x3F; | |
270 | adc = (UShort_t)(data & 0xFFF); | |
271 | } | |
272 | ||
273 | /// This is a utility method which converts an error code to a string | |
24a0fe9f | 274 | /// representation for printing purposes. |
e3a2b9c9 | 275 | /// \param code The error code as received in OnError for example. |
276 | /// \return An ANSI string containing the name of the error code symbol. | |
277 | static const char* ErrorCodeToString(ErrorCode code); | |
278 | ||
279 | /// This is a utility method which converts an error code to user friendly | |
280 | /// descriptive message useful for printing to the screen. | |
281 | /// \param code The error code as received in OnError for example. | |
282 | /// \return An ANSI string containing a descriptive message of the error. | |
283 | static const char* ErrorCodeToMessage(ErrorCode code); | |
284 | }; | |
285 | ||
e0173291 | 286 | //_____________________________________________________________________________ |
287 | ||
288 | inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToString(ErrorCode code) | |
289 | { | |
290 | /// This is a utility method which converts an error code to a string | |
291 | /// representation for printing purposes. | |
292 | /// \param code The error code as received in OnError for example. | |
293 | /// \return An ANSI string containing the name of the error code symbol. | |
294 | ||
295 | switch (code) | |
296 | { | |
297 | case kNoError: return "kNoError"; | |
298 | case kBufferTooBig: return "kBufferTooBig"; | |
299 | case kTooManyBlocks: return "kTooManyBlocks"; | |
300 | case kTooManyDSPs: return "kTooManyDSPs"; | |
301 | case kTooManyBusPatches: return "kTooManyBusPatches"; | |
302 | case kNoBlockHeader: return "kNoBlockHeader"; | |
303 | case kBadBlockKey: return "kBadBlockKey"; | |
304 | case kBadBlockLength: return "kBadBlockLength"; | |
305 | case kBadBlockTotalLength: return "kBadBlockTotalLength"; | |
306 | case kBlockLengthMismatch: return "kBlockLengthMismatch"; | |
307 | case kNoDSPHeader: return "kNoDSPHeader"; | |
308 | case kBadDSPKey: return "kBadDSPKey"; | |
309 | case kBadDSPLength: return "kBadDSPLength"; | |
310 | case kBadDSPTotalLength: return "kBadDSPTotalLength"; | |
311 | case kDSPLengthMismatch: return "kDSPLengthMismatch"; | |
312 | case kNoBusPatchHeader: return "kNoBusPatchHeader"; | |
313 | case kBadBusPatchKey: return "kBadBusPatchKey"; | |
314 | case kBadBusPatchLength: return "kBadBusPatchLength"; | |
315 | case kBadBusPatchTotalLength: return "kBadBusPatchTotalLength"; | |
316 | case kBusPatchLengthMismatch: return "kBusPatchLengthMismatch"; | |
29b6be6a | 317 | case kNoDDLTrailerWords: return "kNoDDLTrailerWords"; |
318 | case kTooFewDDLTrailerWords: return "kTooFewDDLTrailerWords"; | |
74585128 | 319 | case kUnknownDspError: return "kUnknownDspError"; |
320 | case kTokenLost: return "kTokenLost"; | |
e0173291 | 321 | case kGlitchFound: return "kGlitchFound"; |
322 | case kBadPaddingWord: return "kBadPaddingWord"; | |
323 | case kParityError: return "kParityError"; | |
324 | default: return "INVALID"; | |
325 | } | |
326 | } | |
327 | ||
328 | ||
329 | inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToMessage(ErrorCode code) | |
330 | { | |
331 | /// This is a utility method which converts an error code to user friendly | |
332 | /// descriptive message useful for printing to the screen. | |
333 | /// \param code The error code as received in OnError for example. | |
334 | /// \return An ANSI string containing a descriptive message of the error. | |
335 | ||
336 | switch (code) | |
337 | { | |
338 | case kNoError: | |
339 | return "Decoding was successful."; | |
340 | case kBufferTooBig: | |
341 | return "The DDL raw data is larger than indicated by the headers;" | |
342 | " extra bytes are probably just garbage."; | |
343 | case kTooManyBlocks: | |
344 | return "Too many block structures found."; | |
345 | case kTooManyDSPs: | |
346 | return "Too many DSP structures found in the block."; | |
347 | case kTooManyBusPatches: | |
348 | return "Too many bus patch structures found in the DSP structure."; | |
349 | case kNoBlockHeader: | |
350 | return "Missing a block header."; | |
351 | case kBadBlockKey: | |
352 | return "The block header key word does not contain the correct value."; | |
353 | case kBadBlockLength: | |
354 | return "The block length field points past the end of the raw data size."; | |
355 | case kBadBlockTotalLength: | |
356 | return "The total block length field points past the end of the" | |
357 | " raw data size."; | |
358 | case kBlockLengthMismatch: | |
359 | return "The block length and total length fields do not correspond." | |
360 | " One or both of these values is incorrect."; | |
361 | case kNoDSPHeader: | |
362 | return "Missing a DSP header."; | |
363 | case kBadDSPKey: | |
364 | return "The DSP header key word does not contain the correct value."; | |
365 | case kBadDSPLength: | |
366 | return "The DSP structure length field points past the end of the" | |
367 | " block structure."; | |
368 | case kBadDSPTotalLength: | |
369 | return "The total DSP structure length field points past the end of" | |
370 | " the block structure."; | |
371 | case kDSPLengthMismatch: | |
372 | return "The DSP structure length and total length fields do not" | |
373 | " correspond. One or both of these values is incorrect."; | |
374 | case kNoBusPatchHeader: | |
375 | return "Missing a bus patch header."; | |
376 | case kBadBusPatchKey: | |
377 | return "The bus patch header key word does not contain the correct value."; | |
378 | case kBadBusPatchLength: | |
379 | return "The bus patch length field points past the end of the" | |
380 | " DSP structure."; | |
381 | case kBadBusPatchTotalLength: | |
382 | return "The total bus patch length field points past the end of" | |
383 | " the DSP structure."; | |
384 | case kBusPatchLengthMismatch: | |
385 | return "The bus patch length and total length fields do not correspond." | |
386 | " One or both of these values is incorrect."; | |
29b6be6a | 387 | case kNoDDLTrailerWords: |
388 | return "No end of DDL data key found in the trailer words."; | |
389 | case kTooFewDDLTrailerWords: | |
390 | return "Only one end of DDL data key word found in the trailer but expected two."; | |
74585128 | 391 | case kUnknownDspError: |
392 | return "The DSP error code is non-zero but of an unrecognised format."; | |
393 | case kTokenLost: | |
394 | return "The DSP contains a token lost error code that can affect the deadtime."; | |
e0173291 | 395 | case kGlitchFound: |
396 | return "Found a glitch. This means a 1 byte word has been randomly" | |
397 | " inserted into the raw data by mistake."; | |
398 | case kBadPaddingWord: | |
399 | return "The padding word does not contain the correct value."; | |
400 | case kParityError: | |
401 | return "Found a parity error in the data word."; | |
402 | default: | |
403 | return "Unknown error code!"; | |
404 | } | |
405 | } | |
406 | ||
407 | ||
408 | inline std::ostream& operator << (std::ostream& os, AliMUONTrackerDDLDecoderEventHandler::ErrorCode code) | |
409 | { | |
410 | /// This is the stream operator for std::ostream classes to be able to | |
411 | /// easily write the error messages associated with the error codes generated | |
412 | /// by the decoder to 'cout' or 'cerr' for example. | |
413 | ||
414 | os << AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToMessage(code); | |
415 | return os; | |
416 | } | |
417 | ||
e3a2b9c9 | 418 | #endif // ALIMUONTRACKERDDLDECODEREVENTHANDLER_H |
e0173291 | 419 |