New RAW I/O. I rolled my own, because I wasn't happy with the old
[u/mrichter/AliRoot.git] / FMD / AliFMDAltroIO.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 //____________________________________________________________________
19 //                                                                          
20 // Mapping of ALTRO hardware channel to detector coordinates 
21 //
22 #include "AliFMDAltroIO.h"
23 #include <AliRawDataHeader.h>
24 #include <AliRawReader.h>
25 #include "AliLog.h"
26 #include <iostream>
27 #include <iomanip>
28 #define PRETTY_HEX(N,X) \
29   "  0x" << std::setfill('0') << std::setw(N) << std::hex << X \
30          << std::setfill(' ') << std::dec
31
32 //====================================================================
33 ClassImp(AliFMDAltroIO)
34 #if 0
35   ; // This is here to keep Emacs for indenting the next line
36 #endif
37
38 //____________________________________________________________________
39 const AliFMDAltroIO::W40_t AliFMDAltroIO::fgkTrailerMask = 
40 ((AliFMDAltroIO::W40_t(0x2aaa) << 26) + (AliFMDAltroIO::W40_t(0xa) << 12));
41
42 //____________________________________________________________________
43 AliFMDAltroIO::AliFMDAltroIO() 
44   : fBuffer(0), fIBuffer(0)
45 {}
46
47 //____________________________________________________________________
48 const char*
49 AliFMDAltroIO::ErrorString(Int_t err)  const
50 {
51   switch (err) {
52   case kNoError:    return "No error";                          break;
53   case kBadFile:    return "Bad state after open/close file";   break;
54   case kBadBits:    return "Bad bit offset specified";          break;
55   case kBadRead:    return "Bad state after reading from file"; break;
56   case kBadWrite:   return "Bad state after writing to file";   break;
57   case kBadSeek:    return "Bad state after seeking in file";   break;
58   case kBadTell:    return "Could not tell position in file";   break;
59   case kBadTrailer: return "Bad trailer 40 bit word in file";   break;
60   case kBadFill:    return "Bad fill word in file";             break;
61   }
62   return "Unknown";
63 }
64
65
66 //____________________________________________________________________
67 AliFMDAltroIO::W40_t
68 AliFMDAltroIO::ConcatW40(size_t n, const W10_t& w) const
69 {
70   if (n > 3) return -kBadBits;
71   return W40_t(w & 0x3ff) << (10 * n);
72 }
73
74 //____________________________________________________________________
75 AliFMDAltroIO::W10_t
76 AliFMDAltroIO::ExtractW10(size_t n, const W40_t w) const
77 {
78   if (n > 3) return -kBadBits;
79   return (w >> (10 * n)) & 0x3ff;
80 }
81
82 //====================================================================
83 ClassImp(AliFMDAltroReader)
84 #if 0
85   ; // This is here to keep Emacs for indenting the next line
86 #endif
87
88 //____________________________________________________________________
89 AliFMDAltroReader::AliFMDAltroReader(std::istream& stream)
90   : fInput(stream)
91   // : fBuffer(buffer), fCurrent(n / 10 * sizeof(char))
92 {
93   // fInput.open(filename);
94   if (!fInput)      throw -kBadFile;
95   fBegin   = fInput.tellg();
96   if (fInput.bad()) throw -kBadTell;
97   fInput.seekg(0, std::ios_base::end);
98   if (fInput.bad()) throw -kBadSeek;
99   fCurrent = fInput.tellg();
100   if (fInput.bad()) throw -kBadTell;
101 #if 0
102   fInput.seekg(fBegin);
103   size_t i = 0;
104   do {
105     W40_t w = 0;
106     fInput.read((char*)&w, 5);
107     std::cout << std::setw(6) << i << ": " << PRETTY_HEX(10, w) << std::endl;
108     i++;
109   } while (!fInput.eof());
110   fInput.seekg(fCurrent);
111 #endif
112 }
113
114 //____________________________________________________________________
115 Int_t
116 AliFMDAltroReader::ReadChannel(UShort_t& board, UShort_t& chip, 
117                                UShort_t& channel, UShort_t& last, 
118                                UShort_t* data) 
119 {
120   UShort_t hwaddr;
121   Int_t    ret = ReadChannel(hwaddr, last, data);
122   board        = (hwaddr >>  7) & 0x1f;
123   chip         = (hwaddr >>  4) & 0x3;
124   channel      = hwaddr & 0xf;
125   return ret;
126 }
127
128 //____________________________________________________________________
129 Int_t
130 AliFMDAltroReader::ReadChannel(UShort_t& hwaddr, UShort_t& last, 
131                                UShort_t* data) 
132 {
133   Int_t ret, tmp;
134   AliDebug(15, Form("Reading a channel"));
135   if ((ret = ExtractTrailer(hwaddr, last)) < 0) { 
136     AliError(Form("Failed to read trailer: %s", ErrorString(-ret)));
137     return ret;
138   }
139   AliDebug(15, Form("Now extracting bunches from %d 10 bit words", last));
140   tmp     =  ExtractBunches(last, data); 
141   if (tmp < 0) {
142     AliError(Form("Failed to read bunches: %s", ErrorString(-tmp)));
143     return tmp;
144   }
145   ret     += tmp;
146   last    =  (last == 0 ? 0 : last - 2); 
147   return ret;
148 }
149
150 //____________________________________________________________________
151 Int_t
152 AliFMDAltroReader::ExtractTrailer(UShort_t& hwaddr, UShort_t& last)
153 {
154   AliDebug(15, "Extracting trailer");
155   W40_t trailer = GetNextW40();
156   if (trailer < 0) {
157     AliError(Form("Trailer 0x%x is bad: %s", trailer, ErrorString(-trailer)));
158     return trailer;
159   }
160   if (!IsTrailer(trailer)) { 
161     AliError(Form("Bad trailer: 0x%08x", trailer));
162     return -kBadTrailer;
163   }
164   last    = (trailer >> 16) & 0x3ff;
165   hwaddr  = (trailer & 0xfff);
166   return 4;
167 }
168
169 //____________________________________________________________________
170 Int_t
171 AliFMDAltroReader::ExtractBunches(UShort_t last, UShort_t* data) 
172 {
173   Int_t ret;
174   if ((ret = ExtractFillWords(last)) < 0) { 
175     AliError(Form("Failed to read fill words: %s", ErrorString(-ret)));
176     return ret;
177   }
178   while (last > 0) { 
179     Int_t tmp = ExtractBunch(data);
180     if (tmp <= 0) { 
181       AliError(Form("Failed to extract bunch at %d: %s", 
182                     last, ErrorString(-tmp)));
183       return tmp;
184     }
185     ret  += tmp;
186     last -= tmp;
187   }
188   return ret;
189 }
190
191 //____________________________________________________________________
192 Int_t
193 AliFMDAltroReader::ExtractFillWords(UShort_t last) 
194 {
195   // Number of fill words 
196   size_t nFill = (last % 4 == 0 ? 0 : 4 - last % 4);
197   // Read the fill words 
198   for (size_t i = 3; i >= 4 - nFill; i--) {
199     W10_t f = GetNextW10();
200     if (f != 0x2aa) return -kBadFill;
201   }
202   return nFill;
203 }
204
205 //____________________________________________________________________
206 Int_t
207 AliFMDAltroReader::ExtractBunch(UShort_t* data)
208 {
209   Int_t ret =  0;
210   W10_t l =  GetNextW10(); 
211   if (l < 0) { 
212     AliError(Form("Failed to read bunch length: %s", ErrorString(-l)));
213     return l;
214   }
215   W10_t t =  GetNextW10(); 
216   if (t < 0) { 
217     AliError(Form("Failed to read bunch time: %s", ErrorString(-t)));
218     return t;
219   }
220   ret     += 2;
221   for (Int_t i = 2; i < l; i++) {
222     W10_t s = GetNextW10();
223     if (s < 0) { 
224       AliError(Form("Failed to read bunch data: %s", ErrorString(-s)));
225       return 2;
226     }
227     AliDebug(50,Form("Assigning to data[%d - (%d - 1)] = 0x%X", t, i, s));
228     data[t - (i-1)] = s;
229     ret++;
230   }
231   return ret;
232 }
233
234 //____________________________________________________________________
235 Bool_t
236 AliFMDAltroReader::IsTrailer(W40_t x) 
237 {
238   return ((x & fgkTrailerMask) == fgkTrailerMask);
239 }
240
241 //____________________________________________________________________
242 Bool_t
243 AliFMDAltroReader::IsBof() 
244 {
245   return fCurrent == fBegin;
246 }
247
248 //____________________________________________________________________
249 Int_t
250 AliFMDAltroReader::ReadW40() 
251 {
252   fInput.seekg(fCurrent-std::istream::pos_type(5));
253   if (fInput.bad()) return -kBadSeek;
254   fCurrent = fInput.tellg();
255   if (fInput.bad()) return -kBadTell;
256   fInput.read((char*)&fBuffer, 5 * sizeof(char));
257   if (fInput.bad()) return -kBadRead;
258   fIBuffer = 4;
259   AliDebug(15, Form("  0x%03x  0x%03x  0x%03x  0x%03x    0x%010x  %6d", 
260                     ExtractW10(3, fBuffer), ExtractW10(2, fBuffer), 
261                     ExtractW10(1, fBuffer), ExtractW10(0, fBuffer), 
262                     fBuffer, fCurrent));
263   return fCurrent;
264 }
265
266 //____________________________________________________________________
267 AliFMDAltroIO::W10_t
268 AliFMDAltroReader::GetNextW10()
269 {
270   if (fIBuffer <= 0) {
271     Int_t ret;
272     if ((ret = ReadW40()) < 0) return ret;
273   }
274   fIBuffer--;
275   W10_t w10 = ExtractW10(fIBuffer, fBuffer); 
276   return w10;
277 }
278
279 //____________________________________________________________________
280 AliFMDAltroIO::W40_t
281 AliFMDAltroReader::GetNextW40() 
282 {
283   W40_t w40 = 0;
284   for (Int_t i = 3; i >= 0; i--) {
285     W10_t tmp  =  GetNextW10();
286     W40_t bits =  ConcatW40(i, tmp);
287     if (bits < 0) return bits;
288     w40        += bits;
289   }
290   return w40;
291 }
292
293 //====================================================================
294 ClassImp(AliFMDAltroWriter)
295 #if 0
296   ; // This is here to keep Emacs for indenting the next line
297 #endif
298
299 //____________________________________________________________________
300 AliFMDAltroWriter::AliFMDAltroWriter(std::ostream& stream) 
301   : fThreshold(0), fTotal(0), fOutput(stream)
302 {
303   AliDebug(15, "New AliFMDAltroWriter object");
304   fTime   = 0;
305   fLength = 0;
306   fLast   = 0;
307   // Write a dummy header
308   fHeader = fOutput.tellp();
309   if (fOutput.bad()) throw -kBadTell;
310   AliRawDataHeader header;
311   fOutput.write((char*)(&header), sizeof(header));
312   if (fOutput.bad()) throw -kBadWrite;
313   fBegin = fOutput.tellp();
314   if (fOutput.bad()) throw -kBadTell;
315 }
316
317 //____________________________________________________________________
318 Int_t
319 AliFMDAltroWriter::Flush() 
320 {
321   if (fIBuffer == 0) return 0;
322   fOutput.write((char*)&fBuffer, 5 * sizeof(char));
323   if (fOutput.bad()) return -kBadWrite;
324   // for (size_t i = 0; i < 4; i++) 
325   //   std::cout << "\t" << PRETTY_HEX(3, ExtractW10(i, fBuffer));
326   // std::cout << "\t" << PRETTY_HEX(10, fBuffer) << std::endl;
327   fTotal   += 5;
328   fIBuffer =  0;
329   fBuffer  =  0;
330   return 5;
331 }
332
333 //____________________________________________________________________
334 Int_t 
335 AliFMDAltroWriter::Close() 
336 {
337   Flush();
338   std::ostream::pos_type end = fOutput.tellp();
339   if (fOutput.bad()) return -kBadTell;
340   fOutput.seekp(fHeader, std::ios_base::beg);
341   if (fOutput.bad()) return -kBadSeek;
342   AliRawDataHeader header;
343   header.fSize = (size_t(end) - fHeader);
344   AliDebug(15, Form("Size set to %d (%d)", header.fSize, fTotal));
345   header.SetAttribute(0);
346   fOutput.write((char*)(&header), sizeof(header));
347   if (fOutput.bad()) return -kBadWrite;
348   fOutput.seekp(end);
349   if (fOutput.bad()) return -kBadSeek;
350   return sizeof(header);
351 }
352
353
354 //____________________________________________________________________
355 Int_t
356 AliFMDAltroWriter::AddSignal(UShort_t adc) 
357 {
358   Int_t ret = 0;
359   if (adc < fThreshold) 
360     ret = AddBunchTrailer();
361   else {
362     ret = AddToBuffer(adc);
363     fLength++;
364   }
365   fTime++;
366   if (ret < 0) AliError(Form("Failed to add signal %x: %s", ErrorString(ret)));
367   return ret;
368 }
369
370 //____________________________________________________________________
371 Int_t
372 AliFMDAltroWriter::AddChannelTrailer(UShort_t board, UShort_t chip, 
373                                      UShort_t channel)
374 {
375   UInt_t hwaddr = (channel & 0xf)+((chip & 0x3) << 4)+((board & 0x1f) << 7);
376   return AddChannelTrailer(hwaddr);
377 }
378
379 //____________________________________________________________________
380 Int_t
381 AliFMDAltroWriter::AddChannelTrailer(UInt_t hwaddr)
382 {
383   Int_t ret =0, tmp;
384   if ((tmp = AddBunchTrailer()) < 0) { 
385     AliError(Form("Failed to bad bunch trailer: %s", ErrorString(tmp)));
386     return tmp;
387   }
388   ret += tmp;
389   if ((tmp = AddFillWords())    < 0) { 
390     AliError(Form("Failed to bad fill words: %s", ErrorString(tmp)));
391     return tmp;
392   }
393   ret += tmp;
394   W40_t trailer = (fgkTrailerMask + hwaddr + ((fLast & 0x3ff) << 16));
395   fBuffer = trailer;
396   fIBuffer = 3;
397   ret     += 4;
398   if ((tmp = Flush()) < 0) {
399     AliError(Form("Failed to flush: %s", ErrorString(tmp)));
400     return tmp;
401   }
402   ret     += tmp;
403   fTime   =  0;
404   fLast   =  0;
405   return ret;
406 }
407
408 //____________________________________________________________________
409 Int_t
410 AliFMDAltroWriter::AddToBuffer(UShort_t x) 
411 {
412   W40_t tmp = ConcatW40(fIBuffer, x);
413   if (tmp < 0) return tmp;
414   fBuffer += tmp;
415   fIBuffer++;
416   fLast++;
417   Int_t ret = 0;
418   if (fIBuffer > 3 && (ret = Flush() < 0)) return ret;
419   return 1;
420 }
421
422 //____________________________________________________________________
423 Int_t
424 AliFMDAltroWriter::AddBunchTrailer()
425 {
426   if (fLength <= 0) return 0;    
427   Int_t ret = 0, tmp;
428   if ((tmp = AddToBuffer(fTime))     < 0) return tmp;
429   ret += tmp;
430   if ((tmp = AddToBuffer(fLength+2)) < 0) return tmp;
431   ret += tmp;
432   fLength = 0;
433   return ret;
434 }
435
436 //____________________________________________________________________
437 Int_t
438 AliFMDAltroWriter::AddFillWords() 
439 {
440   Int_t ret = 0, tmp;
441   if (fIBuffer == 0) return ret;
442   for (Int_t i = fIBuffer; i < 4; i++) { 
443     if ((tmp = AddToBuffer(0x2aa)) < 0) return tmp;
444     ret += tmp;
445     fLast--; 
446   }
447   if ((tmp = Flush() < 0)) return tmp;
448   return ret;
449 }
450
451 //_____________________________________________________________________________
452 //
453 // EOF
454 //