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