Do not write the ALTRO trailer in case of an empty ALTRO payload.
[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 "AliRawDataHeaderSim.h"
26 #include "AliLog.h"
27 #include "AliFstream.h"
28 //#include <stdlib.h>
29
30
31 ClassImp(AliAltroBuffer)
32
33 //_____________________________________________________________________________
34 AliAltroBuffer::AliAltroBuffer(const char* fileName, const AliAltroMapping *mapping):
35   fShift(0),
36   fCurrentCell(0),
37   fFreeCellBuffer(16),
38   fVerbose(0),
39   fFile(NULL),
40   fDataHeaderPos(0),
41   fMapping(mapping)
42 {
43   //the buffer is cleaned 
44   for (Int_t i = 0; i < 5; i++) fBuffer[i] = 0;
45
46   //open the output file
47   fFile = new AliFstream(fileName);
48
49 }
50
51 //_____________________________________________________________________________
52 AliAltroBuffer::~AliAltroBuffer()
53 {
54 // destructor
55
56   //Flush out the Buffer content at the end only if Buffer wasn't completely filled
57   Flush();
58   if (fVerbose) Info("~AliAltroBuffer", "File Created");
59
60   delete fFile;
61
62 }
63
64 //_____________________________________________________________________________
65 AliAltroBuffer::AliAltroBuffer(const AliAltroBuffer& source):
66   TObject(source),
67   fShift(source.fShift),
68   fCurrentCell(source.fCurrentCell),
69   fFreeCellBuffer(source.fFreeCellBuffer),
70   fVerbose(source.fVerbose),
71   fFile(NULL),
72   fDataHeaderPos(source.fDataHeaderPos),
73   fMapping(source.fMapping)
74 {
75 // Copy Constructor
76
77   Fatal("AliAltroBuffer", "copy constructor not implemented");
78 }
79
80 //_____________________________________________________________________________
81 AliAltroBuffer& AliAltroBuffer::operator = (const AliAltroBuffer& /*source*/)
82 {
83 //Assigment operator
84
85   Fatal("operator =", "assignment operator not implemented");
86   return *this;
87 }
88
89 //_____________________________________________________________________________
90 void AliAltroBuffer::Flush()
91 {
92 // Flushes the Buffer content 
93   if (fFreeCellBuffer != 16) {
94     Int_t temp = fFreeCellBuffer;
95     for (Int_t i = 0; i < temp; i++){
96       FillBuffer(0x2AA);
97     }//end for
98   }//end if
99 }
100
101 //_____________________________________________________________________________
102 void AliAltroBuffer::FillBuffer(Int_t val)
103 {
104 //Fills the Buffer with 16 ten bits words and write into a file 
105
106   if ((val > 0x3FF) || (val < 0)) {
107     Error("FillBuffer", "Value out of range (10 bits): %d", val);
108     val = 0x3FF;
109   }
110   fFreeCellBuffer--;
111
112   fBuffer[fCurrentCell] |= (val << fShift);
113   fShift += 10;
114
115   if (fShift > 32) {
116     fCurrentCell++;
117     fShift -= 32;
118     fBuffer[fCurrentCell] |= (val >> (10 - fShift));
119   }
120
121   if (fShift == 32) {
122     //Buffer is written into a file
123     fFile->WriteBuffer((char*)fBuffer, sizeof(UInt_t)*5);
124     //Buffer is empty
125     for (Int_t j = 0; j < 5; j++) fBuffer[j] = 0;
126     fShift = 0;
127     fCurrentCell = 0;
128     fFreeCellBuffer = 16;
129   }
130 }
131
132
133 //_____________________________________________________________________________
134 void AliAltroBuffer::WriteDummyTrailer(Int_t wordsNumber, Int_t padNumber,
135                                        Int_t rowNumber, Int_t secNumber)
136 {
137 //Writes a trailer of 40 bits
138
139    Int_t num = fFreeCellBuffer % 4;
140    for(Int_t i = 0; i < num; i++) {
141      FillBuffer(0x2AA);
142    }//end for
143    FillBuffer(wordsNumber);
144    FillBuffer(padNumber);
145    FillBuffer(rowNumber);
146    FillBuffer(secNumber);
147 }
148
149 //_____________________________________________________________________________
150 void AliAltroBuffer::WriteTrailer(Int_t wordsNumber, Int_t padNumber,
151                                   Int_t rowNumber, Int_t secNumber)
152 {
153 //Writes a trailer of 40 bits
154
155   if (!fMapping) {
156     AliError("No ALTRO mapping information is loaded! Filling a dummy trailer!");
157     return WriteDummyTrailer(wordsNumber,padNumber,
158                              rowNumber,secNumber);
159   }
160
161   Short_t hwAddress = fMapping->GetHWAddress(rowNumber,padNumber,secNumber);
162   if (hwAddress == -1)
163     AliFatal(Form("No hardware (ALTRO) adress found for these pad-row (%d) and pad (%d) indeces !",rowNumber,padNumber));
164   WriteTrailer(wordsNumber,hwAddress);
165 }
166
167 //_____________________________________________________________________________
168 void AliAltroBuffer::WriteTrailer(Int_t wordsNumber, Short_t hwAddress)
169 {
170 //Writes a trailer of 40 bits using
171 //a given hardware adress
172   Int_t num = fFreeCellBuffer % 4;
173   for(Int_t i = 0; i < num; i++) {
174     FillBuffer(0x2AA);
175   }//end for
176   Int_t temp;
177   temp = hwAddress & 0x3FF;
178   FillBuffer(temp);
179
180   temp = (wordsNumber << 6) & 0x3FF;
181   temp |= (0xA << 2);
182   temp |= ((hwAddress >> 10) & 0x3);
183   FillBuffer(temp);
184
185   temp = 0xA << 6;
186   temp |= ((wordsNumber & 0x3FF) >> 4);
187   FillBuffer(temp);
188
189   temp = 0x2AA;
190   FillBuffer(temp);
191 }
192
193 //_____________________________________________________________________________
194 void AliAltroBuffer::WriteChannel(Int_t padNumber, Int_t rowNumber, 
195                                   Int_t secNumber,
196                                   Int_t nTimeBins, const Int_t* adcValues,
197                                   Int_t threshold)
198 {
199   //Write all ADC values and the trailer of a channel
200   Int_t nWords = WriteBunch(nTimeBins,adcValues,threshold);
201   // write the trailer
202   if (nWords) WriteTrailer(nWords, padNumber, rowNumber, secNumber);
203 }
204
205 //_____________________________________________________________________________
206 void AliAltroBuffer::WriteChannel(Short_t hwAddress,
207                                   Int_t nTimeBins, const Int_t* adcValues,
208                                   Int_t threshold)
209 {
210   //Write all ADC values and the trailer of a channel
211   Int_t nWords = WriteBunch(nTimeBins,adcValues,threshold);
212   // write the trailer
213   if (nWords) WriteTrailer(nWords, hwAddress);
214 }
215
216 //_____________________________________________________________________________
217 Int_t AliAltroBuffer::WriteBunch(Int_t nTimeBins, const Int_t* adcValues,
218                                  Int_t threshold)
219 {
220   //Write all ADC values
221   //Return number of words written
222
223   Int_t nWords = 0;
224   Int_t timeBin = -1;
225   Int_t bunchLength = 0;
226
227   // loop over time bins
228   for (Int_t iTime = 0; iTime < nTimeBins; iTime++) {
229     if (adcValues[iTime] >= threshold) { // ADC value above threshold
230       FillBuffer(adcValues[iTime]);
231       nWords++;
232       timeBin = iTime;
233       bunchLength++;
234
235     } else if (timeBin >= 0) {  // end of bunch
236       FillBuffer(timeBin);
237       FillBuffer(bunchLength + 2);
238       nWords += 2;
239       timeBin = -1;
240       bunchLength = 0;
241     }
242   }
243
244   if (timeBin >= 0) {  // end of bunch
245     FillBuffer(timeBin);
246     FillBuffer(bunchLength + 2);
247     nWords += 2;
248   }
249
250   return nWords;
251 }
252
253 //_____________________________________________________________________________
254 void AliAltroBuffer::WriteDataHeader(Bool_t dummy, Bool_t compressed)
255 {
256 //Write a (dummy or real) DDL data header, 
257 //set the compression bit if compressed
258
259   AliRawDataHeaderSim header;
260   if (dummy) {
261     //if size=0 it means that this data header is a dummy data header
262     fDataHeaderPos = fFile->Tellp();
263     fFile->WriteBuffer((char*)(&header), sizeof(header));
264   } else {
265     WriteRCUTrailer(0);
266     UInt_t currentFilePos = fFile->Tellp();
267     fFile->Seekp(fDataHeaderPos);
268     header.fSize = currentFilePos-fDataHeaderPos;
269     header.SetAttribute(0);  // valid data
270     if (compressed) header.SetAttribute(1); 
271     fFile->WriteBuffer((char*)(&header), sizeof(header));
272     fFile->Seekp(currentFilePos);
273   }
274 }
275
276 //_____________________________________________________________________________
277 void AliAltroBuffer::WriteRCUTrailer(Int_t rcuId)
278 {
279   // Writes the RCU trailer
280   // rcuId the is serial number of the corresponding
281   // RCU. The basic format of the trailer can be
282   // found in the RCU manual.
283   // This method should be called at the end of
284   // raw data writing.
285
286   UInt_t currentFilePos = fFile->Tellp();
287   UInt_t size = currentFilePos-fDataHeaderPos;
288   size -= sizeof(AliRawDataHeader);
289   
290   if ((size % 5) != 0) {
291     AliFatal(Form("The current raw data payload is not a mutiple of 5 (%d) ! Can not write the RCU trailer !",size));
292     return;
293   }
294
295   // Now put the size in unit of number of 40bit words
296   size /= 5;
297   fFile->WriteBuffer((char *)(&size),sizeof(UInt_t));
298
299   // Now several not yet full defined fields
300   // In principle they are supposed to contain
301   // information about the sampling frequency,
302   // L1 phase, list of 'dead' FECs, etc.
303   //  UInt_t buffer[n];
304   //  fFile->WriteBuffer((char *)(buffer),sizeof(UInt_t)*n);
305   
306   //  Now the RCU identifier and size of the trailer
307   //  FOr the moment the triler size is 2 32-bit words
308   UInt_t buffer = 2;
309   buffer |= ((rcuId & 0x3FF) << 22);
310   fFile->WriteBuffer((char *)(&buffer),sizeof(UInt_t));
311
312 }