Crrected versions of AliAltroBuffer, AliAltroMapping and AliTPCRawStream
[u/mrichter/AliRoot.git] / RAW / AliAltroBuffer.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 // Interface to the Altro format
19 // to read and write digits
20 // To be used in Alice Data Challenges 
21 // and in the compression of the RAW data
22
23 #include "AliAltroBuffer.h"
24 #include "AliAltroMapping.h"
25 #include "AliRawDataHeader.h"
26 #include "AliLog.h"
27 #include <Riostream.h>
28 #include <stdlib.h>
29
30
31 ClassImp(AliAltroBuffer)
32
33 //_____________________________________________________________________________
34 AliAltroBuffer::AliAltroBuffer(const char* fileName, Int_t flag, const AliAltroMapping *mapping):
35   fShift(0),
36   fCurrentCell(0),
37   fFreeCellBuffer(0),
38   fFlag(flag),
39   fVerbose(0),
40   fFile(NULL),
41   fMaskBackward(0xFF),
42   fFilePosition(0),
43   fFileEnd(0),
44   fDataHeaderPos(0),
45   fEndingFillWords(0),
46   fMapping(mapping)
47 {
48 //if flag = 1 the actual object is used in the write mode
49 //if flag = 0 the actual object is used in the read mode
50
51   //the buffer is cleaned 
52   for (Int_t i = 0; i < 5; i++) fBuffer[i] = 0;
53
54   if (flag) {
55     fFreeCellBuffer = 16;
56     fShift = 32; 
57     //open the output file
58 #ifndef __DECCXX
59     fFile = new fstream(fileName, ios::binary|ios::out);
60 #else
61     fFile = new fstream(fileName, ios::out);
62 #endif
63   } else {
64     //open the input file
65 #ifndef __DECCXX
66     fFile = new fstream(fileName, ios::binary|ios::in);
67 #else
68     fFile = new fstream(fileName, ios::in);
69 #endif
70     if (!fFile) {
71       Error("AliAltroBuffer", "File doesn't exist: %s", fileName);
72       return;
73     }
74     fShift = 0;
75     //To get the file dimension (position of the last element in term of bytes)
76     fFile->seekg(0, ios::end);
77     fFilePosition = fFile->tellg();
78     fFileEnd = fFilePosition;
79     fFile->seekg(0);
80   }
81
82 }
83
84 //_____________________________________________________________________________
85 AliAltroBuffer::~AliAltroBuffer()
86 {
87 // destructor
88
89   if (fFlag) {
90     //Flush out the Buffer content at the end only if Buffer wasn't completely filled
91     Flush();
92     if (fVerbose) Info("~AliAltroBuffer", "File Created");
93   }//end if
94   fFile->close();
95   delete fFile;
96
97 }
98
99 //_____________________________________________________________________________
100 AliAltroBuffer::AliAltroBuffer(const AliAltroBuffer& source):
101   TObject(source),
102   fShift(source.fShift),
103   fCurrentCell(source.fCurrentCell),
104   fFreeCellBuffer(source.fFreeCellBuffer),
105   fFlag(source.fFlag),
106   fVerbose(source.fVerbose),
107   fFile(NULL),
108   fMaskBackward(source.fMaskBackward),
109   fFilePosition(source.fFilePosition),
110   fFileEnd(source.fFileEnd),
111   fDataHeaderPos(source.fDataHeaderPos),
112   fEndingFillWords(source.fEndingFillWords),
113   fMapping(source.fMapping)
114 {
115 // Copy Constructor
116
117   Fatal("AliAltroBuffer", "copy constructor not implemented");
118 }
119
120 //_____________________________________________________________________________
121 AliAltroBuffer& AliAltroBuffer::operator = (const AliAltroBuffer& /*source*/)
122 {
123 //Assigment operator
124
125   Fatal("operator =", "assignment operator not implemented");
126   return *this;
127 }
128
129
130 //_____________________________________________________________________________
131 Int_t AliAltroBuffer::GetNext()
132 {
133 //It reads a 10 bits word in forward dicection from the Buffer.
134 //A new Buffer is read from the file only when Buffer is empty.
135 //If there aren't elements anymore -1 is returned otherwise 
136 //the next element is returned
137
138   UInt_t mask = 0xFFC00000;
139   UInt_t temp;
140   UInt_t value;
141   if (!fShift) {
142     if (fFile->tellg() >= (Int_t)fFileEnd) return -1;
143     if (fFile->read((char*)fBuffer, sizeof(UInt_t)*5)) {
144       fCurrentCell = 0;
145       fShift = 22;
146       value = fBuffer[fCurrentCell] & mask;
147       value = value >> 22;
148       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] << 10;
149       return value;      
150     } else {
151       return -1;
152     }
153   } else {
154     if (fShift >= 10) {
155       value = fBuffer[fCurrentCell] & mask;
156       value = value >> 22;
157       fShift -= 10;
158       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] << 10;
159     } else {
160       value = fBuffer[fCurrentCell] & mask;
161       fCurrentCell++;
162       temp = fBuffer[fCurrentCell];
163       temp = temp >> fShift;
164       temp = temp & mask;
165       value = value | temp;
166       value = value >> 22;
167       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] << (10-fShift);
168       fShift += 22;
169     }
170     return value;
171   }//end else
172 }
173
174 //_____________________________________________________________________________
175 Int_t AliAltroBuffer::GetNextBackWord()
176 {
177 //It reads a 10 bits word in backward dicection from the Buffer.
178 //A new Buffer is read from the file only when Buffer is empty.
179 //If there aren't elements anymore -1 is returned otherwise 
180 //the next element is returned
181
182   UInt_t mask = 0x3FF;
183   UInt_t temp;
184   UInt_t value;
185   if (!fShift) {
186     if (fFilePosition > fDataHeaderPos){
187       fFilePosition -= sizeof(UInt_t)*5;
188       fFile->seekg(fFilePosition);
189       fFile->read((char*)fBuffer, sizeof(UInt_t)*5);
190       
191       fCurrentCell = 4;
192       fShift = 22;
193       fMaskBackward = 0xFF;
194       value = fBuffer[fCurrentCell] & mask;
195       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] >> 10;
196       return value;
197     } else {
198       fFile->seekg(fDataHeaderPos);
199       return -1;
200     }
201   } else {
202     if (fShift >= 10) {
203       value = fBuffer[fCurrentCell] & mask;
204       fShift -= 10;
205       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] >> 10;
206     } else {
207       value = fBuffer[fCurrentCell];
208       fCurrentCell--;
209       temp = fBuffer[fCurrentCell] & mask;
210       temp = temp & fMaskBackward;
211       fMaskBackward = fMaskBackward >> 2;
212       temp = temp << fShift;
213       value = value | temp;
214       fBuffer[fCurrentCell] = fBuffer[fCurrentCell] >> (10-fShift);
215       fShift = 22 + fShift;
216     }
217     return value;
218   }//end else
219 }
220
221 //_____________________________________________________________________________
222 void AliAltroBuffer::Flush()
223 {
224 // Flushes the Buffer content 
225   if (fFreeCellBuffer != 16) {
226     Int_t temp = fFreeCellBuffer;
227     for (Int_t i = 0; i < temp; i++){
228       FillBuffer(0x2AA);
229     }//end for
230   }//end if
231 }
232
233 //_____________________________________________________________________________
234 void AliAltroBuffer::FillBuffer(Int_t val)
235 {
236 //Fills the Buffer with 16 ten bits words and write into a file 
237
238   if ((val > 0x3FF) || (val < 0)) {
239     Error("FillBuffer", "Value out of range (10 bits): %d", val);
240     val = 0x3FF;
241   }
242   fFreeCellBuffer--;
243   if (fShift < 10) {
244     Int_t temp = val;
245     val = val >> (10-fShift);
246     fBuffer[fCurrentCell] |= val;
247     fCurrentCell++;
248     fShift += 32;
249     val = temp;
250   }
251   fShift -= 10;
252   val = val << fShift;
253   fBuffer[fCurrentCell] |= val;
254   if (!fShift) {
255     //Buffer is written into a file
256     fFile->write((char*)fBuffer, sizeof(UInt_t)*5);
257     //Buffer is empty
258     for (Int_t j = 0; j < 5; j++) fBuffer[j] = 0;
259     fShift = 32;
260     fCurrentCell = 0;
261     fFreeCellBuffer = 16;
262   }
263 }
264
265
266 //_____________________________________________________________________________
267 void AliAltroBuffer::WriteDummyTrailer(Int_t wordsNumber, Int_t padNumber,
268                                        Int_t rowNumber, Int_t secNumber)
269 {
270 //Writes a trailer of 40 bits
271
272    Int_t num = fFreeCellBuffer % 4;
273    for(Int_t i = 0; i < num; i++) {
274      FillBuffer(0x2AA);
275    }//end for
276    FillBuffer(wordsNumber);
277    FillBuffer(padNumber);
278    FillBuffer(rowNumber);
279    FillBuffer(secNumber);
280 }
281
282 //_____________________________________________________________________________
283 void AliAltroBuffer::WriteTrailer(Int_t wordsNumber, Int_t padNumber,
284                                   Int_t rowNumber, Int_t secNumber)
285 {
286 //Writes a trailer of 40 bits
287
288   if (!fMapping) {
289     AliError("No ALTRO mapping information is loaded! Filling a dummy trailer!");
290     return WriteDummyTrailer(wordsNumber,padNumber,
291                              rowNumber,secNumber);
292   }
293
294   Short_t hwAddress = fMapping->GetHWAddress(rowNumber,padNumber,secNumber);
295   if (hwAddress == -1)
296     AliFatal(Form("No hardware (ALTRO) adress found for these pad-row (%d) and pad (%d) indeces !",rowNumber,padNumber));
297   WriteTrailer(wordsNumber,hwAddress);
298 }
299
300 //_____________________________________________________________________________
301 void AliAltroBuffer::WriteTrailer(Int_t wordsNumber, Short_t hwAddress)
302 {
303 //Writes a trailer of 40 bits using
304 //a given hardware adress
305   Int_t num = fFreeCellBuffer % 4;
306   for(Int_t i = 0; i < num; i++) {
307     FillBuffer(0x2AA);
308   }//end for
309   Int_t temp;
310   temp = hwAddress & 0x3FF;
311   FillBuffer(temp);
312
313   temp = (wordsNumber << 6) & 0x3FF;
314   temp |= (0xA << 2);
315   temp |= ((hwAddress >> 10) & 0x3);
316   FillBuffer(temp);
317
318   temp = 0xA << 6;
319   temp |= ((wordsNumber & 0x3FF) >> 4);
320   FillBuffer(temp);
321
322   temp = 0x2AA;
323   FillBuffer(temp);
324 }
325
326 //_____________________________________________________________________________
327 Bool_t AliAltroBuffer::ReadDummyTrailer(Int_t& wordsNumber, Int_t& padNumber,
328                                         Int_t& rowNumber, Int_t& secNumber)
329 {
330 //Read a dummy trailer of 40 bits in the forward reading mode
331
332   wordsNumber = GetNext();
333   if (wordsNumber == -1) return kFALSE;
334   padNumber = GetNext();
335   if (padNumber == -1) return kFALSE;
336   rowNumber = GetNext();
337   if (rowNumber == -1) return kFALSE;
338   secNumber = GetNext();
339   if (secNumber == -1) return kFALSE;
340   return kTRUE;
341 }
342
343 //_____________________________________________________________________________
344 Bool_t AliAltroBuffer::ReadTrailer(Int_t& wordsNumber, Int_t& padNumber,
345                                    Int_t& rowNumber, Int_t& secNumber)
346 {
347 //Read a trailer of 40 bits in the forward reading mode
348   if (!fMapping) {
349     AliError("No ALTRO mapping information is loaded! Reading a dummy trailer!");
350     return ReadDummyTrailer(wordsNumber,padNumber,
351                             rowNumber,secNumber);
352   }
353
354   Short_t hwAddress;
355   if (!ReadTrailer(wordsNumber,hwAddress)) return kFALSE;
356   rowNumber = fMapping->GetPadRow(hwAddress);
357   padNumber = fMapping->GetPad(hwAddress);
358   secNumber = fMapping->GetSector(hwAddress);
359
360   return kTRUE;
361 }
362
363 //_____________________________________________________________________________
364 Bool_t AliAltroBuffer::ReadTrailer(Int_t& wordsNumber, Short_t& hwAddress)
365 {
366 //Read a trailer of 40 bits in the forward reading mode
367
368   Int_t temp = GetNext();
369   hwAddress = temp;
370
371   temp = GetNext();
372   wordsNumber = ((temp & 0x3FF) >> 6);
373   if (((temp >> 2) & 0xF) != 0xA)
374     AliFatal(Form("Incorrect trailer found ! Expecting second 0xA but found %x !",temp >> 6));
375   hwAddress |= (temp & 0x3) << 10;
376
377   temp = GetNext();
378   if ((temp >> 6) != 0xA)
379     AliFatal(Form("Incorrect trailer found ! Expecting 0xA but found %x !",temp >> 6));
380   wordsNumber |= (temp << 4) & 0x3FF;
381
382   temp = GetNext();
383   if (temp != 0x2AA)
384     AliFatal(Form("Incorrect trailer found ! Expecting 0x2AA but found %x !",temp));
385
386   return kTRUE;
387 }
388
389 //_____________________________________________________________________________
390 Bool_t AliAltroBuffer::ReadDummyTrailerBackward(Int_t& wordsNumber, Int_t& padNumber,
391                                                 Int_t& rowNumber, Int_t& secNumber)
392 {
393 //Read a trailer of 40 bits in the backward reading mode
394
395   Int_t temp;
396   fEndingFillWords = 0;
397   do {
398     temp = GetNextBackWord();
399     fEndingFillWords++;
400     if (temp == -1) return kFALSE;
401   } while (temp == 0x2AA);  
402   fEndingFillWords--;
403   secNumber = temp;
404   rowNumber = GetNextBackWord();
405   if (rowNumber == -1) return kFALSE;
406   padNumber = GetNextBackWord();
407   if (padNumber == -1) return kFALSE;
408   wordsNumber = GetNextBackWord();
409   if (wordsNumber == -1) return kFALSE;
410   return kTRUE;
411
412
413 //_____________________________________________________________________________
414 Bool_t AliAltroBuffer::ReadTrailerBackward(Int_t& wordsNumber, Int_t& padNumber,
415                                            Int_t& rowNumber, Int_t& secNumber)
416 {
417 //Read a trailer of 40 bits in the backward reading mode
418   if (!fMapping) {
419     AliError("No ALTRO mapping information is loaded! Reading a dummy trailer!");
420     return ReadDummyTrailerBackward(wordsNumber,padNumber,
421                                     rowNumber,secNumber);
422   }
423
424   Short_t hwAddress;
425   if (!ReadTrailerBackward(wordsNumber,hwAddress)) return kFALSE;
426   rowNumber = fMapping->GetPadRow(hwAddress);
427   padNumber = fMapping->GetPad(hwAddress);
428   secNumber = fMapping->GetSector(hwAddress);
429
430   return kTRUE;
431 }
432
433 //_____________________________________________________________________________
434 Bool_t AliAltroBuffer::ReadTrailerBackward(Int_t& wordsNumber, Short_t& hwAddress)
435 {
436 //Read a trailer of 40 bits in the backward reading mode
437
438   Int_t temp;
439   fEndingFillWords = 0;
440   while ((temp = GetNextBackWord()) == 0x2AA) {
441     fEndingFillWords++;
442     if (temp == -1) return kFALSE;
443   };
444   if (fEndingFillWords == 0)
445     AliFatal("Incorrect trailer found ! Expected 0x2AA not found !");
446   fEndingFillWords--;
447
448   wordsNumber = (temp << 4) & 0x3FF;
449   if ((temp >> 6) != 0xA)
450     AliFatal(Form("Incorrect trailer found ! Expecting 0xA but found %x !",temp >> 6));
451
452   temp = GetNextBackWord();
453   hwAddress = (temp & 0x3) << 10;
454   if (((temp >> 2) & 0xF) != 0xA)
455     AliFatal(Form("Incorrect trailer found ! Expecting second 0xA but found %x !",(temp >> 2) & 0xF));
456   wordsNumber |= ((temp & 0x3FF) >> 6);
457
458   temp = GetNextBackWord();
459   hwAddress |= temp;
460
461   return kTRUE;
462
463
464 //_____________________________________________________________________________
465 void AliAltroBuffer::WriteChannel(Int_t padNumber, Int_t rowNumber, 
466                                   Int_t secNumber,
467                                   Int_t nTimeBins, const Int_t* adcValues,
468                                   Int_t threshold)
469 {
470   //Write all ADC values and the trailer of a channel
471   Int_t nWords = WriteBunch(nTimeBins,adcValues,threshold);
472   // write the trailer
473   WriteTrailer(nWords, padNumber, rowNumber, secNumber);
474 }
475
476 //_____________________________________________________________________________
477 void AliAltroBuffer::WriteChannel(Short_t hwAddress,
478                                   Int_t nTimeBins, const Int_t* adcValues,
479                                   Int_t threshold)
480 {
481   //Write all ADC values and the trailer of a channel
482   Int_t nWords = WriteBunch(nTimeBins,adcValues,threshold);
483   // write the trailer
484   WriteTrailer(nWords, hwAddress);
485 }
486
487 //_____________________________________________________________________________
488 Int_t AliAltroBuffer::WriteBunch(Int_t nTimeBins, const Int_t* adcValues,
489                                  Int_t threshold)
490 {
491   //Write all ADC values
492   //Return number of words written
493
494   Int_t nWords = 0;
495   Int_t timeBin = -1;
496   Int_t bunchLength = 0;
497
498   // loop over time bins
499   for (Int_t iTime = 0; iTime < nTimeBins; iTime++) {
500     if (adcValues[iTime] >= threshold) { // ADC value above threshold
501       FillBuffer(adcValues[iTime]);
502       nWords++;
503       timeBin = iTime;
504       bunchLength++;
505
506     } else if (timeBin >= 0) {  // end of bunch
507       FillBuffer(timeBin);
508       FillBuffer(bunchLength + 2);
509       nWords += 2;
510       timeBin = -1;
511       bunchLength = 0;
512     }
513   }
514
515   if (timeBin >= 0) {  // end of bunch
516     FillBuffer(timeBin);
517     FillBuffer(bunchLength + 2);
518     nWords += 2;
519   }
520
521   return nWords;
522 }
523
524 //_____________________________________________________________________________
525 void AliAltroBuffer::ReadChannelBackward(Int_t& padNumber, Int_t& rowNumber, 
526                                          Int_t& secNumber,
527                                          Int_t& nTimeBins, Int_t* adcValues)
528 {
529 //Read all ADC values and the trailer of a channel (in backward order)
530
531   Int_t wordsNumber;
532   if (!ReadTrailerBackward(wordsNumber,padNumber,
533                            rowNumber,secNumber)) return;
534   return ReadBunchBackward(wordsNumber,nTimeBins,adcValues);
535 }
536
537 //_____________________________________________________________________________
538 void AliAltroBuffer::ReadChannelBackward(Short_t& hwAddress,
539                                          Int_t& nTimeBins, Int_t* adcValues)
540 {
541 //Read all ADC values and the trailer of a channel (in backward order)
542
543   Int_t wordsNumber;
544   if (!ReadTrailerBackward(wordsNumber,
545                            hwAddress)) return;
546   return ReadBunchBackward(wordsNumber,nTimeBins,adcValues);
547 }
548
549 //_____________________________________________________________________________
550 void AliAltroBuffer::ReadBunchBackward(Int_t wordsNumber,
551                                        Int_t& nTimeBins, Int_t* adcValues)
552 {
553   if (wordsNumber < 0) return;
554   // Number of fill words 
555   Int_t nFillWords;
556   if ((wordsNumber % 4) == 0)
557     nFillWords = 0;
558   else
559     nFillWords = 4 - wordsNumber % 4;
560   // Read the fill words 
561   for (Int_t i = 0; i < nFillWords; i++) {
562     Int_t temp = GetNextBackWord();
563     if (temp != 0x2AA) 
564       AliFatal(Form("Invalid fill word, expected 0x2AA, but got %X", temp));
565   }
566
567   // Decoding
568   Int_t lastWord =  wordsNumber;
569   nTimeBins = -1;
570   while (lastWord > 0) { 
571     Int_t l =  GetNextBackWord(); 
572     if (l < 0) AliFatal(Form("Bad bunch length (%d) !", l));
573     Int_t t =  GetNextBackWord(); 
574     if (t < 0) AliFatal(Form("Bad bunch time (%d) !", t));
575     lastWord -= 2;
576     if (nTimeBins == -1) nTimeBins = t + 1;
577     for (Int_t i = 2; i < l; i++) {
578       Int_t amp = GetNextBackWord();
579       if (amp < 0) AliFatal(Form("Bad adc value (%X) !", amp));
580       adcValues[t - (i-2)] = amp;
581       lastWord--;
582     }
583   }
584
585
586
587 //_____________________________________________________________________________
588 void AliAltroBuffer::WriteDataHeader(Bool_t dummy, Bool_t compressed)
589 {
590 //Write a (dummy or real) DDL data header, 
591 //set the compression bit if compressed
592
593   AliRawDataHeader header;
594   if (dummy) {
595     //if size=0 it means that this data header is a dummy data header
596     fDataHeaderPos = fFile->tellp();
597     fFile->write((char*)(&header), sizeof(header));
598   } else {
599     UInt_t currentFilePos = fFile->tellp();
600     fFile->seekp(fDataHeaderPos);
601     header.fSize = currentFilePos-fDataHeaderPos;
602     header.SetAttribute(0);  // valid data
603     if (compressed) header.SetAttribute(1); 
604     fFile->write((char*)(&header), sizeof(header));
605     fFile->seekp(currentFilePos);
606   }
607 }
608
609 //_____________________________________________________________________________
610 Bool_t AliAltroBuffer::ReadDataHeader()
611 {
612 //Read the DDL data header at the beginning of the file, 
613 //returns true in case of valid data
614
615   AliRawDataHeader header;
616   UInt_t currentPos = fFile->tellp();
617   fFile->seekp(0);
618   if (!fFile->read((char*)(&header), sizeof(header))) return kFALSE;
619   fDataHeaderPos = fFile->tellp();
620   fFile->seekp(currentPos);
621   return header.TestAttribute(0);
622 }
623