Update of the fast altro decoder (Per Thomas)
[u/mrichter/AliRoot.git] / RAW / AliAltroDecoder.cxx
CommitLineData
86525f0f 1// $Id$
2
31a920d3 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> *
86525f0f 8 * Oystein Djuvsland <oystein.djuvsland@gmail.com> *
31a920d3 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
86525f0f 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>
31a920d3 27#include <Riostream.h>
28#include "AliAltroDecoder.h"
29#include "AliAltroData.h"
86525f0f 30#include "AliLog.h"
31a920d3 31
ac672c4c 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.
86525f0f 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
ac672c4c 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
86525f0f 40// last altro channel of the back linked list, the next call the second last channel ..etc until
41// all channels are read.
ac672c4c 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
31a920d3 47ClassImp(AliAltroDecoder)
48
49AliAltroDecoder::AliAltroDecoder() : f32DtaPtr(0),
ebf7cafe 50 f8DtaPtr(0),
ac672c4c 51 fkN32HeaderWords(8),
ebf7cafe 52 fN40AltroWords(0),
53 fN40RcuAltroWords(0),
54 fNDDLBlocks(0),
55 f32LastDDLBlockSize(5),
86525f0f 56 f8PayloadSize(0),
ebf7cafe 57 fOutBufferIndex(0),
58 fSize(0),
59 fNAltro10bitWords(0),
60 fComplete(0),
61 fInComplete(0),
62 fDecodeIfCorruptedTrailer(kTRUE),
63 fIsDecoded(kFALSE),
44443c72 64 fIsFatalCorruptedTrailer(kTRUE)
65 // fIsFirstChannelOfPayload(kTRUE)
31a920d3 66{
ac672c4c 67 // Default constructor
31a920d3 68}
69
70
71AliAltroDecoder::~AliAltroDecoder()
72{
ac672c4c 73 // Default destructor
31a920d3 74}
75
76
ac672c4c 77Bool_t AliAltroDecoder::CheckPayloadTrailer() const
31a920d3 78{
86525f0f 79 //Check consistency between the number of 40 bit altro words given by
ac672c4c 80 //the RCU payload and the number of 40 bit words calculated from the size of the RCU payload.
81
31a920d3 82 if(fN40AltroWords != fN40RcuAltroWords)
83 {
84 return kFALSE;
85 }
86 else
87 {
88 return kTRUE;
89 }
90}
91
92
93Bool_t AliAltroDecoder::Decode()
ebf7cafe 94{
95 if( fIsFatalCorruptedTrailer == kTRUE)
31a920d3 96 {
987d6d62 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");
ebf7cafe 99 return kFALSE;
100 }
817c796a 101 else if (!f8DtaPtr || !f32DtaPtr ||
102 (UChar_t*)f32DtaPtr < f8DtaPtr-fSize ||
103 (UChar_t*)f32DtaPtr > f8DtaPtr)
104 {
105 return kFALSE;
106 }
ebf7cafe 107 else
31a920d3 108 {
ebf7cafe 109 // see header file for class documentation
110 fComplete = 0;
111 fInComplete = 0;
112
ac672c4c 113 Int_t tmpcnt = CountAAApaddings();
31a920d3 114
ebf7cafe 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 }
31a920d3 127
ebf7cafe 128 if( ((CheckPayloadTrailer() == kTRUE) || fDecodeIfCorruptedTrailer == kTRUE ) && (fSize > 32) )
31a920d3 129 {
ebf7cafe 130 fOutBufferIndex = 0;
131
132 for(Int_t i = 0; i < fNDDLBlocks; i++)
133 {
134 DecodeDDLBlock();
135 }
31a920d3 136
ebf7cafe 137 DecodeLastDDLBlock();
138 fOutBufferIndex = fN40AltroWords*4 - 1;
ebf7cafe 139 fIsDecoded = kTRUE;
140 return kTRUE;
141 }
142
143 else
144 {
987d6d62 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;
ebf7cafe 149 return kFALSE;
150 }
49f90cc3 151
31a920d3 152 }
153}
154
155
44443c72 156
157
31a920d3 158Bool_t AliAltroDecoder::NextChannel(AliAltroData *altroDataPtr)
159{
ebf7cafe 160 if(fIsFatalCorruptedTrailer == kTRUE)
31a920d3 161 {
ebf7cafe 162 return kFALSE;
163 }
164
165 else
31a920d3 166 {
31a920d3 167
ebf7cafe 168 if(fIsDecoded != kTRUE)
169 {
ebf7cafe 170 Decode();
171 }
31a920d3 172
86525f0f 173 if(fOutBufferIndex >= 7)
31a920d3 174 {
ebf7cafe 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 --;
44443c72 189 altroDataPtr->SetHadd( ((fOutBuffer[fOutBufferIndex] & 0x3)) << 10 | ( fOutBuffer[fOutBufferIndex-1] ), fOutBufferIndex);
ebf7cafe 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 }
84111923 201
49f90cc3 202 if(fOutBufferIndex >= 0)
84111923 203 {
84111923 204 altroDataPtr->SetData( &fOutBuffer[fOutBufferIndex] );
49f90cc3 205 if(fOutBufferIndex > 0) fOutBufferIndex --;
84111923 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 }
86525f0f 214
31a920d3 215 }
216 else
217 {
ebf7cafe 218 return kFALSE;
31a920d3 219 }
220
31a920d3 221 }
222}
223
31a920d3 224
ac672c4c 225Int_t AliAltroDecoder::CountAAApaddings() const
31a920d3 226{
ac672c4c 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
86525f0f 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.
ac672c4c 236
86525f0f 237 UShort_t *tailPtr= (UShort_t *)((UChar_t*)f32DtaPtr + f8PayloadSize);
31a920d3 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
254Float_t AliAltroDecoder::GetFailureRate()
255{
ac672c4c 256 // Prints to stdout the percent of altroblocks that
257 // is missing the 2aaa trailer.
258
31a920d3 259 Float_t tmp = 0;
987d6d62 260 // cout << "Number of Complete channles = " << fComplete <<endl;
261 // cout << "Number of InComplete channles = " << fInComplete <<endl;
31a920d3 262 tmp = (100*(Float_t)fInComplete)/((Float_t)fComplete + (Float_t)fInComplete);
987d6d62 263 // cout <<"There are "<< tmp <<"% incomplete channels"<<endl;
31a920d3 264 return tmp;
265}
266
267
44443c72 268
31a920d3 269void AliAltroDecoder::PrintInfo(AliAltroData &altrodata, Int_t n, Int_t nPerLine)
270{
ac672c4c 271 // prints data and address information contained in altrodata
272 // to the standard output
273
987d6d62 274 // cout << "altrodata.fDataSize = " << altrodata.GetDataSize() << endl;
275 // cout << "altrodata.fHadd = " << altrodata.GetHadd() <<endl;
31a920d3 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
ebf7cafe 289int AliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size)
31a920d3 290{
ac672c4c 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
44443c72 294 // fIsFirstChannelOfPayload = kTRUE;
295
84111923 296 if(dtaPtr == 0)
297 {
44443c72 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");
84111923 300 return -99;
301 }
302
49f90cc3 303 if (size<fkN32HeaderWords+4)
304 {
44443c72 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");
49f90cc3 307 return -99;
308 }
309
310
ebf7cafe 311 int iRet = 0;
49f90cc3 312 UInt_t tmpTrailerSize;
31a920d3 313 fIsDecoded = kFALSE;
314 f8DtaPtr =dtaPtr;
315 fSize = size;
316 f8DtaPtr =f8DtaPtr + fSize;
317 f32DtaPtr = (UInt_t *)f8DtaPtr;
49f90cc3 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
31a920d3 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 }
49f90cc3 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)
31a920d3 341 {
342 tmpTrailerSize = 1; //assume that last word is ONE, and that the this word gives the number of 40 bit altro words
343 }
49f90cc3 344 else
345 {
346 tmpTrailerSize=0;
347 fIsFatalCorruptedTrailer = kTRUE;
348 iRet = -1;
349 }
31a920d3 350
49f90cc3 351 if(tmpTrailerSize > 0 && (fkN32HeaderWords + tmpTrailerSize)*4<=fSize)
ebf7cafe 352 {
49f90cc3 353 f8PayloadSize = fSize - (fkN32HeaderWords + tmpTrailerSize)*4;
354 fN40AltroWords = f8PayloadSize/5;
355 fNDDLBlocks = fN40AltroWords/4;
356 f32LastDDLBlockSize = ((f8PayloadSize%(4*DDL_32BLOCK_SIZE))+3)/4;
357
ebf7cafe 358 f32DtaPtr = f32DtaPtr - tmpTrailerSize;
359 fN40RcuAltroWords = *f32DtaPtr;
ac672c4c 360 f32DtaPtr = (UInt_t *)dtaPtr + fkN32HeaderWords;
ebf7cafe 361 fIsFatalCorruptedTrailer = kFALSE;
ebf7cafe 362 }
817c796a 363
364 // all subsequent consistency checks depend on the correct initialization
365 // of the pointer and size variables
366 assert(f8DtaPtr == dtaPtr + fSize);
ebf7cafe 367 return iRet;
368
31a920d3 369}
370
371
372void AliAltroDecoder::DecodeDDLBlock()
373{
ac672c4c 374 //Decode one 160 bit DDL block into 16 x 16 bit integers (only least significant 10 bits are filled)
375
31a920d3 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
44443c72 420
421
422
423
424
425
31a920d3 426void AliAltroDecoder::DecodeLastDDLBlock()
427{
ac672c4c 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
44443c72 431 // if the last block does not align with 160 bits then it is padded with zeroes
ac672c4c 432
31a920d3 433 for(Int_t i=0; i < f32LastDDLBlockSize; i++)
434 {
435 fDDLBlockDummy[i] = *f32DtaPtr;
436 f32DtaPtr ++;
437 }
438
439 f32DtaPtr = fDDLBlockDummy;
31a920d3 440 DecodeDDLBlock();
86525f0f 441 f32DtaPtr=(UInt_t*)(f8DtaPtr-fSize+f8PayloadSize+fkN32HeaderWords*4);
442}
443
44443c72 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
86525f0f 472Int_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
ecc0795d 516 UInt_t lenCheck=*(pSrc+iCopy+2)|(*(pSrc+iCopy+3)&0x3)<<8;
86525f0f 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 {
ecc0795d 531 AliWarning(Form("format error: can not reproduce channel length: expected %d, read %d", fNAltro10bitWords, lenCheck));
86525f0f 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
550Bool_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
563Int_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));
31a920d3 569}