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