3 /**************************************************************************
4 * This file is property of and copyright by the ALICE HLT Project *
5 * All rights reserved. *
7 * Primary Authors: Per Thomas Hille <perthi@fys.uio.no> *
8 * Oystein Djuvsland <oystein.djuvsland@gmail.com> *
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 **************************************************************************/
20 @file AliAltroDocoder.cxx
21 @author Per Thomas Hille, Oystein Djuvsland
23 @brief High performance decoder class for the RCU/Altro data format
27 #include <Riostream.h>
28 #include "AliAltroDecoder.h"
29 #include "AliAltroData.h"
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
47 ClassImp(AliAltroDecoder)
49 AliAltroDecoder::AliAltroDecoder() : f32DtaPtr(0),
55 f32LastDDLBlockSize(5),
62 fDecodeIfCorruptedTrailer(kTRUE),
64 fIsFatalCorruptedTrailer(kTRUE)
66 // Default constructor
70 AliAltroDecoder::~AliAltroDecoder()
76 Bool_t AliAltroDecoder::CheckPayloadTrailer() const
78 //Check consistency between the number of 40 bit altro words given by
79 //the RCU payload and the number of 40 bit words calculated from the size of the RCU payload.
81 if(fN40AltroWords != fN40RcuAltroWords)
92 Bool_t AliAltroDecoder::Decode()
94 // Decodes the RCU payload (all altro channels in one go) from the DDL/Altro
95 // format to PC readable format.
96 // The 10 bit words of the 40/10 bit Altro format are transformed to separated
99 if( fIsFatalCorruptedTrailer == kTRUE)
101 // printf("\n AliAltroDecoder::Decode(), WARNING, attempt to decode badly corrupted data\n");
102 // printf("\n AliAltroDecoder::Decode(). Please check on the return value (-1 if fataly corrupted) of the SetMemory() function\n");
108 // see header file for class documentation
112 Int_t tmpcnt = CountAAApaddings();
116 fN40AltroWords = fN40AltroWords -1;
120 fN40AltroWords = fN40AltroWords -2;
124 fN40AltroWords = fN40AltroWords -3;
127 if( ((CheckPayloadTrailer() == kTRUE) || fDecodeIfCorruptedTrailer == kTRUE ) && (fSize > 32) )
132 for(Int_t i = 0; i < fNDDLBlocks; i++)
137 DecodeLastDDLBlock();
138 fOutBufferIndex = fN40AltroWords*4 - 1;
140 // DumpData(fOutBuffer, 400,4);
148 // cout <<" ERROR: data integrity check failed, discarding data" << endl;
149 // cout << "Size of datablock is " << fSize << endl;
150 // cout << "fN40AltroWords = " << fN40AltroWords << endl;
151 // cout << "fN40RcuAltroWords = " << fN40RcuAltroWords << endl;
159 Bool_t AliAltroDecoder::NextChannel(AliAltroData *altroDataPtr)
161 // Reads the next altro channel in the RCU payload after the RCU payload
162 // has been decoded. The channels are read starting from the end (backlinked list)
163 // Returns kTRUE as long as ther are unread channels in the payload
164 // Returns kFALSE when all the channels have been read.
166 if(fIsFatalCorruptedTrailer == kTRUE)
168 // printf("\n AliAltroDecoder::NextChannel(), WARNING, attempt to decode badly corrupted data\n");
169 // printf("\n AliAltroDecoder::NextChannel(), Please check on the return value (-1 if fataly corrupted) of the SetMemory() function\n");
176 if(fIsDecoded != kTRUE)
178 // cout <<"AliAltroDecoder::NextChanne, WARNING, buffer was not decoded, decoding now.. "<< endl;
182 // an altro block must constist of at least 2 40bit words:
183 // - 40bit Altro trailer
184 // - at least 3 10bit words (bunch length, time bin, signal) padded to 40 bit
185 // we are reading backwards, so the index is already 1 inside the block
186 if(fOutBufferIndex >= 7)
188 if((fOutBuffer[fOutBufferIndex] << 4 ) | ((fOutBuffer[fOutBufferIndex-1] & 0x3c0) >> 6) == 0x2aaa)
190 altroDataPtr->SetIsComplete(kTRUE);
195 altroDataPtr->SetIsComplete(kFALSE);
200 fNAltro10bitWords = ( (fOutBuffer[fOutBufferIndex] & 0x3f) << 4 ) | ((fOutBuffer[fOutBufferIndex -1] & (0xF << 6)) >> 6) ;
202 altroDataPtr->SetHadd( ((fOutBuffer[fOutBufferIndex] & 0x3)) << 10 | ( fOutBuffer[fOutBufferIndex-1] ) );
206 if(fNAltro10bitWords%4 == 0)
208 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords;
212 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords -(4 - fNAltro10bitWords%4);
216 if(fOutBufferIndex > 0)
219 //cout << " AliAltroDecoder::NextChannel fOutBufferIndex =" << fOutBufferIndex << endl;
220 // printf( "AliAltroDecoder::NextChannel fOutBufferIndex = %d", fOutBufferIndex);
221 altroDataPtr->SetData( &fOutBuffer[fOutBufferIndex] );
223 altroDataPtr->SetDataSize( fNAltro10bitWords );
228 //TODO write a fatal log message when this happends
243 Int_t AliAltroDecoder::CountAAApaddings() const
245 // Use for simulated data only.
246 // Patch for incorrectly simulated data. Counts the number of
247 // 2aaa word in the trailer of the payload and tries to figure out
248 // the correct number of 40 bit altro words in the RCU pauload
250 // The simulated raw data differs from the real data by a number
251 // of additional 0x2aa words between the Altro payload and the
252 // RCU trailer. This is most likely to bring the total number of
253 // bytes to a common multiple of 4 and 5.
255 UShort_t *tailPtr= (UShort_t *)((UChar_t*)f32DtaPtr + f8PayloadSize);
260 while(*tailPtr == 0xaaaa)
266 tailPtr = tailPtr + cnt +1;
272 Float_t AliAltroDecoder::GetFailureRate()
274 // Prints to stdout the percent of altroblocks that
275 // is missing the 2aaa trailer.
278 // cout << "Number of Complete channles = " << fComplete <<endl;
279 // cout << "Number of InComplete channles = " << fInComplete <<endl;
280 tmp = (100*(Float_t)fInComplete)/((Float_t)fComplete + (Float_t)fInComplete);
281 // cout <<"There are "<< tmp <<"% incomplete channels"<<endl;
286 void AliAltroDecoder::PrintInfo(AliAltroData &altrodata, Int_t n, Int_t nPerLine)
288 // prints data and address information contained in altrodata
289 // to the standard output
291 // cout << "altrodata.fDataSize = " << altrodata.GetDataSize() << endl;
292 // cout << "altrodata.fHadd = " << altrodata.GetHadd() <<endl;
293 const UInt_t* data = altrodata.GetData();
294 for(Int_t i= 0; i< n; i++)
296 if( (i%nPerLine == 0) && (i != 0) )
300 printf("%d\t", data[i]);
306 int AliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size)
308 // Sets the pointer to the memory block that should be decoded
309 // Returns a negative value if an inconsistency in the data is detected
313 printf("\nAliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size) FATAL ERROR, dtaPtr = ZERO !!!!!!!!!!!!\n");
314 printf("\nThis is an user error, please check in your code that you don give a zero pointer to the decoder \n");
320 Int_t tmpTrailerSize;
324 f8DtaPtr =f8DtaPtr + fSize;
325 f32DtaPtr = (UInt_t *)f8DtaPtr;
326 tmpTrailerSize = *(f32DtaPtr - 1);
328 if(tmpTrailerSize <= MAX_TRAILER_WORDS)
330 tmpTrailerSize = tmpTrailerSize; //assume that the last word of the buffer gives the number of trailer words
334 tmpTrailerSize = 1; //assume that last word is ONE, and that the this word gives the number of 40 bit altro words
337 f8PayloadSize = fSize - (fkN32HeaderWords + tmpTrailerSize)*4;
338 fN40AltroWords = f8PayloadSize/5;
339 fNDDLBlocks = fN40AltroWords/4;
340 f32LastDDLBlockSize = ((f8PayloadSize%(4*DDL_32BLOCK_SIZE))+3)/4;
342 if(tmpTrailerSize > 0 && tmpTrailerSize < 5)
344 f32DtaPtr = f32DtaPtr - tmpTrailerSize;
345 fN40RcuAltroWords = *f32DtaPtr;
346 f32DtaPtr = (UInt_t *)dtaPtr + fkN32HeaderWords;
347 fIsFatalCorruptedTrailer = kFALSE;
351 // printf("\n AliAltroDecoder::SetMemory, ERROR\n, trailer is corrupted");
352 fIsFatalCorruptedTrailer = kTRUE;
361 void AliAltroDecoder::DecodeDDLBlock()
363 //Decode one 160 bit DDL block into 16 x 16 bit integers (only least significant 10 bits are filled)
365 fOutBuffer[fOutBufferIndex] = *f32DtaPtr & 0x3ff; //s0
367 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00) >> 10; //s1
369 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00000) >> 20; //s2
371 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xc0000000) >> 30; //s3_1
373 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xff) << 2); //s3_2
375 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00) >> 8; //s4
377 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0000) >> 18; //s5
379 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xf0000000) >> 28; //s6_1
381 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3f) << 4); //s6_2
383 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0) >> 6; //s7
385 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0000) >> 16; //s8
387 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xFC000000) >> 26; //s9_1
389 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xf) << 6); //s9_2
391 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0) >> 4; //s10
393 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc000) >> 14; //s11
395 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xff000000) >> 24; //s12_1
397 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3) << 8); //s12_2
399 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc) >> 2; //s13
401 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff000) >> 12; //s14
403 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00000) >> 22; //s15
409 void AliAltroDecoder::DecodeLastDDLBlock()
411 // Decode one 160 bit DDL block into 16 integers.
412 // In order to use the same decoding function (DecodeDDLBlock())
413 // a copy of the the last DDL block is made and
414 // if the las block does not align with 160 bits then it is padded with zeroes
416 for(Int_t i=0; i < f32LastDDLBlockSize; i++)
418 fDDLBlockDummy[i] = *f32DtaPtr;
422 f32DtaPtr = fDDLBlockDummy;
424 f32DtaPtr=(UInt_t*)(f8DtaPtr-fSize+f8PayloadSize+fkN32HeaderWords*4);
427 Int_t AliAltroDecoder::CopyBackward(Byte_t* pBuffer, Int_t bufferSize)
429 // Copy the original 10/40 bit encecoded data of the current channel.
430 // The funtions copies the data to the end of the provided buffer.
431 // @param pBuffer target buffer
432 // @param bufferSize size of target buffer
433 // @return number of copied bytes, neg. error code if failed
436 if(fIsDecoded != kTRUE) {
437 AliWarning("buffer has not been decoded, no channel data available");
441 // This method does not need to be the fastest possible implementation
442 // For the sake of stability, there are a lot of consistency checks.
444 // the fOutBufferIndex always points to the next channel, since we are
445 // reading backwards, this is one byte before the start of the current
447 Int_t currentIndex=fOutBufferIndex+1;
448 if (fNAltro10bitWords>0 && currentIndex < fN40AltroWords*4 ) {
450 // calculate the position in the encoded data, beginning right
451 // after the CDH. 10 -> 8 bit: needs 5/4 times the index
452 Int_t position=(currentIndex*5)/4;
453 if (position*4==currentIndex*5) {
454 // no of 10 bit words is without the fill words to fill complete 40 bit words
455 // in addition, align to complete 40 bit words (the '+3')
456 iCopy=((fNAltro10bitWords+3)/4)*5;
458 // calculate the source pointer in the encoded data
459 // f8DtaPtr was set to the end of the whole data buffer
460 // f32DtaPtr is behind the payload after decoding
461 Byte_t* pSrc=f8DtaPtr-fSize+(fkN32HeaderWords*4)+position;
462 if (pSrc+5<(Byte_t*)f32DtaPtr) {
464 // check the first byte of the source buffer, has to be consistent
465 // with the 8 LSBs of the decoded 10 bit word at the beginning of
466 // the current channel
467 //assert(*pSrc==fOutBuffer[currentIndex]&0xff);
468 if (*pSrc==fOutBuffer[currentIndex]&0xff) {
470 // try to verfify the length of the channel
471 UInt_t lenCheck=*(pSrc+iCopy+2)|(*(pSrc+iCopy+3)&0x3)<<8;
472 if (lenCheck==fNAltro10bitWords) {
474 // copy including the 40 bit altro trailer
476 if (iCopy<=bufferSize) {
478 // copy to the end of the buffer
479 Byte_t* pTgt=pBuffer+bufferSize-iCopy;
480 memcpy(pTgt, pSrc, iCopy);
482 AliError(Form("target buffer too small: available %d, required %d", bufferSize, iCopy));
486 AliWarning(Form("format error: can not reproduce channel length: expected %d, read %d", fNAltro10bitWords, lenCheck));
490 AliError(Form("first byte of encoded data (%#x at %d) does not match decoded word (%#x at %d)", *pSrc, position, fOutBuffer[currentIndex]&0xff, currentIndex));
494 AliError(Form("buffer size missmatch: payload ends at %p, but current channel pretends to end at %p", f32DtaPtr, pSrc+5));
498 AliError(Form("current position does not match a byte: currentIndex=%d", currentIndex));
505 Bool_t AliAltroDecoder::GetRCUTrailerData(UChar_t*& data) const
507 // Provide a pointer to RCU trailer.
508 // The type of the parameter might not be optimal, but the function has
509 // been chosen that way to be similar to the counterpart in
510 // AliAltroRawStream.
511 // @return kTRUE if trailer available;
512 if (!f8DtaPtr) return kFALSE;
513 data=f8DtaPtr-(fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
514 assert((UChar_t*)f32DtaPtr == data);
518 Int_t AliAltroDecoder::GetRCUTrailerSize() const
520 // Provide size of RCU trailer.
521 if (!f8DtaPtr) return 0;
522 assert(fSize>(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
523 return fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t));