]> git.uio.no Git - u/mrichter/AliRoot.git/blame_incremental - RAW/AliAltroDecoder.cxx
The present commit corresponds to an important change in the way the
[u/mrichter/AliRoot.git] / RAW / AliAltroDecoder.cxx
... / ...
CommitLineData
1// $Id$
2
3/**************************************************************************
4 * This file is property of and copyright by the ALICE HLT Project *
5 * All rights reserved. *
6 * *
7 * Primary Authors: Per Thomas Hille <perthi@fys.uio.no> *
8 * Oystein Djuvsland <oystein.djuvsland@gmail.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/**
20 @file AliAltroDocoder.cxx
21 @author Per Thomas Hille, Oystein Djuvsland
22 @date
23 @brief High performance decoder class for the RCU/Altro data format
24*/
25
26#include <cassert>
27#include <Riostream.h>
28#include "AliAltroDecoder.h"
29#include "AliAltroData.h"
30#include "AliLog.h"
31
32// Class for fast decoding of RCU/Altro raw data format (DDL format)
33// to PC readable form. The decoding is done in 3 steps.
34// 1) The RCU payload consist of a variable number of 160 bit words
35// denoted a DDL block. All the DDL blocks of an RCU payload are transformed
36// into 16 bit integers and stored into a buffer of integers big enought to contain the
37// biggest number of samples possible
38// 2) The decoded buffer is then accesible for the NextChannel functions wich reads
39// the altro channel data (samples) contained in the payload. The first call to NextChannel gives the
40// last altro channel of the back linked list, the next call the second last channel ..etc until
41// all channels are read.
42// 3) (optional) For each Altro channel one chan invoke the member function NextBunch which gives on first call
43// The last bunch (the bunch with the highest timestamp), on next call the second last bunch..etc
44// untill all bunches are read
45
46
47ClassImp(AliAltroDecoder)
48
49AliAltroDecoder::AliAltroDecoder() : f32DtaPtr(0),
50 f8DtaPtr(0),
51 fkN32HeaderWords(8),
52 fN40AltroWords(0),
53 fN40RcuAltroWords(0),
54 fNDDLBlocks(0),
55 f32LastDDLBlockSize(5),
56 f8PayloadSize(0),
57 fOutBufferIndex(0),
58 fSize(0),
59 fNAltro10bitWords(0),
60 fComplete(0),
61 fInComplete(0),
62 fDecodeIfCorruptedTrailer(kTRUE),
63 fIsDecoded(kFALSE),
64 fIsFatalCorruptedTrailer(kTRUE)
65 // fIsFirstChannelOfPayload(kTRUE)
66{
67 // Default constructor
68}
69
70
71AliAltroDecoder::~AliAltroDecoder()
72{
73 // Default destructor
74}
75
76
77Bool_t AliAltroDecoder::CheckPayloadTrailer() const
78{
79 //Check consistency between the number of 40 bit altro words given by
80 //the RCU payload and the number of 40 bit words calculated from the size of the RCU payload.
81
82 if(fN40AltroWords != fN40RcuAltroWords)
83 {
84 return kFALSE;
85 }
86 else
87 {
88 return kTRUE;
89 }
90}
91
92
93Bool_t AliAltroDecoder::Decode()
94{
95 // Decodes the RCU payload (all altro channels in one go) from the DDL/Altro
96 // format to PC readable format.
97 // The 10 bit words of the 40/10 bit Altro format are transformed to separated
98 // integers.
99
100 if( fIsFatalCorruptedTrailer == kTRUE)
101 {
102 // printf("\n AliAltroDecoder::Decode(), WARNING, attempt to decode badly corrupted data\n");
103 // printf("\n AliAltroDecoder::Decode(). Please check on the return value (-1 if fataly corrupted) of the SetMemory() function\n");
104 return kFALSE;
105 }
106 else if (!f8DtaPtr || !f32DtaPtr ||
107 (UChar_t*)f32DtaPtr < f8DtaPtr-fSize ||
108 (UChar_t*)f32DtaPtr > f8DtaPtr)
109 {
110 return kFALSE;
111 }
112 else
113 {
114 // see header file for class documentation
115 fComplete = 0;
116 fInComplete = 0;
117
118 Int_t tmpcnt = CountAAApaddings();
119
120 if(tmpcnt == 3)
121 {
122 fN40AltroWords = fN40AltroWords -1;
123 }
124 else if(tmpcnt == 5)
125 {
126 fN40AltroWords = fN40AltroWords -2;
127 }
128 else if(tmpcnt == 8)
129 {
130 fN40AltroWords = fN40AltroWords -3;
131 }
132
133 if( ((CheckPayloadTrailer() == kTRUE) || fDecodeIfCorruptedTrailer == kTRUE ) && (fSize > 32) )
134 {
135 fOutBufferIndex = 0;
136
137 for(Int_t i = 0; i < fNDDLBlocks; i++)
138 {
139 DecodeDDLBlock();
140 }
141
142 DecodeLastDDLBlock();
143 fOutBufferIndex = fN40AltroWords*4 - 1;
144 fIsDecoded = kTRUE;
145 return kTRUE;
146 }
147
148 else
149 {
150// cout <<" ERROR: data integrity check failed, discarding data" << endl;
151// cout << "Size of datablock is " << fSize << endl;
152// cout << "fN40AltroWords = " << fN40AltroWords << endl;
153// cout << "fN40RcuAltroWords = " << fN40RcuAltroWords << endl;
154 return kFALSE;
155 }
156
157 }
158}
159
160
161
162
163Bool_t AliAltroDecoder::NextChannel(AliAltroData *altroDataPtr)
164{
165 // Reads the next altro channel in the RCU payload after the RCU payload
166 // has been decoded. The channels are read starting from the end (backlinked list)
167 // Returns kTRUE as long as ther are unread channels in the payload
168 // Returns kFALSE when all the channels have been read.
169
170 if(fIsFatalCorruptedTrailer == kTRUE)
171 {
172 return kFALSE;
173 }
174
175 else
176 {
177
178 if(fIsDecoded != kTRUE)
179 {
180 Decode();
181 }
182
183 // an altro block must constist of at least 2 40bit words:
184 // - 40bit Altro trailer
185 // - at least 3 10bit words (bunch length, time bin, signal) padded to 40 bit
186 // we are reading backwards, so the index is already 1 inside the block
187 if(fOutBufferIndex >= 7)
188 {
189 if(((fOutBuffer[fOutBufferIndex] << 4 ) | ((fOutBuffer[fOutBufferIndex-1] & 0x3c0) >> 6)) == 0x2aaa)
190 {
191 altroDataPtr->SetIsComplete(kTRUE);
192 fComplete ++;
193 }
194 else
195 {
196 altroDataPtr->SetIsComplete(kFALSE);
197 fInComplete ++;
198 }
199
200 fOutBufferIndex --;
201 fNAltro10bitWords = ( (fOutBuffer[fOutBufferIndex] & 0x3f) << 4 ) | ((fOutBuffer[fOutBufferIndex -1] & (0xF << 6)) >> 6) ;
202 fOutBufferIndex --;
203 altroDataPtr->SetHadd( ((fOutBuffer[fOutBufferIndex] & 0x3)) << 10 | ( fOutBuffer[fOutBufferIndex-1] ), fOutBufferIndex);
204
205 fOutBufferIndex --;
206
207 if(fNAltro10bitWords%4 == 0)
208 {
209 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords;
210 }
211 else
212 {
213 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords -(4 - fNAltro10bitWords%4);
214 }
215
216 if(fOutBufferIndex >= 0)
217 {
218 altroDataPtr->SetData( &fOutBuffer[fOutBufferIndex] );
219 fOutBufferIndex --;
220 altroDataPtr->SetDataSize( fNAltro10bitWords );
221 return kTRUE;
222 }
223 else
224 {
225 //TODO write a fatal log message when this happends
226 return kFALSE;
227 }
228
229 }
230 else
231 {
232 return kFALSE;
233 }
234
235 }
236}
237
238
239Int_t AliAltroDecoder::CountAAApaddings() const
240{
241 // Use for simulated data only.
242 // Patch for incorrectly simulated data. Counts the number of
243 // 2aaa word in the trailer of the payload and tries to figure out
244 // the correct number of 40 bit altro words in the RCU pauload
245 //
246 // The simulated raw data differs from the real data by a number
247 // of additional 0x2aa words between the Altro payload and the
248 // RCU trailer. This is most likely to bring the total number of
249 // bytes to a common multiple of 4 and 5.
250
251 UShort_t *tailPtr= (UShort_t *)((UChar_t*)f32DtaPtr + f8PayloadSize);
252 Int_t cnt = 0;
253
254 tailPtr --;
255
256 while(*tailPtr == 0xaaaa)
257 {
258 cnt ++;
259 tailPtr --;
260 }
261
262 tailPtr = tailPtr + cnt +1;
263
264 return cnt;
265}
266
267
268Float_t AliAltroDecoder::GetFailureRate()
269{
270 // Prints to stdout the percent of altroblocks that
271 // is missing the 2aaa trailer.
272
273 Float_t tmp = 0;
274 // cout << "Number of Complete channles = " << fComplete <<endl;
275 // cout << "Number of InComplete channles = " << fInComplete <<endl;
276 tmp = (100*(Float_t)fInComplete)/((Float_t)fComplete + (Float_t)fInComplete);
277 // cout <<"There are "<< tmp <<"% incomplete channels"<<endl;
278 return tmp;
279}
280
281
282
283void AliAltroDecoder::PrintInfo(AliAltroData &altrodata, Int_t n, Int_t nPerLine)
284{
285 // prints data and address information contained in altrodata
286 // to the standard output
287
288 // cout << "altrodata.fDataSize = " << altrodata.GetDataSize() << endl;
289 // cout << "altrodata.fHadd = " << altrodata.GetHadd() <<endl;
290 const UInt_t* data = altrodata.GetData();
291 for(Int_t i= 0; i< n; i++)
292 {
293 if( (i%nPerLine == 0) && (i != 0) )
294 {
295 printf("\n");
296 }
297 printf("%d\t", data[i]);
298 }
299 printf("\n");
300}
301
302
303int AliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size)
304{
305 // Sets the pointer to the memory block that should be decoded
306 // Returns a negative value if an inconsistency in the data is detected
307
308 // fIsFirstChannelOfPayload = kTRUE;
309 int iRet = 0;
310 fIsDecoded = kFALSE;
311
312 if(dtaPtr == 0)
313 {
314 // printf("\nAliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size) FATAL ERROR, dtaPtr = ZERO !!!!!!!!!!!!\n");
315 // printf("Please check your code that you don't give a zero pointer to the decoder \n");
316 return -99;
317 }
318
319 if ((Int_t)size<(fkN32HeaderWords+1)*4)
320 {
321 // printf("\nAliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size) FATAL ERROR, too little data (%d)\n", size);
322 // printf("Data buffer must contain the CDH and at least one 32bit RCU trailer word\n");
323 return -99;
324 }
325
326 UInt_t tmpTrailerSize;
327 f8DtaPtr =dtaPtr;
328 fSize = size;
329 f8DtaPtr =f8DtaPtr + fSize;
330 f32DtaPtr = (UInt_t *)f8DtaPtr;
331 tmpTrailerSize = *(f32DtaPtr - 1);
332
333 // format of the trailer has been fixed in the RCU FW2
334 // Bit 31 to 16: 0xaaaa (16 bit)
335 // Bit 15 to 7: RCU address ( 9 bit)
336 // Bit 6 to 0: Trailer length ( 7 bit)
337 //
338 // RCU FW1 has one trailer word containing the number of
339 // 10bit Altro words. According to some early documents,
340 // it should have at least 2 32bit words: trailer length and
341 // the number of 10bit Altro words. This is the format of
342 // the simulation at time of writing (June 2008)
343 bool haveFw2=false;
344 if ((tmpTrailerSize>>16)==0xaaaa) {
345 haveFw2=true;
346 tmpTrailerSize = tmpTrailerSize&0x7f; // 7 LSBs of the last word
347 } else
348 if(tmpTrailerSize <= MAX_TRAILER_WORDS)
349 {
350 tmpTrailerSize = tmpTrailerSize; //assume that the last word of the buffer gives the number of trailer words
351 }
352 // nof 10bit AltroWords * 5/4 + bytes in the CDH + 4 bytes RCU trailer
353 else if (((*(f32DtaPtr-1)*5)/4 + fkN32HeaderWords*4 + 4)<=fSize)
354 {
355 tmpTrailerSize = 1; //assume that last word is ONE, and that the this word gives the number of 40 bit altro words
356 }
357 else
358 {
359 tmpTrailerSize=0;
360 fIsFatalCorruptedTrailer = kTRUE;
361 iRet = -1;
362 }
363
364 if(tmpTrailerSize > 0 && (fkN32HeaderWords + tmpTrailerSize)*4<=fSize)
365 {
366 f8PayloadSize = fSize - (fkN32HeaderWords + tmpTrailerSize)*4;
367 fN40AltroWords = f8PayloadSize/5;
368 fNDDLBlocks = fN40AltroWords/4;
369 f32LastDDLBlockSize = ((f8PayloadSize%(4*DDL_32BLOCK_SIZE))+3)/4;
370
371 f32DtaPtr = f32DtaPtr - tmpTrailerSize;
372 fN40RcuAltroWords = *f32DtaPtr;
373 f32DtaPtr = (UInt_t *)dtaPtr + fkN32HeaderWords;
374 fIsFatalCorruptedTrailer = kFALSE;
375 }
376
377 // all subsequent consistency checks depend on the correct initialization
378 // of the pointer and size variables
379 assert(f8DtaPtr == dtaPtr + fSize);
380 return iRet;
381
382}
383
384
385void AliAltroDecoder::DecodeDDLBlock()
386{
387 //Decode one 160 bit DDL block into 16 x 16 bit integers (only least significant 10 bits are filled)
388
389 fOutBuffer[fOutBufferIndex] = *f32DtaPtr & 0x3ff; //s0
390 fOutBufferIndex ++;
391 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00) >> 10; //s1
392 fOutBufferIndex ++;
393 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00000) >> 20; //s2
394 fOutBufferIndex ++;
395 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xc0000000) >> 30; //s3_1
396 f32DtaPtr ++;
397 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xff) << 2); //s3_2
398 fOutBufferIndex ++;
399 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00) >> 8; //s4
400 fOutBufferIndex ++;
401 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0000) >> 18; //s5
402 fOutBufferIndex ++;
403 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xf0000000) >> 28; //s6_1
404 f32DtaPtr ++;
405 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3f) << 4); //s6_2
406 fOutBufferIndex ++;
407 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0) >> 6; //s7
408 fOutBufferIndex ++;
409 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0000) >> 16; //s8
410 fOutBufferIndex ++;
411 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xFC000000) >> 26; //s9_1
412 f32DtaPtr ++;
413 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xf) << 6); //s9_2
414 fOutBufferIndex ++;
415 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0) >> 4; //s10
416 fOutBufferIndex ++;
417 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc000) >> 14; //s11
418 fOutBufferIndex ++;
419 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xff000000) >> 24; //s12_1
420 f32DtaPtr ++;
421 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3) << 8); //s12_2
422 fOutBufferIndex ++;
423 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc) >> 2; //s13
424 fOutBufferIndex ++;
425 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff000) >> 12; //s14
426 fOutBufferIndex ++;
427 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00000) >> 22; //s15
428 f32DtaPtr ++;
429 fOutBufferIndex ++;
430}
431
432
433
434
435
436
437
438
439void AliAltroDecoder::DecodeLastDDLBlock()
440{
441 // Decode one 160 bit DDL block into 16 integers.
442 // In order to use the same decoding function (DecodeDDLBlock())
443 // a copy of the the last DDL block is made and
444 // if the last block does not align with 160 bits then it is padded with zeroes
445
446 for(Int_t i=0; i < f32LastDDLBlockSize; i++)
447 {
448 fDDLBlockDummy[i] = *f32DtaPtr;
449 f32DtaPtr ++;
450 }
451
452 f32DtaPtr = fDDLBlockDummy;
453 DecodeDDLBlock();
454 f32DtaPtr=(UInt_t*)(f8DtaPtr-fSize+f8PayloadSize+fkN32HeaderWords*4);
455}
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485Int_t AliAltroDecoder::CopyBackward(Byte_t* pBuffer, Int_t bufferSize)
486{
487 // Copy the original 10/40 bit encecoded data of the current channel.
488 // The funtions copies the data to the end of the provided buffer.
489 // @param pBuffer target buffer
490 // @param bufferSize size of target buffer
491 // @return number of copied bytes, neg. error code if failed
492 Int_t iCopy=0;
493
494 if(fIsDecoded != kTRUE) {
495 AliWarning("buffer has not been decoded, no channel data available");
496 return 0;
497 }
498
499 // This method does not need to be the fastest possible implementation
500 // For the sake of stability, there are a lot of consistency checks.
501
502 // the fOutBufferIndex always points to the next channel, since we are
503 // reading backwards, this is one byte before the start of the current
504 // channel.
505 Int_t currentIndex=fOutBufferIndex+1;
506 if (fNAltro10bitWords>0 && currentIndex < fN40AltroWords*4 ) {
507
508 // calculate the position in the encoded data, beginning right
509 // after the CDH. 10 -> 8 bit: needs 5/4 times the index
510 Int_t position=(currentIndex*5)/4;
511 if (position*4==currentIndex*5) {
512 // no of 10 bit words is without the fill words to fill complete 40 bit words
513 // in addition, align to complete 40 bit words (the '+3')
514 iCopy=((fNAltro10bitWords+3)/4)*5;
515
516 // calculate the source pointer in the encoded data
517 // f8DtaPtr was set to the end of the whole data buffer
518 // f32DtaPtr is behind the payload after decoding
519 Byte_t* pSrc=f8DtaPtr-fSize+(fkN32HeaderWords*4)+position;
520 if (pSrc+5<(Byte_t*)f32DtaPtr) {
521
522 // check the first byte of the source buffer, has to be consistent
523 // with the 8 LSBs of the decoded 10 bit word at the beginning of
524 // the current channel
525 //assert(*pSrc==fOutBuffer[currentIndex]&0xff);
526 if (*pSrc==(fOutBuffer[currentIndex]&0xff)) {
527
528 // try to verfify the length of the channel
529 UInt_t lenCheck=*(pSrc+iCopy+2)|(*(pSrc+iCopy+3)&0x3)<<8;
530 if (lenCheck==fNAltro10bitWords) {
531
532 // copy including the 40 bit altro trailer
533 iCopy+=5;
534 if (iCopy<=bufferSize) {
535
536 // copy to the end of the buffer
537 Byte_t* pTgt=pBuffer+bufferSize-iCopy;
538 memcpy(pTgt, pSrc, iCopy);
539 } else {
540 AliError(Form("target buffer too small: available %d, required %d", bufferSize, iCopy));
541 iCopy=-1;
542 }
543 } else {
544 AliWarning(Form("format error: can not reproduce channel length: expected %d, read %d", fNAltro10bitWords, lenCheck));
545 iCopy=-1;
546 }
547 } else {
548 AliError(Form("first byte of encoded data (%#x at %d) does not match decoded word (%#x at %d)", *pSrc, position, fOutBuffer[currentIndex]&0xff, currentIndex));
549 iCopy=-1;
550 }
551 } else {
552 AliError(Form("buffer size missmatch: payload ends at %p, but current channel pretends to end at %p", f32DtaPtr, pSrc+5));
553 iCopy=-1;
554 }
555 } else {
556 AliError(Form("current position does not match a byte: currentIndex=%d", currentIndex));
557 iCopy=-1;
558 }
559 }
560 return iCopy;
561}
562
563Bool_t AliAltroDecoder::GetRCUTrailerData(UChar_t*& data) const
564{
565 // Provide a pointer to RCU trailer.
566 // The type of the parameter might not be optimal, but the function has
567 // been chosen that way to be similar to the counterpart in
568 // AliAltroRawStream.
569 // @return kTRUE if trailer available;
570 if (!f8DtaPtr) return kFALSE;
571 data=f8DtaPtr-(fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
572 assert((UChar_t*)f32DtaPtr == data);
573 return kTRUE;
574}
575
576Int_t AliAltroDecoder::GetRCUTrailerSize() const
577{
578 // Provide size of RCU trailer.
579 if (!f8DtaPtr || !fIsDecoded || fSize==0) return 0;
580 assert(fSize>(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
581 return fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t));
582}