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