]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliAltroDecoder.cxx
Coverity fix.
[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   // 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
163 Bool_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
239 Int_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
268 Float_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
283 void 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
303 int 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
385 void 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
439 void 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
485 Int_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
563 Bool_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
576 Int_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 }