ALIROOT-5433 Transition to CDHv3 in HLT
[u/mrichter/AliRoot.git] / HLT / TPCLib / HWCFemulator / AliHLTTPCHWCFSupport.cxx
1 // $Id$
2 //****************************************************************************
3 //* This file is property of and copyright by the ALICE HLT Project          * 
4 //* ALICE Experiment at CERN, All rights reserved.                           *
5 //*                                                                          *
6 //* Primary Authors: Sergey Gorbunov, Torsten Alt                            *
7 //* Developers:      Sergey Gorbunov <sergey.gorbunov@fias.uni-frankfurt.de> *
8 //*                  Torsten Alt <talt@cern.ch>                              *
9 //*                  for The ALICE HLT Project.                              *
10 //*                                                                          *
11 //* Permission to use, copy, modify and distribute this software and its     *
12 //* documentation strictly for non-commercial purposes is hereby granted     *
13 //* without fee, provided that the above copyright notice appears in all     *
14 //* copies and that both the copyright notice and this permission notice     *
15 //* appear in the supporting documentation. The authors make no claims       *
16 //* about the suitability of this software for any purpose. It is            *
17 //* provided "as is" without express or implied warranty.                    *
18 //****************************************************************************
19
20 //  @file   AliHLTTPCHWCFSupport.cxx
21 //  @author Sergey Gorbunov <sergey.gorbunov@fias.uni-frankfurt.de>
22 //  @author Torsten Alt <talt@cern.ch> 
23 //  @brief  Input interfaces for FPGA ClusterFinder Emulator for TPC
24 //  @brief  ( see AliHLTTPCHWCFEmulator class )
25 //  @note
26
27
28 #include "AliHLTTPCHWCFSupport.h"
29 #include "AliHLTDataTypes.h"
30 #include "AliHLTTPCMapping.h"
31 #include "AliHLTTPCDigitReaderUnpacked.h"
32 #include "AliHLTTPCTransform.h"
33 #include "AliHLTTPCDefinitions.h"
34 #include "AliHLTCDHWrapper.h"
35 #include "AliHLTTPCHWCFEmulator.h"
36 #include "AliTPCcalibDB.h"
37 #include "AliTPCCalPad.h"
38 #include "AliTPCCalROC.h"
39 #include "TMath.h"
40
41 #include <cstdlib>
42 #include <algorithm>
43 #include <cerrno>
44 #include <sys/time.h>
45
46 using namespace std;
47
48 AliHLTTPCHWCFSupport::AliHLTTPCHWCFSupport()
49   : 
50   AliHLTLogging(),
51   fEventMemory(0),
52   fEventMCMemory(0)
53 {
54   // see header file for class documentation
55   for( int i=0; i<fgkNSlices; i++ )
56     for( int j=0; j<fgkNPatches; j++ ) fMapping[i][j] = 0;
57 }
58
59
60 AliHLTTPCHWCFSupport::~AliHLTTPCHWCFSupport()
61 {
62   // see header file for class documentation
63   for( int i=0; i<fgkNSlices; i++ )
64     for( int j=0; j<fgkNPatches; j++ ) delete[] fMapping[i][j];
65   ReleaseEventMemory(); 
66 }
67
68 AliHLTTPCHWCFSupport::AliHLTTPCHWCFSupport(const AliHLTTPCHWCFSupport&)
69   : 
70   AliHLTLogging(),
71   fEventMemory(0),
72   fEventMCMemory(0)
73 {
74   // dummy
75 }
76
77 AliHLTTPCHWCFSupport& AliHLTTPCHWCFSupport::operator=(const AliHLTTPCHWCFSupport&){
78   // dummy
79   return *this;
80 }
81
82
83 void AliHLTTPCHWCFSupport::ReleaseEventMemory()
84 {
85   // clean up 
86   if( fEventMemory ) delete[] fEventMemory;
87   if( fEventMCMemory )delete[] fEventMCMemory;
88   fEventMemory = 0;
89   fEventMCMemory = 0;
90 }
91
92
93 const AliHLTUInt32_t *AliHLTTPCHWCFSupport::GetMapping( int slice, int patch )
94
95   // see header file for class documentation
96   if( slice<0 || slice>=fgkNSlices ){
97     HLTFatal("Wrong slice number %d, no mapping is provided.", slice);
98     return 0;
99   }
100   if( patch<0 || patch>= fgkNPatches ){
101     HLTFatal("Wrong patch number %d, no mapping is provided.", patch);
102     return 0;
103   }
104   if( !fMapping[slice][patch] ) fMapping[slice][patch] = ReadMapping(slice,patch);
105 return fMapping[slice][patch];
106 }
107
108
109 AliHLTUInt32_t *AliHLTTPCHWCFSupport::ReadMapping( int slice, int patch, const char *mappingFileName ) const
110 {
111   // Create mapping array for one patch 
112   // If no mapping file provided, reads from default file
113   // Output: mapping [] array of type AliHLTUInt32_t, where :
114   //
115   // mapping[0] == N hardware adresses in the array (mapping size is maping[0] + 1 )
116   // mapping[hwAddress] == configWord
117   //
118   // configWord consist of:
119   //
120   // bits 0-7: pad number
121   // bits 8-13: row number
122   // bit  14 : flag for border pad
123   // bit  15 : is the pad active
124   // bits 16->28 : gain calibration as 13 bit fixed point,
125   //               with 1 bit position before decimal point
126
127   const AliHLTUInt32_t  kBorderFlag = (1 << 14); 
128   const AliHLTUInt32_t  kActiveFlag = (1 << 15); 
129   
130   if( slice<0 || slice>=fgkNSlices ){
131      HLTFatal("Wrong slice number %d, no mapping is provided.", slice);
132      return 0;
133   }
134
135   if( patch<0 || patch>5 ){
136      HLTFatal("Wrong patch number %d, no mapping is provided.", patch);
137      return 0;
138   }
139
140   // AliHLTTPCTransform::GetFirstRow returns first row in scheme A.
141   // We have to transform to scheme B by AliHLTTPCTransform::Slice2Sector.
142
143   UInt_t offsetSchemeB=0;
144   Int_t sector = 0;
145   {
146     Int_t tmp=0;
147     AliHLTTPCTransform::Slice2Sector(slice, AliHLTTPCTransform::GetFirstRow(patch),
148                                      sector, tmp);
149     offsetSchemeB = (UInt_t) tmp;
150   }
151   
152
153   AliTPCcalibDB *calib = AliTPCcalibDB::Instance();  
154   AliTPCCalPad * gainTPC = 0;
155   AliTPCCalROC * gainROC = 0;
156   if( calib ) gainTPC = calib->GetPadGainFactor();
157   if( gainTPC ) gainROC = gainTPC->GetCalROC(sector);  // pad gains per given sector
158   else{      
159     HLTWarning("No TPC gain calibration found");  
160   }
161
162   TString filename;
163   
164   if( mappingFileName ){
165     filename = mappingFileName;
166   } else {
167     const char* basePath=getenv("ALICE_ROOT");
168     if (basePath) filename.Form("%s/TPC/mapping/Patch%d.data", basePath,patch);    
169   } 
170   
171   ifstream inFile;
172   inFile.open(filename.Data());
173   if (!inFile) {
174     HLTFatal("Unable to open mapping file: %s   This means no mapping is provided.", filename.Data());
175     return 0;
176   }
177
178
179   AliHLTUInt32_t *mapping = 0; 
180   AliHLTUInt32_t *rowBranchPadHw = 0;
181   bool err = 1;
182   do{
183
184     UInt_t nHWAdd=0;
185     UInt_t maxHWAdd=0;
186
187     if( !(inFile >> nHWAdd ) || !(inFile >> maxHWAdd)  ){
188       HLTError("Mapping file for patch %d corrupted &s", patch,filename.Data());
189       break;
190     }
191
192     if( maxHWAdd > 0xFFF ){
193       HLTError("Max hardware address exceeded for patch %d, max number is %d, number from mapping file is %d.",patch, 0xFFF, maxHWAdd+1);       
194       break;
195     }
196
197     if(nHWAdd > maxHWAdd ){
198       HLTError("Too large number of hardware addresses for patch %d: max number is %d, number from mapping file is %d.",patch, maxHWAdd, nHWAdd );
199       break;
200     }
201       
202     mapping = new AliHLTUInt32_t[maxHWAdd+2];
203     rowBranchPadHw = new AliHLTUInt32_t[nHWAdd];
204     if( !mapping || !rowBranchPadHw ){
205       HLTError("Can not allocate &d bytes of memory", (maxHWAdd+1+nHWAdd)*sizeof(AliHLTUInt32_t));
206       break;
207     }
208
209     for( unsigned int i=0; i<maxHWAdd+2; i++ ) mapping[i] = 0;
210     for( unsigned int i=0; i<nHWAdd; i++ ) rowBranchPadHw[i] = 0;    
211     mapping[0] = maxHWAdd+1;
212     UInt_t nRead = 0;
213     err = 0;
214     while(!err ){
215       UInt_t hwAdd=0;
216       UInt_t row=0;
217       UInt_t pad=0;
218       if( !(inFile>>hwAdd) || !(inFile>>row) || !(inFile>>pad) ) break;      
219
220       err = 1;
221
222       if ( nRead >= nHWAdd ){
223         HLTError("Too many hardware addresses: %d, expected %d, mapping file %s corrupted?", nRead+1,  nHWAdd, filename.Data());
224         break;
225       }
226       if (hwAdd>maxHWAdd) {
227         HLTError("hardware address exceeds max hwAddress %d, mapping file %s corrupted?", maxHWAdd, filename.Data());   
228         break;
229       }
230
231       if( row < offsetSchemeB ){
232         HLTError("row number %d below minimum %d for patch %d, mapping file %s corrupted?", row, offsetSchemeB, patch, filename.Data());        
233         break;    
234       } 
235
236       row -= offsetSchemeB;
237         
238       if( row > 0x3F ){
239         HLTError("row number %d withing patch exceed the maximum %d for patch %d, mapping file %s corrupted?", row, 0x3F, patch, filename.Data());      
240         break;    
241       }
242
243       if( pad > 0xFF ){
244         HLTError("pad number %d exceed the maximum %d for patch %d, mapping file %s corrupted?", pad, 0xFF, patch, filename.Data());    
245         break;    
246       }
247
248       bool active = true; // Currently all channels are always active   
249       //
250
251       AliHLTFloat64_t gain = 1.;
252       if( gainROC ){
253         gain = gainROC->GetValue(offsetSchemeB+row,pad);
254         if( gain>1.e-4 ) gain = 1./gain;
255         else gain = 0;
256       }
257       gain*= (1<<12);
258       AliHLTUInt32_t  gainCalib = TMath::Nint(gain); 
259       if( gainCalib > 0x1FFF ) gainCalib = 0x1FFF;
260
261       AliHLTUInt32_t configWord = ( (row & 0x3F) << 8 ) | (pad & 0xFF);
262       if ( active ) configWord |= kActiveFlag;
263       configWord |= (gainCalib & 0x1FFF) << 16; 
264
265       mapping[1+hwAdd] = configWord;
266         
267       AliHLTUInt32_t branch = (hwAdd >> 11) & 0x1;      
268       rowBranchPadHw[nRead] = (row<<25) | (branch<<24) | (pad<<16) | hwAdd;
269
270       nRead++;
271       err = 0;
272     }
273     
274     if( err ) break;
275     
276     if ( nRead!= nHWAdd ){
277       HLTError("Too less hardware addresses: %d, expected %d, mapping file %s corrupted?", nRead,  nHWAdd, filename.Data());
278       err = 1;
279       break;
280     }
281     
282     // mark pads at borders of A/B branches 
283       
284     std::sort(rowBranchPadHw, rowBranchPadHw + nHWAdd);
285     int rowBranchLast = -1;
286     for( unsigned int i=0; i<nHWAdd; i++ ){
287       int rowBranch = rowBranchPadHw[i]>>24;
288       if( rowBranch != rowBranchLast ){
289         mapping[1+(rowBranchPadHw[i] & 0xFFF)] |= kBorderFlag;
290         rowBranchLast = rowBranch;
291         if( i>0 ) mapping[1+(rowBranchPadHw[i-1] & 0xFFF)] |= kBorderFlag;        
292       }
293     }
294     mapping[1+(rowBranchPadHw[nRead-1] & 0xFFF)] |= kBorderFlag;
295     
296   } while(0);
297   
298   inFile.close();
299
300   delete[] rowBranchPadHw;
301
302   if( err ){
303     delete[] mapping; 
304     return 0;
305   }
306   return mapping;
307 }
308
309
310 int AliHLTTPCHWCFSupport::CreateRawEvent
311 ( const AliHLTComponentBlockData* block, 
312   const AliHLTUInt32_t *&rawEvent, AliHLTUInt32_t &rawEventSize32, 
313   const AliHLTTPCClusterMCLabel *&mcLabels,  AliHLTUInt32_t &nMCLabels 
314 )
315 {
316   // the method creates TPC raw data out of the input block
317   // MC labels are provided if possible  
318   //
319
320   ReleaseEventMemory();
321   
322   rawEvent = 0;
323   rawEventSize32 = 0;
324   mcLabels = 0;
325   nMCLabels = 0;
326       
327   if( block->fPtr==NULL ){
328     HLTWarning("NULL pointer to the data block");
329     return 0;
330   }
331
332   Int_t slice = AliHLTTPCDefinitions::GetMinSliceNr( *block );
333   Int_t patch = AliHLTTPCDefinitions::GetMinPatchNr( *block );
334   AliHLTTPCMapping mapping(patch);
335
336   const char *str=Form("slice %d patch %d:", slice, patch);
337
338   if ( block->fDataType == (kAliHLTDataTypeDDLRaw | kAliHLTDataOriginTPC) )
339     {    
340       // already raw format -> only set the pointers and estimate the size
341
342       // read CDH header, estimate size of the data 
343       AliHLTCDHWrapper cdhHeader(block->fPtr);
344
345       AliHLTUInt64_t headerSize = cdhHeader.GetHeaderSize();
346  
347       AliHLTUInt64_t blockSize = block->fSize; // size of the raw data in bytes      
348
349       if( cdhHeader.GetDataSize()!=0xFFFFFFFF ){ // use size information from the header
350         blockSize = cdhHeader.GetDataSize();
351         if( blockSize > block->fSize ){
352           HLTWarning("%s Could not find a valid DDL header!",str);
353           return 0;
354         }
355       }
356       
357       if( blockSize < headerSize ){
358         HLTWarning("%s Buffer size is smaller than CDH header size", str);
359         return 0;
360       }
361       
362       rawEvent = reinterpret_cast<AliHLTUInt32_t*> (reinterpret_cast<UChar_t*>(block->fPtr)+headerSize);
363       rawEventSize32 = ( blockSize - headerSize )/sizeof(AliHLTUInt32_t);
364
365     }
366   else if ( block->fDataType == AliHLTTPCDefinitions::fgkUnpackedRawDataType )
367     {
368
369       AliHLTTPCDigitReaderUnpacked digitReader;          
370       digitReader.SetUnsorted(kTRUE);      
371       
372       if( digitReader.InitBlock(block->fPtr,block->fSize,patch,slice)<0 ) {
373         HLTWarning("failed setting up digit reader (InitBlock)");
374         return 0;
375       }
376
377       int nDigitsTotal = 0;
378       int nBunchesTotal = 0;
379      
380       while( digitReader.NextChannel() ){
381         while(digitReader.NextBunch()){
382           nBunchesTotal++;
383           nDigitsTotal+=digitReader.GetBunchSize();
384         }
385       }
386       
387       digitReader.Reset();
388
389       if( digitReader.InitBlock(block->fPtr,block->fSize,patch,slice)<0) {
390         HLTWarning("failed setting up digit reader (InitBlock)");
391         return 0;
392       }
393       
394       Int_t nPadsTotal = 0;
395       Int_t firstRow = AliHLTTPCTransform::GetFirstRow(patch);
396       Int_t nRows = AliHLTTPCTransform::GetNRows(patch);
397
398       for( int i=0; i<nRows; i++ ){
399         nPadsTotal += AliHLTTPCTransform::GetNPads(firstRow+i); 
400       }
401
402       AliHLTUInt32_t totalSize32 = (nDigitsTotal + nBunchesTotal*2)/3+2*nPadsTotal + 10;
403       AliHLTUInt32_t totalNMC = nDigitsTotal + 10;
404       
405       fEventMemory = new AliHLTUInt32_t[totalSize32];
406       if( !fEventMemory ){
407         HLTWarning("Not enougth memory: can not allocate %d bytes",totalSize32*8);
408         return 0;
409       }
410
411       fEventMCMemory = new AliHLTTPCClusterMCLabel[totalNMC];
412       if( !fEventMCMemory ){
413         HLTWarning("Not enougth memory: can not allocate %d bytes",totalNMC*sizeof(AliHLTTPCClusterMCLabel));
414         delete[] fEventMemory;
415         fEventMemory = 0;
416         return 0;
417       }
418
419       AliHLTUInt32_t nWords32 = 0;
420       AliHLTUInt32_t mcIndex = 0;
421       int err=0;
422
423       AliHLTTPCDigitData tmpDigit;
424       tmpDigit.fTrackID[0] = -1;
425       tmpDigit.fTrackID[1] = -1;
426       tmpDigit.fTrackID[2] = -1;
427
428       while( !err && digitReader.NextChannel() ){
429         
430         Int_t row=digitReader.GetRow();
431         Int_t pad=digitReader.GetPad();
432
433         AliHLTUInt32_t hwAddr = mapping.GetHwAddress(row, pad);
434
435         // create header
436
437         if( nWords32 >= totalSize32){ err = 1; break; } 
438         
439         AliHLTUInt32_t *header = fEventMemory + nWords32;
440         nWords32++;
441
442         int seek10 = 2;
443         int prevTime = 10000000;
444         int nWords10 = 0;
445         while(digitReader.NextBunch()){
446
447           if( hwAddr > 0xFFF ) continue;
448
449           Int_t nSignals = digitReader.GetBunchSize();
450           if( nSignals <=0 ){
451             HLTWarning("Empty bunch received");
452             continue;
453           }
454
455           Int_t time = digitReader.GetTime() + nSignals-1;
456           
457           if( time-nSignals+1<0 || time>=AliHLTTPCTransform::GetNTimeBins() ){
458             HLTWarning("Wrong time bins received: %d-%d for row %d pad %d", time-nSignals+1, time, row, pad);
459             break;
460           }
461
462           if( time >= prevTime ){
463             HLTWarning("Unexpected order of TPC bunches in row %d, pad %d", row, pad);      
464             break;
465           }
466
467           prevTime = time-nSignals+1;
468           
469           if( nWords32+( 2+nSignals)/3+1 >= totalSize32 ){ err = 1; break; }
470           if( mcIndex + nSignals   >= totalNMC ){ err = 1; break; }
471
472           if( nWords10 + 2 + nSignals > 0x3FF ){
473             HLTWarning("Too much data in row %d, pad %d", row, pad);        
474             break;
475           }
476
477           nWords10 += 2 + nSignals;
478
479           Add10Word( nWords32, seek10, nSignals + 2 );
480           Add10Word( nWords32, seek10, time );
481           
482           const UInt_t *bunchData = digitReader.GetSignals();
483           const AliHLTTPCDigitData *mcDigits = digitReader.GetBunchDigits();
484           if( !mcDigits ){
485             HLTWarning("No MC labels found for a bunch of digits");
486           }
487
488           for(Int_t is=nSignals-1; is>=0; is--){
489             Add10Word( nWords32, seek10, bunchData[is] );           
490             const AliHLTTPCDigitData &digit = mcDigits ?mcDigits[is] :tmpDigit;
491             int nmc = 0;
492             for( int i=0; i<3; i++ ) if( digit.fTrackID[i] >=0 ) nmc++;      
493             for( int i=0; i<3; i++ ){
494               fEventMCMemory[mcIndex].fClusterID[i].fMCID = digit.fTrackID[i];
495               fEventMCMemory[mcIndex].fClusterID[i].fWeight = 0;
496               if( digit.fTrackID[i] >=0 ){                      
497                 fEventMCMemory[mcIndex].fClusterID[i].fWeight  = ((float)bunchData[is])/nmc;
498               }
499             }     
500             mcIndex++;
501           }       
502
503         } // bunches
504         
505       *header = (1<<30) | ((nWords10&0x3FF)<<16) | (hwAddr & 0xFFF);
506
507       }// channels (pads)
508
509       if( err ){
510         HLTError("Internal error: too less memory allocated");  
511       } else {
512         for( AliHLTUInt32_t i=0; i<nWords32; i++ ) fEventMemory[i] = AliHLTTPCHWCFEmulator::WriteBigEndian(fEventMemory[i]);
513         rawEvent = fEventMemory;
514         rawEventSize32 = nWords32;
515         mcLabels = fEventMCMemory;
516         nMCLabels = mcIndex;
517       }
518
519     } // unpacked data type
520
521   return 0;
522 }
523
524
525 void AliHLTTPCHWCFSupport::Add10Word( AliHLTUInt32_t &nWords32, int &seek10, UInt_t data )
526 {
527   // add 10-bit data to the 32-bit word
528   // fEventMemory [nWords32] --- current 32-bit word
529   // *seek10 --- 10-bit position withing the word
530   // pointers are increased, a new word is first initialised to 0
531
532   data = data & 0x3FF; // truncate to 10 bits
533
534   if( seek10 == 2 ){
535     nWords32++;
536     fEventMemory[nWords32-1] = data<<20;
537     seek10 = 1;
538   } else if( seek10 == 1 ){
539     fEventMemory[nWords32-1] &= 0xFFF003FF;
540     fEventMemory[nWords32-1] |= (data<<10);
541     seek10 = 0;
542   } else if( seek10 == 0 ){
543     fEventMemory[nWords32-1] &= 0xFFFFFC00;
544     fEventMemory[nWords32-1] |= data;
545     seek10 = 2;
546   } 
547 }
548
549
550
551 int AliHLTTPCHWCFSupport::CheckRawData( const AliHLTUInt32_t *buffer,
552                                                    unsigned long bufferSize32, int patch, int slice )
553 {
554   //
555   // The procedure checks consistency of the data
556   //
557
558
559   if (!buffer) return 0;
560
561   AliHLTCDHWrapper cdh((void*)buffer);
562   const unsigned int headerSize32 = cdh.GetHeaderSize()/4;
563
564   const char *str=Form("slice %d patch %d:", slice, patch);
565   
566   if( bufferSize32 < headerSize32 ){
567     HLTWarning("%s Buffer size is smaller than CDH header size", str);
568     return kFALSE;
569   }    
570   
571   // read data header 
572  
573   AliHLTUInt32_t blockSize32 = bufferSize32; // size of the raw data in words
574
575   if( buffer[0]!=0xFFFFFFFF ) blockSize32 = buffer[0]/4; // use size information from the header  
576   if( blockSize32 > bufferSize32 ){  
577     HLTWarning(Form("%s Could not find a valid DDL header!",str));
578     return 0;
579   }
580   
581   UChar_t rcuVer = (UChar_t)( (buffer[1] >> 24) & 0xFF ); 
582
583   if (rcuVer < 2) {
584     HLTWarning("%s Old data format, RCU version %d", str,rcuVer);
585     return 0;
586   }
587
588   // is the block valid
589   //AliHLTUInt32_t blockAttributes = buffer[3]; // block attributes (bits 24-31) and participating sub detectors 
590   //cout<<blockAttributes<<" "<<(blockAttributes >> 24)<<endl;
591   //if ( !( (blockAttributes >> 24) & 1) ) return 0; 
592      
593
594   const AliHLTUInt32_t* fData = buffer + headerSize32;
595   unsigned long  dataSize32 = blockSize32 - headerSize32;       
596   
597   // Read the RCU trailer according to the RCU formware version specified in CDH
598   // Cross-check with version found in the trailer
599   // The two major bit should be 11 (identifies the end of the trailer)    
600   
601   AliHLTUInt32_t word = fData[dataSize32 - 1];
602   
603   if ((word >> 30) != 3) {
604     HLTWarning("%s Last RCU trailer word not found!", str);
605     return 0;
606   }
607   
608   UChar_t ver = (word >> 16) & 0xFF;
609   //AliHLTUInt32_t rcuId = (Int_t)((word >> 7) & 0x1FF);
610   AliHLTUInt32_t rcuTrailerSize32 = (word & 0x7F); // size of RCU trailer data in words
611   
612   if (ver != rcuVer) {
613     HLTWarning("%s Wrong RCU firmware version detected: %d != %d",
614                str,ver,rcuVer);
615     return 0;
616   }  
617
618   if (rcuTrailerSize32 < 2) {
619     HLTWarning(Form("Invalid trailer size found (%d bytes) !",
620                     rcuTrailerSize32*4));
621     return 0;
622   }
623   
624   if( rcuTrailerSize32 > dataSize32 ){
625     HLTWarning(Form("%s Invalid trailer size found (%d bytes) ! The size is bigger than the raw data size (%ld bytes)!",
626                     str, rcuTrailerSize32*4,dataSize32*4));
627     return 0;    
628   }
629
630   // check the trailer
631
632   Int_t trailerIndex = dataSize32 - rcuTrailerSize32;
633
634   for( unsigned int i=trailerIndex; i<dataSize32-1; i++){
635     if ((fData[i] >> 30) != 2) {
636       HLTWarning("%s Missing RCU trailer identifier pattern!",str);
637       continue;
638     }
639   }
640
641   // Read the payload size  
642  
643   Int_t  rcuPayloadSize32 = fData[trailerIndex] & 0x3FFFFFF;
644
645   if ( rcuPayloadSize32 + rcuTrailerSize32  != dataSize32) {
646     HLTWarning(Form("%s Inconsistent raw data size ! Raw data size - %ld bytes (from CDH), RCU trailer - %d bytes, raw data size (from RCU trailer) - %d bytes !",
647                     str, dataSize32*4,
648                     (rcuTrailerSize32)*4,
649                     rcuPayloadSize32*4));
650     return 0;
651   }
652     
653   
654   //AliHLTTPCMapping *mapping = new AliHLTTPCMapping(patch);
655   const int kMaxNTimeBins = 2000;
656
657   UShort_t  *channelData10 = new UShort_t[kMaxNTimeBins];    // cache for the decoded altro payload
658
659   Int_t position = 0; // current position (32-bit words) in fData
660  
661   while(1){
662
663     // Search for the next Altro channel
664
665     word = 0;
666     while( position < rcuPayloadSize32 ){
667       word = fData[position++];
668       if( (word >> 30) == 1) break;
669     }
670     if (position >= rcuPayloadSize32 ) break; // no next channel found
671     
672     // extract channel payload and hw address
673
674     Int_t channelPayloadSize10 = (word >> 16) & 0x3FF; // payload size in 10-bit words 
675     Int_t channelPayloadSize32 = (channelPayloadSize10+2)/3;
676     Bool_t channelIOErrors = (word >> 29) & 0x1; // check for readout errors    
677     Short_t  channelHWAddress = word & 0xFFF;
678
679     if( position + channelPayloadSize32-1> rcuPayloadSize32 ){
680       HLTWarning(Form("%s Inconsistent channel payload data size: expected <= %d bytes from RCU trailer, found %d bytes in the channel header!",
681                       str,(rcuPayloadSize32 - position)*4, channelPayloadSize32*4 ));
682       continue;
683     }
684
685     //bool channelBranchAB = ((channelHWAddress >> 11) & 0x1);
686     // int channelFEC       = ((channelHWAddress >> 7) & 0xF); // front-end card index
687     //int channelAltro = ((channelHWAddress >> 4) & 0x7); // altro chip index
688     //int channelIndex = (channelHWAddress & 0xF); // channel index
689     //int channelRow = mapping->GetRow(channelHWAddress);
690     //int channelPad = mapping->GetPad(channelHWAddress);
691
692     // Now unpack the Altro data: 10-bit words to 16 bit-words    
693     
694     Int_t channelData10Index = 0;// current position in the payload
695
696     for (Int_t iword = 0; iword < channelPayloadSize32; iword++) {
697       word = fData[position++];
698       if ((word >> 30) != 0) {
699         HLTWarning(Form("%s Unexpected end of payload in altro channel payload! Address=0x%x, word=0x%x",
700                         str, channelHWAddress,word));
701         channelIOErrors = 1;
702         position--;
703         break;
704       }
705       channelData10[channelData10Index++] = (word >> 20) & 0x3FF;
706       channelData10[channelData10Index++] = (word >> 10) & 0x3FF;
707       channelData10[channelData10Index++] = word & 0x3FF;
708     }
709   
710     if ( channelIOErrors ) continue;    
711
712     // read bunches
713
714     Int_t prevTimeBin =  1024;
715     channelData10Index = 0;
716
717     while(1){
718       
719       // Read next Altro bunch 
720   
721       if ((channelData10Index+1 >= channelPayloadSize10) ) break;
722     
723       Int_t bunchLength = channelData10[channelData10Index++];
724       Int_t bunchStartTimeBin = channelData10[channelData10Index++];
725
726       if (bunchLength <= 2) {
727         // Invalid bunch size
728         HLTWarning(Form("%s Too short bunch length (%d) in Address=0x%x!",
729                         str, bunchLength,channelHWAddress));    
730         break;
731       }
732       if( channelData10Index + bunchLength - 2 > channelPayloadSize10 ){
733         // Too long bunch detected
734         HLTWarning(Form("%s Too long bunch detected in Address=0x%x! Expected <= %d 10-bit words, found %d !",
735                         str,channelHWAddress,channelPayloadSize10-channelData10Index,bunchLength));
736         break;
737       }
738             
739       if( bunchStartTimeBin-bunchLength+1 < 0) {
740         HLTWarning(Form("%s Invalid start time-bin in Address=0x%x ! (%d-%d+1) < 0",
741                         str,channelHWAddress,bunchStartTimeBin,bunchLength));
742         break;
743       }
744       if (bunchStartTimeBin >= prevTimeBin) {
745         HLTWarning(Form("%s Invalid start time-bin in Address=0x%x! (%d>=%d)",
746                         str,channelHWAddress,bunchStartTimeBin,prevTimeBin));
747         break;
748       }
749
750       prevTimeBin = bunchStartTimeBin-bunchLength+1;
751   
752       bunchLength -= 2;
753         
754       //UShort_t* bunchData = &channelData10[channelData10Index];   // pointer to the current bunch samples
755       channelData10Index += bunchLength;            
756     }
757   }
758   
759   delete[] channelData10;
760   //delete mapping;
761
762   return 1;
763 }
764