]> git.uio.no Git - u/mrichter/AliRoot.git/blame - RAW/AliAltroDecoder.cxx
new Preprocessor and DA from Michal
[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),
64 fIsFatalCorruptedTrailer(kTRUE)
31a920d3 65{
ac672c4c 66 // Default constructor
31a920d3 67}
68
69
70AliAltroDecoder::~AliAltroDecoder()
71{
ac672c4c 72 // Default destructor
31a920d3 73}
74
75
ac672c4c 76Bool_t AliAltroDecoder::CheckPayloadTrailer() const
31a920d3 77{
86525f0f 78 //Check consistency between the number of 40 bit altro words given by
ac672c4c 79 //the RCU payload and the number of 40 bit words calculated from the size of the RCU payload.
80
31a920d3 81 if(fN40AltroWords != fN40RcuAltroWords)
82 {
83 return kFALSE;
84 }
85 else
86 {
87 return kTRUE;
88 }
89}
90
91
92Bool_t AliAltroDecoder::Decode()
ebf7cafe 93{
86525f0f 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
97 // integers.
ac672c4c 98
ebf7cafe 99 if( fIsFatalCorruptedTrailer == kTRUE)
31a920d3 100 {
987d6d62 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");
ebf7cafe 103 return kFALSE;
104 }
105
106 else
31a920d3 107 {
ebf7cafe 108 // see header file for class documentation
109 fComplete = 0;
110 fInComplete = 0;
111
ac672c4c 112 Int_t tmpcnt = CountAAApaddings();
31a920d3 113
ebf7cafe 114 if(tmpcnt == 3)
115 {
116 fN40AltroWords = fN40AltroWords -1;
117 }
118 else if(tmpcnt == 5)
119 {
120 fN40AltroWords = fN40AltroWords -2;
121 }
122 else if(tmpcnt == 8)
123 {
124 fN40AltroWords = fN40AltroWords -3;
125 }
31a920d3 126
ebf7cafe 127 if( ((CheckPayloadTrailer() == kTRUE) || fDecodeIfCorruptedTrailer == kTRUE ) && (fSize > 32) )
31a920d3 128 {
ebf7cafe 129 // fDDLBlockCnt = 0;
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;
31a920d3 139
ebf7cafe 140 // DumpData(fOutBuffer, 400,4);
31a920d3 141
ebf7cafe 142 fIsDecoded = kTRUE;
143 return kTRUE;
144 }
145
146 else
147 {
987d6d62 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;
ebf7cafe 152 return kFALSE;
153 }
31a920d3 154
31a920d3 155 }
156}
157
158
159Bool_t AliAltroDecoder::NextChannel(AliAltroData *altroDataPtr)
160{
ac672c4c 161 // Reads the next altro channel in the RCU payload after the RCU payload
86525f0f 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.
ac672c4c 165
ebf7cafe 166 if(fIsFatalCorruptedTrailer == kTRUE)
31a920d3 167 {
987d6d62 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");
ebf7cafe 170 return kFALSE;
171 }
172
173 else
31a920d3 174 {
31a920d3 175
ebf7cafe 176 if(fIsDecoded != kTRUE)
177 {
987d6d62 178 // cout <<"AliAltroDecoder::NextChanne, WARNING, buffer was not decoded, decoding now.. "<< endl;
ebf7cafe 179 Decode();
180 }
31a920d3 181
86525f0f 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)
31a920d3 187 {
ebf7cafe 188 if((fOutBuffer[fOutBufferIndex] << 4 ) | ((fOutBuffer[fOutBufferIndex-1] & 0x3c0) >> 6) == 0x2aaa)
189 {
190 altroDataPtr->SetIsComplete(kTRUE);
191 fComplete ++;
192 }
193 else
194 {
195 altroDataPtr->SetIsComplete(kFALSE);
196 fInComplete ++;
197 }
198
199 fOutBufferIndex --;
200 fNAltro10bitWords = ( (fOutBuffer[fOutBufferIndex] & 0x3f) << 4 ) | ((fOutBuffer[fOutBufferIndex -1] & (0xF << 6)) >> 6) ;
201 fOutBufferIndex --;
202 altroDataPtr->SetHadd( ((fOutBuffer[fOutBufferIndex] & 0x3)) << 10 | ( fOutBuffer[fOutBufferIndex-1] ) );
203
204 fOutBufferIndex --;
205
206 if(fNAltro10bitWords%4 == 0)
207 {
208 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords;
209 }
210 else
211 {
212 fOutBufferIndex = fOutBufferIndex - fNAltro10bitWords -(4 - fNAltro10bitWords%4);
213 }
214
215
216 altroDataPtr->SetData( &fOutBuffer[fOutBufferIndex] );
217 fOutBufferIndex --;
218 altroDataPtr->SetDataSize( fNAltro10bitWords );
86525f0f 219
ebf7cafe 220 return kTRUE;
221
31a920d3 222 }
223 else
224 {
ebf7cafe 225 return kFALSE;
31a920d3 226 }
227
31a920d3 228 }
229}
230
31a920d3 231
ac672c4c 232Int_t AliAltroDecoder::CountAAApaddings() const
31a920d3 233{
ac672c4c 234 // Use for simulated data only.
235 // Patch for incorrectly simulated data. Counts the number of
236 // 2aaa word in the trailer of the payload and tries to figure out
237 // the correct number of 40 bit altro words in the RCU pauload
86525f0f 238 //
239 // The simulated raw data differs from the real data by a number
240 // of additional 0x2aa words between the Altro payload and the
241 // RCU trailer. This is most likely to bring the total number of
242 // bytes to a common multiple of 4 and 5.
ac672c4c 243
86525f0f 244 UShort_t *tailPtr= (UShort_t *)((UChar_t*)f32DtaPtr + f8PayloadSize);
31a920d3 245 Int_t cnt = 0;
246
247 tailPtr --;
248
249 while(*tailPtr == 0xaaaa)
250 {
251 cnt ++;
252 tailPtr --;
253 }
254
255 tailPtr = tailPtr + cnt +1;
256
257 return cnt;
258}
259
260
261Float_t AliAltroDecoder::GetFailureRate()
262{
ac672c4c 263 // Prints to stdout the percent of altroblocks that
264 // is missing the 2aaa trailer.
265
31a920d3 266 Float_t tmp = 0;
987d6d62 267 // cout << "Number of Complete channles = " << fComplete <<endl;
268 // cout << "Number of InComplete channles = " << fInComplete <<endl;
31a920d3 269 tmp = (100*(Float_t)fInComplete)/((Float_t)fComplete + (Float_t)fInComplete);
987d6d62 270 // cout <<"There are "<< tmp <<"% incomplete channels"<<endl;
31a920d3 271 return tmp;
272}
273
274
275void AliAltroDecoder::PrintInfo(AliAltroData &altrodata, Int_t n, Int_t nPerLine)
276{
ac672c4c 277 // prints data and address information contained in altrodata
278 // to the standard output
279
987d6d62 280 // cout << "altrodata.fDataSize = " << altrodata.GetDataSize() << endl;
281 // cout << "altrodata.fHadd = " << altrodata.GetHadd() <<endl;
31a920d3 282 const UInt_t* data = altrodata.GetData();
283 for(Int_t i= 0; i< n; i++)
284 {
285 if( (i%nPerLine == 0) && (i != 0) )
286 {
287 printf("\n");
288 }
289 printf("%d\t", data[i]);
290 }
291 printf("\n");
292}
293
294
ebf7cafe 295int AliAltroDecoder::SetMemory(UChar_t *dtaPtr, UInt_t size)
31a920d3 296{
ac672c4c 297 // Sets the pointer to the memory block that should be decoded
298 // Returns a negative value if an inconsistency in the data is detected
299
ebf7cafe 300 int iRet = 0;
31a920d3 301 Int_t tmpTrailerSize;
302 fIsDecoded = kFALSE;
303 f8DtaPtr =dtaPtr;
304 fSize = size;
305 f8DtaPtr =f8DtaPtr + fSize;
306 f32DtaPtr = (UInt_t *)f8DtaPtr;
307 tmpTrailerSize = *(f32DtaPtr - 1);
308
309 if(tmpTrailerSize <= MAX_TRAILER_WORDS)
310 {
311 tmpTrailerSize = tmpTrailerSize; //assume that the last word of the buffer gives the number of trailer words
312 }
313 else
314 {
315 tmpTrailerSize = 1; //assume that last word is ONE, and that the this word gives the number of 40 bit altro words
316 }
317
86525f0f 318 f8PayloadSize = fSize - (fkN32HeaderWords + tmpTrailerSize)*4;
319 fN40AltroWords = f8PayloadSize/5;
320 fNDDLBlocks = fN40AltroWords/4;
321 f32LastDDLBlockSize = ((f8PayloadSize%(4*DDL_32BLOCK_SIZE))+3)/4;
ebf7cafe 322
323 if(tmpTrailerSize > 0 && tmpTrailerSize < 5)
324 {
325 f32DtaPtr = f32DtaPtr - tmpTrailerSize;
326 fN40RcuAltroWords = *f32DtaPtr;
ac672c4c 327 f32DtaPtr = (UInt_t *)dtaPtr + fkN32HeaderWords;
ebf7cafe 328 fIsFatalCorruptedTrailer = kFALSE;
329 }
330 else
331 {
987d6d62 332 // printf("\n AliAltroDecoder::SetMemory, ERROR\n, trailer is corrupted");
ebf7cafe 333 fIsFatalCorruptedTrailer = kTRUE;
334 iRet = -1;
335 }
ebf7cafe 336
337 return iRet;
338
31a920d3 339}
340
341
342void AliAltroDecoder::DecodeDDLBlock()
343{
ac672c4c 344 //Decode one 160 bit DDL block into 16 x 16 bit integers (only least significant 10 bits are filled)
345
31a920d3 346 fOutBuffer[fOutBufferIndex] = *f32DtaPtr & 0x3ff; //s0
347 fOutBufferIndex ++;
348 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00) >> 10; //s1
349 fOutBufferIndex ++;
350 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00000) >> 20; //s2
351 fOutBufferIndex ++;
352 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xc0000000) >> 30; //s3_1
353 f32DtaPtr ++;
354 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xff) << 2); //s3_2
355 fOutBufferIndex ++;
356 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff00) >> 8; //s4
357 fOutBufferIndex ++;
358 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0000) >> 18; //s5
359 fOutBufferIndex ++;
360 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xf0000000) >> 28; //s6_1
361 f32DtaPtr ++;
362 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3f) << 4); //s6_2
363 fOutBufferIndex ++;
364 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc0) >> 6; //s7
365 fOutBufferIndex ++;
366 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0000) >> 16; //s8
367 fOutBufferIndex ++;
368 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xFC000000) >> 26; //s9_1
369 f32DtaPtr ++;
370 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0xf) << 6); //s9_2
371 fOutBufferIndex ++;
372 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff0) >> 4; //s10
373 fOutBufferIndex ++;
374 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc000) >> 14; //s11
375 fOutBufferIndex ++;
376 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xff000000) >> 24; //s12_1
377 f32DtaPtr ++;
378 fOutBuffer[fOutBufferIndex] = fOutBuffer[fOutBufferIndex] | ((*f32DtaPtr & 0x3) << 8); //s12_2
379 fOutBufferIndex ++;
380 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc) >> 2; //s13
381 fOutBufferIndex ++;
382 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0x3ff000) >> 12; //s14
383 fOutBufferIndex ++;
384 fOutBuffer[fOutBufferIndex] = (*f32DtaPtr & 0xffc00000) >> 22; //s15
385 f32DtaPtr ++;
386 fOutBufferIndex ++;
387}
388
389
390void AliAltroDecoder::DecodeLastDDLBlock()
391{
ac672c4c 392 // Decode one 160 bit DDL block into 16 integers.
393 // In order to use the same decoding function (DecodeDDLBlock())
394 // a copy of the the last DDL block is made and
395 // if the las block does not align with 160 bits then it is padded with zeroes
396
31a920d3 397 for(Int_t i=0; i < f32LastDDLBlockSize; i++)
398 {
399 fDDLBlockDummy[i] = *f32DtaPtr;
400 f32DtaPtr ++;
401 }
402
403 f32DtaPtr = fDDLBlockDummy;
31a920d3 404 DecodeDDLBlock();
86525f0f 405 f32DtaPtr=(UInt_t*)(f8DtaPtr-fSize+f8PayloadSize+fkN32HeaderWords*4);
406}
407
408Int_t AliAltroDecoder::CopyBackward(Byte_t* pBuffer, Int_t bufferSize)
409{
410 // Copy the original 10/40 bit encecoded data of the current channel.
411 // The funtions copies the data to the end of the provided buffer.
412 // @param pBuffer target buffer
413 // @param bufferSize size of target buffer
414 // @return number of copied bytes, neg. error code if failed
415 Int_t iCopy=0;
416
417 if(fIsDecoded != kTRUE) {
418 AliWarning("buffer has not been decoded, no channel data available");
419 return 0;
420 }
421
422 // This method does not need to be the fastest possible implementation
423 // For the sake of stability, there are a lot of consistency checks.
424
425 // the fOutBufferIndex always points to the next channel, since we are
426 // reading backwards, this is one byte before the start of the current
427 // channel.
428 Int_t currentIndex=fOutBufferIndex+1;
429 if (fNAltro10bitWords>0 && currentIndex < fN40AltroWords*4 ) {
430
431 // calculate the position in the encoded data, beginning right
432 // after the CDH. 10 -> 8 bit: needs 5/4 times the index
433 Int_t position=(currentIndex*5)/4;
434 if (position*4==currentIndex*5) {
435 // no of 10 bit words is without the fill words to fill complete 40 bit words
436 // in addition, align to complete 40 bit words (the '+3')
437 iCopy=((fNAltro10bitWords+3)/4)*5;
438
439 // calculate the source pointer in the encoded data
440 // f8DtaPtr was set to the end of the whole data buffer
441 // f32DtaPtr is behind the payload after decoding
442 Byte_t* pSrc=f8DtaPtr-fSize+(fkN32HeaderWords*4)+position;
443 if (pSrc+5<(Byte_t*)f32DtaPtr) {
444
445 // check the first byte of the source buffer, has to be consistent
446 // with the 8 LSBs of the decoded 10 bit word at the beginning of
447 // the current channel
448 //assert(*pSrc==fOutBuffer[currentIndex]&0xff);
449 if (*pSrc==fOutBuffer[currentIndex]&0xff) {
450
451 // try to verfify the length of the channel
ecc0795d 452 UInt_t lenCheck=*(pSrc+iCopy+2)|(*(pSrc+iCopy+3)&0x3)<<8;
86525f0f 453 if (lenCheck==fNAltro10bitWords) {
454
455 // copy including the 40 bit altro trailer
456 iCopy+=5;
457 if (iCopy<=bufferSize) {
458
459 // copy to the end of the buffer
460 Byte_t* pTgt=pBuffer+bufferSize-iCopy;
461 memcpy(pTgt, pSrc, iCopy);
462 } else {
463 AliError(Form("target buffer too small: available %d, required %d", bufferSize, iCopy));
464 iCopy=-1;
465 }
466 } else {
ecc0795d 467 AliWarning(Form("format error: can not reproduce channel length: expected %d, read %d", fNAltro10bitWords, lenCheck));
86525f0f 468 iCopy=-1;
469 }
470 } else {
471 AliError(Form("first byte of encoded data (%#x at %d) does not match decoded word (%#x at %d)", *pSrc, position, fOutBuffer[currentIndex]&0xff, currentIndex));
472 iCopy=-1;
473 }
474 } else {
475 AliError(Form("buffer size missmatch: payload ends at %p, but current channel pretends to end at %p", f32DtaPtr, pSrc+5));
476 iCopy=-1;
477 }
478 } else {
479 AliError(Form("current position does not match a byte: currentIndex=%d", currentIndex));
480 iCopy=-1;
481 }
482 }
483 return iCopy;
484}
485
486Bool_t AliAltroDecoder::GetRCUTrailerData(UChar_t*& data) const
487{
488 // Provide a pointer to RCU trailer.
489 // The type of the parameter might not be optimal, but the function has
490 // been chosen that way to be similar to the counterpart in
491 // AliAltroRawStream.
492 // @return kTRUE if trailer available;
493 if (!f8DtaPtr) return kFALSE;
494 data=f8DtaPtr-(fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
495 assert((UChar_t*)f32DtaPtr == data);
496 return kTRUE;
497}
498
499Int_t AliAltroDecoder::GetRCUTrailerSize() const
500{
501 // Provide size of RCU trailer.
502 if (!f8DtaPtr) return 0;
503 assert(fSize>(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t)));
504 return fSize-(f8PayloadSize+fkN32HeaderWords*sizeof(UInt_t));
31a920d3 505}