Line data Source code
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 24 : class AliMUONTrackerDDLDecoderEventHandler
96 : {
97 : public:
98 :
99 : /// The only reason for a virtual destructor is to make -Weffc++ shutup.
100 : /// This should not really be here since we do not need or use virtual methods.
101 16 : 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.
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.
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.
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 0 : void OnNewBuffer(const void* /*buffer*/, UInt_t /*bufferSize*/) {}
147 :
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.
156 0 : void OnEndOfBuffer(const void* /*buffer*/, UInt_t /*bufferSize*/) {}
157 :
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.
160 : /// - param const AliMUONBlockHeaderStruct* This is a pointer to the block header
161 : /// as found in the DDL payload.
162 : /// - param const void* This is a pointer to the start of the block's contents.
163 : /// Note: both pointers point into the memory buffer being parsed, so the
164 : /// contents must not be modified. On the other hand this is very efficient
165 : /// because no memory copying is required.
166 0 : void OnNewBlock(const AliMUONBlockHeaderStruct* /*header*/, const void* /*data*/) {}
167 :
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.
179 320 : void OnEndOfBlock(const AliMUONBlockHeaderStruct* /*header*/, const void* /*data*/) {}
180 :
181 : /// OnNewDSP is called whenever a new DSP header is found in the payload.
182 : /// Every DSP header received by a call to OnNewDSP is associated to the
183 : /// block header received in the most recent call to OnNewBlock.
184 : /// The default behaviour of this method is to do nothing.
185 : /// - param const AliMUONDSPHeaderStruct* This is a pointer to the DSP header
186 : /// as found in the DDL payload.
187 : /// - param const void* This is a pointer to the start of the DSP's contents.
188 : /// Note: both pointers point into the memory buffer being parsed, so the
189 : /// contents must not be modified. On the other hand this is very efficient
190 : /// because no memory copying is required.
191 0 : void OnNewDSP(const AliMUONDSPHeaderStruct* /*header*/, const void* /*data*/) {}
192 :
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.
203 1472 : void OnEndOfDSP(const AliMUONDSPHeaderStruct* /*header*/, const void* /*data*/) {}
204 :
205 : /// OnNewBusPatch is called whenever a new bus patch header is found in
206 : /// the payload. Every bus patch received by a call to OnNewBusPatch is
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.
209 : /// - param const AliMUONBusPatchHeaderStruct* This is a pointer to the bus patch
210 : /// header as found in the DDL payload.
211 : /// - param const void* This is a pointer to the start of the bus patch's contents,
212 : /// specifically the raw data words.
213 : /// Note: both pointers point into the memory buffer being parsed, so the
214 : /// contents must not be modified. On the other hand this is very efficient
215 : /// because no memory copying is required.
216 0 : void OnNewBusPatch(const AliMUONBusPatchHeaderStruct* /*header*/, const void* /*data*/) {}
217 :
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.
229 7104 : void OnEndOfBusPatch(const AliMUONBusPatchHeaderStruct* /*header*/, const void* /*data*/) {}
230 :
231 : /// OnData is called for every raw data word found within a bus patch.
232 : /// Every data ward received by a call to OnData is associated to the bus patch
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.
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
238 : /// AliMUONTrackerDDLDecoder class was set to false.
239 : void OnData(UInt_t /*data*/, bool /*parityError*/) {}
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
243 : /// immediately at the point this error is discovered.
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
251 : /// can be calculated by: storing the buffer pointer received in OnNewBuffer
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 1416 : manuId = (UShort_t)(data >> 18) & 0x7FF;
269 708 : channelId = (Char_t)(data >> 12) & 0x3F;
270 708 : adc = (UShort_t)(data & 0xFFF);
271 708 : }
272 :
273 : /// This is a utility method which converts an error code to a string
274 : /// representation for printing purposes.
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 :
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 0 : switch (code)
296 : {
297 0 : case kNoError: return "kNoError";
298 0 : case kBufferTooBig: return "kBufferTooBig";
299 0 : case kTooManyBlocks: return "kTooManyBlocks";
300 0 : case kTooManyDSPs: return "kTooManyDSPs";
301 0 : case kTooManyBusPatches: return "kTooManyBusPatches";
302 0 : case kNoBlockHeader: return "kNoBlockHeader";
303 0 : case kBadBlockKey: return "kBadBlockKey";
304 0 : case kBadBlockLength: return "kBadBlockLength";
305 0 : case kBadBlockTotalLength: return "kBadBlockTotalLength";
306 0 : case kBlockLengthMismatch: return "kBlockLengthMismatch";
307 0 : case kNoDSPHeader: return "kNoDSPHeader";
308 0 : case kBadDSPKey: return "kBadDSPKey";
309 0 : case kBadDSPLength: return "kBadDSPLength";
310 0 : case kBadDSPTotalLength: return "kBadDSPTotalLength";
311 0 : case kDSPLengthMismatch: return "kDSPLengthMismatch";
312 0 : case kNoBusPatchHeader: return "kNoBusPatchHeader";
313 0 : case kBadBusPatchKey: return "kBadBusPatchKey";
314 0 : case kBadBusPatchLength: return "kBadBusPatchLength";
315 0 : case kBadBusPatchTotalLength: return "kBadBusPatchTotalLength";
316 0 : case kBusPatchLengthMismatch: return "kBusPatchLengthMismatch";
317 0 : case kNoDDLTrailerWords: return "kNoDDLTrailerWords";
318 0 : case kTooFewDDLTrailerWords: return "kTooFewDDLTrailerWords";
319 0 : case kUnknownDspError: return "kUnknownDspError";
320 0 : case kTokenLost: return "kTokenLost";
321 0 : case kGlitchFound: return "kGlitchFound";
322 0 : case kBadPaddingWord: return "kBadPaddingWord";
323 0 : case kParityError: return "kParityError";
324 0 : default: return "INVALID";
325 : }
326 0 : }
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 0 : switch (code)
337 : {
338 : case kNoError:
339 0 : return "Decoding was successful.";
340 : case kBufferTooBig:
341 0 : return "The DDL raw data is larger than indicated by the headers;"
342 : " extra bytes are probably just garbage.";
343 : case kTooManyBlocks:
344 0 : return "Too many block structures found.";
345 : case kTooManyDSPs:
346 0 : return "Too many DSP structures found in the block.";
347 : case kTooManyBusPatches:
348 0 : return "Too many bus patch structures found in the DSP structure.";
349 : case kNoBlockHeader:
350 0 : return "Missing a block header.";
351 : case kBadBlockKey:
352 0 : return "The block header key word does not contain the correct value.";
353 : case kBadBlockLength:
354 0 : return "The block length field points past the end of the raw data size.";
355 : case kBadBlockTotalLength:
356 0 : return "The total block length field points past the end of the"
357 : " raw data size.";
358 : case kBlockLengthMismatch:
359 0 : return "The block length and total length fields do not correspond."
360 : " One or both of these values is incorrect.";
361 : case kNoDSPHeader:
362 0 : return "Missing a DSP header.";
363 : case kBadDSPKey:
364 0 : return "The DSP header key word does not contain the correct value.";
365 : case kBadDSPLength:
366 0 : return "The DSP structure length field points past the end of the"
367 : " block structure.";
368 : case kBadDSPTotalLength:
369 0 : return "The total DSP structure length field points past the end of"
370 : " the block structure.";
371 : case kDSPLengthMismatch:
372 0 : 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 0 : return "Missing a bus patch header.";
376 : case kBadBusPatchKey:
377 0 : return "The bus patch header key word does not contain the correct value.";
378 : case kBadBusPatchLength:
379 0 : return "The bus patch length field points past the end of the"
380 : " DSP structure.";
381 : case kBadBusPatchTotalLength:
382 0 : return "The total bus patch length field points past the end of"
383 : " the DSP structure.";
384 : case kBusPatchLengthMismatch:
385 0 : return "The bus patch length and total length fields do not correspond."
386 : " One or both of these values is incorrect.";
387 : case kNoDDLTrailerWords:
388 0 : return "No end of DDL data key found in the trailer words.";
389 : case kTooFewDDLTrailerWords:
390 0 : return "Only one end of DDL data key word found in the trailer but expected two.";
391 : case kUnknownDspError:
392 0 : return "The DSP error code is non-zero but of an unrecognised format.";
393 : case kTokenLost:
394 0 : return "The DSP contains a token lost error code that can affect the deadtime.";
395 : case kGlitchFound:
396 0 : 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 0 : return "The padding word does not contain the correct value.";
400 : case kParityError:
401 0 : return "Found a parity error in the data word.";
402 : default:
403 0 : return "Unknown error code!";
404 : }
405 0 : }
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 :
418 : #endif // ALIMUONTRACKERDDLDECODEREVENTHANDLER_H
419 :
|