d9e6350a236b6b5a5ae6bb050866d5c586be6917
[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   Int_t num = fFreeCellBuffer % 4;
296   for(Int_t i = 0; i < num; i++) {
297     FillBuffer(0x2AA);
298   }//end for
299   Int_t temp;
300   temp = 0x2AA;
301   FillBuffer(temp);
302   temp = 0xA << 6;
303   temp |= ((wordsNumber & 0x3FF) >> 4);
304   FillBuffer(temp);
305   temp = (wordsNumber << 6) & 0x3FF;
306   temp |= (0xA << 2);
307
308   Short_t hwAdress = fMapping->GetHWAdress(rowNumber,padNumber,secNumber);
309   if (hwAdress == -1)
310     AliFatal(Form("No hardware (ALTRO) adress found for these pad-row (%d) and pad (%d) indeces !",rowNumber,padNumber));
311       
312   temp |= (hwAdress >> 10) & 0x3;
313   FillBuffer(temp);
314   temp = hwAdress & 0x3FF;
315   FillBuffer(temp);
316 }
317
318 //_____________________________________________________________________________
319 Bool_t AliAltroBuffer::ReadDummyTrailer(Int_t& wordsNumber, Int_t& padNumber,
320                                         Int_t& rowNumber, Int_t& secNumber)
321 {
322 //Read a dummy trailer of 40 bits in the forward reading mode
323
324   wordsNumber = GetNext();
325   if (wordsNumber == -1) return kFALSE;
326   padNumber = GetNext();
327   if (padNumber == -1) return kFALSE;
328   rowNumber = GetNext();
329   if (rowNumber == -1) return kFALSE;
330   secNumber = GetNext();
331   if (secNumber == -1) return kFALSE;
332   return kTRUE;
333 }
334
335 //_____________________________________________________________________________
336 Bool_t AliAltroBuffer::ReadTrailer(Int_t& wordsNumber, Int_t& padNumber,
337                                    Int_t& rowNumber, Int_t& secNumber)
338 {
339 //Read a trailer of 40 bits in the forward reading mode
340   if (!fMapping) {
341     AliError("No ALTRO mapping information is loaded! Reading a dummy trailer!");
342     return ReadDummyTrailer(wordsNumber,padNumber,
343                             rowNumber,secNumber);
344   }
345
346   Int_t temp = GetNext();
347   if (temp != 0x2AA)
348     AliFatal(Form("Incorrect trailer found ! Expecting 0x2AA but found %x !",temp));
349
350   temp = GetNext();
351   if ((temp >> 6) != 0xA)
352     AliFatal(Form("Incorrect trailer found ! Expecting 0xA but found %x !",temp >> 6));
353   wordsNumber = (temp << 4) & 0x3FF;
354
355   temp = GetNext();
356   wordsNumber |= (temp >> 6);
357   if ((temp & 0xF) != 0xA)
358     AliFatal(Form("Incorrect trailer found ! Expecting second 0xA but found %x !",temp >> 6));
359   Int_t hwAdress = (temp & 0x3) << 10;
360
361   temp = GetNext();
362   hwAdress |= temp;
363
364   rowNumber = fMapping->GetPadRow(hwAdress);
365   padNumber = fMapping->GetPad(hwAdress);
366   secNumber = fMapping->GetSector(hwAdress);
367   return kTRUE;
368 }
369
370 //_____________________________________________________________________________
371 Bool_t AliAltroBuffer::ReadTrailerBackward(Int_t& wordsNumber, 
372                                            Int_t& padNumber,
373                                            Int_t& rowNumber, Int_t& secNumber)
374 {
375 //Read a trailer of 40 bits in the backward reading mode
376
377   Int_t temp;
378   fEndingFillWords = 0;
379   do {
380     temp = GetNextBackWord();
381     fEndingFillWords++;
382     if (temp == -1) return kFALSE;
383   } while (temp == 0x2AA);  
384   fEndingFillWords--;
385   secNumber = temp;
386   rowNumber = GetNextBackWord();
387   if (rowNumber == -1) return kFALSE;
388   padNumber = GetNextBackWord();
389   if (padNumber == -1) return kFALSE;
390   wordsNumber = GetNextBackWord();
391   if (wordsNumber == -1) return kFALSE;
392   return kTRUE;
393
394
395
396 //_____________________________________________________________________________
397 void AliAltroBuffer::WriteChannel(Int_t padNumber, Int_t rowNumber, 
398                                   Int_t secNumber,
399                                   Int_t nTimeBins, const Int_t* adcValues,
400                                   Int_t threshold)
401 {
402 //Write all ADC values and the trailer of a channel
403
404   Int_t nWords = 0;
405   Int_t timeBin = -1;
406   Int_t bunchLength = 0;
407
408   // loop over time bins
409   for (Int_t iTime = 0; iTime < nTimeBins; iTime++) {
410     if (adcValues[iTime] >= threshold) { // ADC value above threshold
411       FillBuffer(adcValues[iTime]);
412       nWords++;
413       timeBin = iTime;
414       bunchLength++;
415
416     } else if (timeBin >= 0) {  // end of bunch
417       FillBuffer(timeBin);
418       FillBuffer(bunchLength + 2);
419       nWords += 2;
420       timeBin = -1;
421       bunchLength = 0;
422     }
423   }
424
425   if (timeBin >= 0) {  // end of bunch
426     FillBuffer(timeBin);
427     FillBuffer(bunchLength + 2);
428     nWords += 2;
429   }
430
431   // write the trailer
432   WriteTrailer(nWords, padNumber, rowNumber, secNumber);
433 }
434
435
436 //_____________________________________________________________________________
437 void AliAltroBuffer::WriteDataHeader(Bool_t dummy, Bool_t compressed)
438 {
439 //Write a (dummy or real) DDL data header, 
440 //set the compression bit if compressed
441
442   AliRawDataHeader header;
443   if (dummy) {
444     //if size=0 it means that this data header is a dummy data header
445     fDataHeaderPos = fFile->tellp();
446     fFile->write((char*)(&header), sizeof(header));
447   } else {
448     UInt_t currentFilePos = fFile->tellp();
449     fFile->seekp(fDataHeaderPos);
450     header.fSize = currentFilePos-fDataHeaderPos;
451     header.SetAttribute(0);  // valid data
452     if (compressed) header.SetAttribute(1); 
453     fFile->write((char*)(&header), sizeof(header));
454     fFile->seekp(currentFilePos);
455   }
456 }
457
458 //_____________________________________________________________________________
459 Bool_t AliAltroBuffer::ReadDataHeader()
460 {
461 //Read the DDL data header at the beginning of the file, 
462 //returns true in case of valid data
463
464   AliRawDataHeader header;
465   UInt_t currentPos = fFile->tellp();
466   fFile->seekp(0);
467   if (!fFile->read((char*)(&header), sizeof(header))) return kFALSE;
468   fDataHeaderPos = fFile->tellp();
469   fFile->seekp(currentPos);
470   return header.TestAttribute(0);
471 }
472