98d1d681274f2cce537b3ac2e02a669aa828ad6c
[u/mrichter/AliRoot.git] / MUON / AliMUONRawWriter.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 // MUON Raw Data generaton in ALICE-MUON
21 // This class version 3 (further details could be found in Alice-note)
22 //
23 // Implemented non-constant buspatch numbers for tracking
24 // with correct DDL id (first guess)
25 // (Ch. Finck, dec 2005)
26 //
27 // Digits2Raw:
28 // Generates raw data for MUON tracker and finally for trigger
29 // Using real mapping (inverse) for tracker
30 // For trigger there is no mapping (mapping could be found in AliMUONTriggerCircuit)
31 // Ch. Finck, July 04
32 // Use memcpy instead of assignment elt by elt
33 // Introducing variable DSP numbers, real manu numbers per buspatch for st12
34 // Implemented scaler event for Trigger
35 // Ch. Finck, Jan. 06
36 // Using bus itr in DDL instead of simple incrementation
37 // treat correctly the DDL & buspatch for station 3.
38 // Using informations from AliMUONTriggerCrateStore for 
39 // empty slots and non-notified cards in trigger crates.
40 // Ch. Finck, August 06.
41 // 
42 ////////////////////////////////////
43
44 #include "AliMUONRawWriter.h"
45
46 #include "AliBitPacking.h" 
47 #include "AliDAQ.h"
48 #include "AliLog.h"
49 #include "AliMUON.h"
50 #include "AliMUONBlockHeader.h"
51 #include "AliMUONBusStruct.h"
52 #include "AliMUONConstants.h"
53 #include "AliMUONDarcHeader.h"
54 #include "AliMUONData.h"
55 #include "AliMUONDigit.h"
56 #include "AliMUONDspHeader.h"
57 #include "AliMUONGlobalTrigger.h"
58 #include "AliMUONLocalStruct.h"
59 #include "AliMUONLocalTrigger.h"
60 #include "AliMUONLocalTriggerBoard.h"
61 #include "AliMUONRegHeader.h"
62 #include "AliMUONTriggerCrate.h"
63 #include "AliMUONTriggerCrateStore.h"
64 #include "AliMpBusPatch.h"
65 #include "AliMpDEManager.h"
66 #include "AliMpExMap.h"
67 #include "AliMpIntPair.h"
68 #include "AliMpConstants.h"
69 #include "TList.h"
70 #include "AliMpPad.h"
71 #include "AliMpPlaneType.h"
72 #include "AliMpSegFactory.h"
73 #include "AliMpStationType.h"
74 #include "AliMpVSegmentation.h"
75 #include "AliRawReader.h"
76 #include "TObjArray.h"
77 #include "TStopwatch.h"
78
79 ClassImp(AliMUONRawWriter) // Class implementation in ROOT context
80
81 Int_t AliMUONRawWriter::fgManuPerBusSwp1B[12]  = {1, 27, 53, 79, 105, 131, 157, 183, 201, 214, 224, 232};
82 Int_t AliMUONRawWriter::fgManuPerBusSwp1NB[12] = {1, 27, 53, 79, 105, 131, 157, 183, 201, 214, 225, 233};
83
84 Int_t AliMUONRawWriter::fgManuPerBusSwp2B[12]  = {1, 27, 53, 79, 105, 131, 157, 183, 201, 214, 226, 246};
85 Int_t AliMUONRawWriter::fgManuPerBusSwp2NB[12] = {1, 27, 53, 79, 105, 131, 157, 183, 201, 214, 227, 245};
86
87 namespace 
88 {
89   enum ETimer { kWriteTracker, kWriteTrigger, kDigitLoop, kGetBusPatch, kTest, kLast };
90 }
91
92 //__________________________________________________________________________
93 AliMUONRawWriter::AliMUONRawWriter(AliMUONData* data)
94   : TObject(),
95     fMUONData(data),
96     fBlockHeader(new AliMUONBlockHeader()),
97     fDspHeader(new AliMUONDspHeader()),
98     fDarcHeader(new AliMUONDarcHeader()),
99     fRegHeader(new AliMUONRegHeader()),
100     fLocalStruct(new AliMUONLocalStruct()),
101     fBusPatchManager(new AliMpBusPatch()),
102     fCrateManager(new AliMUONTriggerCrateStore()),
103     fScalerEvent(kFALSE),
104     fHeader(),
105     fTimers(new TStopwatch[kLast]),
106     fSegFactory(new AliMpSegFactory())
107
108 {
109   //
110   // Standard Constructor
111   //
112   AliDebug(1,"Standard ctor");
113   fFile[0] = fFile[1] = 0x0;  
114   fFile[2] = fFile[3] = 0x0;  
115
116   // setting data key to default value (only for writting)
117   fBlockHeader->SetDataKey(fBlockHeader->GetDefaultDataKey());
118   fDspHeader->SetDataKey(fDspHeader->GetDefaultDataKey());
119
120   // bus patch managers
121   fBusPatchManager->ReadBusPatchFile();
122
123   // Crate manager
124   fCrateManager->ReadFromFile();
125
126   // timers
127   for ( Int_t i = 0; i < kLast; ++i )
128   {
129     fTimers[i].Start(kTRUE); 
130     fTimers[i].Stop();
131   }
132   
133 }
134
135 //__________________________________________________________________________
136 AliMUONRawWriter::AliMUONRawWriter()
137   : TObject(),
138     fMUONData(0),
139     fBlockHeader(0),
140     fDspHeader(0),
141     fDarcHeader(0),
142     fRegHeader(0),
143     fLocalStruct(0),
144     fBusPatchManager(0),
145     fCrateManager(0x0),
146     fScalerEvent(kFALSE),
147     fHeader(),
148     fTimers(0),
149     fSegFactory(0x0)
150 {
151   //
152   // Default Constructor
153   //
154   AliDebug(1,"Default ctor");   
155   fFile[0] = fFile[1] = 0x0;  
156   fFile[2] = fFile[3] = 0x0;  
157
158 }
159
160 //__________________________________________________________________________
161 AliMUONRawWriter::~AliMUONRawWriter(void)
162 {
163   //
164   // Destructor
165   //
166   AliDebug(1,"dtor");
167   
168   delete fBlockHeader;
169   delete fDspHeader;
170   delete fDarcHeader;
171   delete fRegHeader;
172   delete fLocalStruct;
173
174   delete fBusPatchManager;
175   delete fCrateManager;
176
177   delete fSegFactory;
178   
179   for ( Int_t i = 0; i < kLast; ++i )
180   {
181     AliDebug(1, Form("Execution time (timer %d) : R:%7.2fs C:%7.2fs",i,
182                  fTimers[i].RealTime(),fTimers[i].CpuTime()));
183   }
184   
185   delete[] fTimers;
186 }
187
188 //______________________________________________________________________________
189 //void
190 //AliMUONRawWriter::CheckDigits()
191 //{
192 //  std::map<int,std::map<int,int> > m;
193 //  
194 //  for (Int_t iSt = 0; iSt < AliMUONConstants::NTrackingCh()/2; ++iSt) 
195 //  {
196 //    for (Int_t iCh = iSt*2; iCh <= iSt*2 + 1; ++iCh) 
197 //    {      
198 //      TClonesArray* muonDigits = fMUONData->Digits(iCh);
199 //      for (Int_t idig = 0; idig < muonDigits->GetEntriesFast(); idig++) 
200 //      {        
201 //        AliMUONDigit* digit = (AliMUONDigit*) muonDigits->UncheckedAt(idig);
202 //        Int_t busPatchId = GetBusPatch(*digit);
203 //        m[busPatchId][digit->ManuId()]++;
204 //      }
205 //    } 
206 //  }
207 //  
208 //  std::map<int,std::map<int,int> >::const_iterator it;
209 //  
210 //  Int_t nManuMax(0);
211 //  
212 //  for ( it = m.begin(); it != m.end(); ++it )
213 //  {
214 //    AliDebug(1,Form("BusPatch %3d has %3d manus",it->first,it->second.size()));
215 //    nManuMax = std::max((Int_t)it->second.size(),nManuMax);
216 //    std::map<int,int>::const_iterator it2;
217 //    for ( it2 = it->second.begin(); it2 != it->second.end(); ++it2 )
218 //    {
219 //      AliDebug(1,Form("        BusPatch %3d Manu %4d Nch %3d",it->first,it2->first,it2->second));
220 //    }
221 //  }
222 //  AliDebug(1,Form("Max manus per busPatch : %3d",nManuMax));
223 //}
224
225 //____________________________________________________________________
226 Int_t AliMUONRawWriter::Digits2Raw()
227 {
228   //
229   // convert digits of the current event to raw data
230   //
231   Int_t idDDL;
232   Char_t name[255];
233
234   fMUONData->GetLoader()->LoadDigits("READ");
235
236   fMUONData->SetTreeAddress("D,GLT");
237
238   fMUONData->ResetDigits();
239   fMUONData->ResetTrigger();
240   
241   // This will get both tracker and trigger digits.
242   fMUONData->GetDigits();
243   
244 //  CheckDigits();
245
246   // tracking chambers
247   
248   for (Int_t iSt = 0; iSt < AliMUONConstants::NTrackingCh()/2; ++iSt) {
249
250     // open files for one station
251     // cos station 3, 1/4 of DE's from 2 chambers has same DDL number 
252     idDDL = iSt * 4;
253     strcpy(name,AliDAQ::DdlFileName("MUONTRK",idDDL));
254     fFile[0] = fopen(name,"w");
255
256     idDDL = (iSt * 4) + 1;
257     strcpy(name,AliDAQ::DdlFileName("MUONTRK",idDDL));
258     fFile[1] = fopen(name,"w");
259
260     idDDL =  (iSt * 4) + 2;;
261     strcpy(name,AliDAQ::DdlFileName("MUONTRK",idDDL));
262     fFile[2] = fopen(name,"w");
263
264     idDDL =  (iSt * 4) + 3;
265     strcpy(name,AliDAQ::DdlFileName("MUONTRK",idDDL));
266     fFile[3] = fopen(name,"w");
267
268     WriteTrackerDDL(iSt);
269   
270     // reset and close when station has been processed
271     fclose(fFile[0]);
272     fclose(fFile[1]);
273     fclose(fFile[2]);
274     fclose(fFile[3]);
275      
276   }
277  
278   AliDebug(1,"Tracker written");
279   
280   // trigger chambers
281  
282   // open files
283   idDDL = 0;// MUTR
284   strcpy(name,AliDAQ::DdlFileName("MUONTRG",idDDL));
285   fFile[0] = fopen(name,"w");
286
287   idDDL = 1;// MUTR
288   strcpy(name,AliDAQ::DdlFileName("MUONTRG",idDDL));
289   fFile[1] = fopen(name,"w");
290
291   WriteTriggerDDL();
292   
293   // reset and close
294   fclose(fFile[0]);
295   fclose(fFile[1]);
296
297   AliDebug(1,"Trigger written");
298
299   fMUONData->ResetDigits();
300   fMUONData->ResetTrigger();  
301   fMUONData->GetLoader()->UnloadDigits();
302
303   AliDebug(1,"muondata reset");
304   
305   return kTRUE;
306 }
307
308 //____________________________________________________________________
309 Int_t AliMUONRawWriter::WriteTrackerDDL(Int_t iSt)
310 {
311   // writing DDL for tracker
312   // used inverse mapping
313   //
314   fTimers[kWriteTracker].Start(kFALSE);
315   
316   static const Int_t kMAXADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
317
318   // resets
319   TClonesArray* muonDigits = 0;
320
321   // DDL header
322   Int_t headerSize = sizeof(fHeader)/4;
323
324   // DDL event one per half chamber
325
326   // raw data
327   Char_t parity = 0x4;
328   UShort_t manuId = 0;
329   UChar_t channelId = 0;
330   UShort_t charge = 0;
331   Int_t busPatchId = 0;
332   UInt_t word;
333
334
335   // Dsp length
336   Int_t totalDspLength;
337   Int_t dspLength;
338
339   // block length
340   Int_t totalBlkLength;
341   Int_t blkLength; 
342   
343   // total DDL length
344   Int_t totalDDLLength;
345
346   // indexes
347   Int_t index;
348   Int_t indexDsp;
349   Int_t indexBlk;
350
351   // buffer size (max'ed out)
352   // (((43 manus max per bus patch *64 channels + 4 bus patch words) * 5 bus patch 
353   //   + 10 dsp words)*5 dsps + 8 block words)*2 blocks 
354   static const Int_t kBufferSize = (((43*64 + 4)*5 + 10)*5 + 8)*2;
355   
356   Int_t nDigits;
357
358   AliMpExMap busPatchMap(kTRUE);
359   
360   fTimers[kDigitLoop].Start(kFALSE);
361   
362   for (Int_t iCh = iSt*2; iCh <= iSt*2 + 1; ++iCh) {
363
364     muonDigits = fMUONData->Digits(iCh);
365     
366     nDigits = muonDigits->GetEntriesFast();
367     
368     // loop over digit
369     for (Int_t idig = 0; idig < nDigits; ++idig) {
370       
371       AliMUONDigit* digit = static_cast<AliMUONDigit*>(muonDigits->UncheckedAt(idig));
372       
373       charge = digit->ADC();
374       if ( charge > kMAXADC )
375       {
376         // This is most probably an error in the digitizer (which should insure
377         // the adc is below kMAXADC), so make it a (non-fatal) error indeed.
378         AliError(Form("adc value %d above %x for ch %d . Setting to %x. Digit is:",iCh,
379                       charge,kMAXADC,kMAXADC));
380         StdoutToAliError(digit->Print());
381         charge = kMAXADC;
382       }
383       
384       // inverse mapping
385       fTimers[kGetBusPatch].Start(kFALSE);
386       busPatchId = GetBusPatch(*digit);
387       fTimers[kGetBusPatch].Stop();
388       if (busPatchId<0) continue;
389       
390       fTimers[kTest].Start(kFALSE);
391       busPatchId = GetBusPatch(*digit);
392       fTimers[kTest].Stop();
393       
394       if ( digit->ManuId() > 0x7FF || digit->ManuId() < 0 ||
395            digit->ManuChannel() > 0x3F || digit->ManuChannel() < 0 )
396       {
397         StdoutToAliError(digit->Print(););
398         AliFatal("ManuId,ManuChannel are invalid for the digit above.");
399       }
400       
401       manuId = ( digit->ManuId() & 0x7FF ); // 11 bits
402       channelId = ( digit->ManuChannel() & 0x3F ); // 6 bits
403             
404       //packing word
405       word = 0;
406       AliBitPacking::PackWord((UInt_t)manuId,word,18,28);
407       AliBitPacking::PackWord((UInt_t)channelId,word,12,17);
408       AliBitPacking::PackWord((UInt_t)charge,word,0,11);
409       
410       // parity word
411       parity = word & 0x1;
412       for (Int_t i = 1; i <= 30; ++i) 
413         parity ^=  ((word >> i) & 0x1);
414       AliBitPacking::PackWord((UInt_t)parity,word,31,31);
415       
416       AliMUONBusStruct* busStruct = 
417         static_cast<AliMUONBusStruct*>(busPatchMap.GetValue(busPatchId));
418       
419       if (!busStruct)
420       {
421         busStruct = new AliMUONBusStruct;
422         busStruct->SetDataKey(busStruct->GetDefaultDataKey());
423         busStruct->SetBusPatchId(busPatchId);
424         busStruct->SetLength(0);
425         busPatchMap.Add(busPatchId,busStruct);
426       }
427
428       // set sub Event
429       busStruct->AddData(word);
430       
431     } // idig
432   } // loop over chamber in station
433     
434   fTimers[kDigitLoop].Stop();
435   
436   // getting info for the number of buspatches
437   Int_t iBusPatch;
438   Int_t length;
439   Int_t iBusPerDSP[5];//number of bus patches per DSP
440   Int_t iDspMax; //number max of DSP per block
441   Int_t iFile = 0;
442
443   AliMUONBusStruct* busStructPtr(0x0);
444
445   // open DDL files, 4 per station
446   for (Int_t iDDL = iSt*4; iDDL < 4 + iSt*4; ++iDDL) {
447
448     fBusPatchManager->ResetBusItr(iDDL);
449     fBusPatchManager->GetDspInfo(iDDL, iDspMax, iBusPerDSP);
450
451     Int_t buffer[kBufferSize];
452     
453     totalDDLLength = 0;
454
455     indexBlk = 0;
456     indexDsp = 0;
457     index = 0;
458
459     // two blocks A and B per DDL
460     for (Int_t iBlock = 0; iBlock < 2; ++iBlock) {
461       
462       // block header
463       length = fBlockHeader->GetHeaderLength();
464       memcpy(&buffer[index],fBlockHeader->GetHeader(),length*4);
465       indexBlk = index;
466       index += length; 
467       
468       // 5 DSP's max per block
469       for (Int_t iDsp = 0; iDsp < iDspMax; ++iDsp) {
470         
471         // DSP header
472         length = fDspHeader->GetHeaderLength();
473         memcpy(&buffer[index],fDspHeader->GetHeader(),length*4);
474         indexDsp = index;
475         index += length; 
476         
477         // 5 buspatches max per DSP
478         for (Int_t i = 0; i < iBusPerDSP[iDsp]; i++) {
479           
480           iBusPatch = fBusPatchManager->NextBusInDDL(iDDL);
481           
482           // iteration over bus patch in DDL
483           if (iBusPatch == -1) {
484             AliWarning(Form("Error in bus itr in DDL %d\n", iDDL));
485             continue;
486           }
487           
488           // 4 DDL's per station, condition needed for station 3
489           iFile = iDDL - iSt*4; // works only if DDL begins at zero (as it should be) !!!
490           
491           busStructPtr = static_cast<AliMUONBusStruct*>(busPatchMap.GetValue(iBusPatch));
492           
493           // check if buspatchid has digit
494           if (busStructPtr) {
495             // add bus patch structure header
496             length = busStructPtr->GetHeaderLength();
497             memcpy(&buffer[index],busStructPtr->GetHeader(),length*4);
498             index += length;
499             
500             // add bus patch data
501             length = busStructPtr->GetLength();
502             memcpy(&buffer[index],busStructPtr->GetData(),length*4);
503             index += length;
504             
505             if (AliLog::GetGlobalDebugLevel() == 3) {
506               for (Int_t j = 0; j < busStructPtr->GetLength(); j++) {
507                 printf("busPatchId %d, manuId %d channelId %d\n", busStructPtr->GetBusPatchId(), 
508                        busStructPtr->GetManuId(j), busStructPtr->GetChannelId(j));
509               }
510             }
511           } else {
512             // writting anyhow buspatch structure (empty ones)
513             buffer[index++] = busStructPtr->GetDefaultDataKey(); // fill it also for empty data size
514             buffer[index++] = busStructPtr->GetHeaderLength(); // header length
515             buffer[index++] = 0; // raw data length
516             buffer[index++] = iBusPatch; // bus patch
517           }
518         } // bus patch
519         
520         // check if totalLength even
521         // set padding word in case
522         // Add one word 0xBEEFFACE at the end of DSP structure
523         totalDspLength  = index - indexDsp;
524         if ((totalDspLength % 2) == 1) { 
525           buffer[indexDsp + fDspHeader->GetHeaderLength() - 2] = 1;
526           buffer[index++] = fDspHeader->GetDefaultPaddingWord();
527           totalDspLength++;
528         }
529         
530         dspLength          = totalDspLength - fDspHeader->GetHeaderLength();
531         
532         buffer[indexDsp+1] = totalDspLength; // dsp total length
533         buffer[indexDsp+2] = dspLength; // data length  
534         
535       } // dsp
536       
537       totalBlkLength  = index - indexBlk;
538       blkLength       = totalBlkLength - fBlockHeader->GetHeaderLength();
539       totalDDLLength += totalBlkLength;
540       
541       buffer[indexBlk+1] = totalBlkLength; // total block length
542       buffer[indexBlk+2] = blkLength;
543       
544     } // block
545     
546     //writting onto disk
547     // write DDL 1 - 4
548     // total length in bytes
549     fHeader.fSize = (totalDDLLength + headerSize) * 4;
550       
551     fwrite((char*)(&fHeader),headerSize*4,1,fFile[iFile]);
552     fwrite(buffer,sizeof(int),index,fFile[iFile]);
553   }
554   
555   fTimers[kWriteTracker].Stop();
556   return kTRUE;
557 }
558
559 //____________________________________________________________________
560 Int_t AliMUONRawWriter::GetBusPatch(Int_t detElemId, Int_t manuId) const
561 {
562   //
563   // Determine the BusPatch this digit belongs to.
564   //
565   
566   Int_t* ptr = 0;
567     
568   AliMpPlaneType plane = 
569     (manuId & AliMpConstants::ManuMask(kNonBendingPlane)) ? 
570     kNonBendingPlane : kBendingPlane; 
571   
572   AliMpStationType stationType = AliMpDEManager::GetStationType(detElemId);
573   
574   if ( stationType == kStation1 || stationType == kStation2 )
575   {
576     if (plane == kBendingPlane) 
577     {
578       ptr = &fgManuPerBusSwp1B[0];
579     }
580     else 
581     {
582       ptr = &fgManuPerBusSwp1NB[0];
583     }
584   }
585   else
586   {
587     if (plane == kBendingPlane)
588     {
589       ptr = &fgManuPerBusSwp2B[0];
590     }
591     else
592     {
593       ptr = &fgManuPerBusSwp2NB[0];
594     }
595   }
596   
597   // Getting buspatch id
598   TArrayI* vec = fBusPatchManager->GetBusfromDE(detElemId);
599   Int_t pos = 0;
600   
601   Int_t m = ( manuId & 0x3FF ); // remove bit 10
602                                         //FIXME : how can we remove that condition
603                                         // on the 10-th bit ? All the rest need not any knowledge about it,
604                                         // can't we find a way to get manu<->buspatch transparent to this too ?
605   
606   if ( stationType == kStation1 || stationType == kStation2 )
607   {
608     for (pos = 11; pos >=0 ; --pos)
609     {
610       if (m >= ptr[pos]) break;
611     }
612   }
613   else 
614   {
615     // offset of 100 in manuId for following bus patch
616     pos = m/100;
617   }
618   
619   
620   if (pos >(Int_t) vec->GetSize())
621   {
622     AliError(Form("pos greater %d than size %d manuId %d detElemId %d \n", 
623                   pos, (Int_t)vec->GetSize(), manuId, detElemId));
624     AliError(Form("Chamber %s Plane %s manuId %d m %d",
625                   StationTypeName(stationType).Data(),
626                   PlaneTypeName(plane).Data(),
627                   manuId,
628                   m));
629     return -1;
630   }
631   
632   Int_t busPatchId = vec->At(pos);
633   
634   if ( ( stationType == kStation1 || stationType == kStation2 ) &&
635        ( plane == kNonBendingPlane ) )
636   {
637     busPatchId += 12;
638   }
639   
640   return busPatchId;
641 }
642
643 //____________________________________________________________________
644 Int_t AliMUONRawWriter::GetBusPatch(const AliMUONDigit& digit) const
645 {
646   //
647   // Determine the BusPatch this digit belongs to.
648   //
649   return GetBusPatch(digit.DetElemId(),digit.ManuId());
650 }
651
652 //____________________________________________________________________
653 Int_t AliMUONRawWriter::WriteTriggerDDL()
654 {
655   //
656   // Write trigger DDL
657   //
658   fTimers[kWriteTrigger].Start(kFALSE);
659   
660  // DDL event one per half chamber
661
662   // stored local id number 
663   TArrayI isFired(256);
664   isFired.Reset();
665
666
667  // DDL header size
668   Int_t headerSize = sizeof(AliRawDataHeader)/4;
669
670   TClonesArray* localTrigger;
671   TClonesArray* globalTrigger;
672   AliMUONGlobalTrigger* gloTrg;
673   AliMUONLocalTrigger* locTrg = 0x0;
674
675   // global trigger for trigger pattern
676   globalTrigger = fMUONData->GlobalTrigger(); 
677   gloTrg = (AliMUONGlobalTrigger*)globalTrigger->UncheckedAt(0);
678   if (!gloTrg) 
679   {
680     fTimers[kWriteTrigger].Stop();
681     return 0;
682   }
683   
684   Int_t gloTrigResp = gloTrg->GetGlobalResponse();
685
686   // local trigger 
687   localTrigger = fMUONData->LocalTrigger();    
688
689   UInt_t word;
690   Int_t* buffer = 0;
691   Int_t index;
692   Int_t iEntries = 0;
693   Int_t iLocCard, locCard;
694   Char_t locDec, trigY, posY, posX, regOut;
695   UInt_t regInpLpt;
696   UInt_t regInpHpt;
697
698   Int_t devX;
699   Int_t version = 1; // software version
700   Int_t eventPhys = 1; // trigger type: 1 for physics, 0 for software
701   Int_t serialNb = 0xF; // serial nb of card: all bits on for the moment
702   Int_t globalFlag = 0; // set to 1 if global info present in DDL else set to 0
703
704   // size of headers
705   static const Int_t kDarcHeaderLength   = fDarcHeader->GetDarcHeaderLength();
706   static const Int_t kGlobalHeaderLength = fDarcHeader->GetGlobalHeaderLength();
707   static const Int_t kDarcScalerLength   = fDarcHeader->GetDarcScalerLength();
708   static const Int_t kGlobalScalerLength = fDarcHeader->GetGlobalScalerLength();
709   static const Int_t kRegHeaderLength    = fRegHeader->GetHeaderLength();
710   static const Int_t kRegScalerLength    = fRegHeader->GetScalerLength();
711   static const Int_t kLocHeaderLength    = fLocalStruct->GetLength();
712   static const Int_t kLocScalerLength    = fLocalStruct->GetScalerLength();
713
714   // [16(local)*6 words + 6 words]*8(reg) + 8 words = 824 
715   static const Int_t kBufferSize = (16 * (kLocHeaderLength+1) +  (kRegHeaderLength+1))* 8 
716       +  kDarcHeaderLength + kGlobalHeaderLength + 2;
717
718   // [16(local)*51 words + 16 words]*8(reg) + 8 + 10 + 8 words scaler event 6682 words
719   static const Int_t kScalerBufferSize = (16 * (kLocHeaderLength +  kLocScalerLength +1) +  
720                                          (kRegHeaderLength + kRegScalerLength +1))* 8 +
721                                          (kDarcHeaderLength + kDarcScalerLength + 
722                                           kGlobalHeaderLength + kGlobalScalerLength + 2);
723   if(fScalerEvent)
724     eventPhys = 0; //set to generate scaler events
725
726   Int_t nEntries = (Int_t) (localTrigger->GetEntries());// 234 local cards
727   // stored the local card id that's fired
728   for (Int_t i = 0; i <  nEntries; i++) {
729     locTrg = (AliMUONLocalTrigger*)localTrigger->At(i);
730     isFired[locTrg->LoCircuit()] = 1; // storing local boards with informations
731   }
732
733   if (!nEntries)
734     AliDebug(1, "No Trigger information available");
735
736   if(fScalerEvent)
737     buffer = new Int_t [kScalerBufferSize];
738   else
739     buffer = new Int_t [kBufferSize];
740
741   // reset crate
742
743   // open DDL file, on per 1/2 chamber
744   for (Int_t iDDL = 0; iDDL < 2; iDDL++) {
745
746     index = 0; 
747
748     if (iDDL == 0) // suppose global info in DDL one
749       globalFlag = 1;
750     else 
751       globalFlag = 0;
752
753     word = 0;
754     // set darc status word
755     // see AliMUONDarcHeader.h for details
756     AliBitPacking::PackWord((UInt_t)eventPhys,word,30,30);
757     AliBitPacking::PackWord((UInt_t)serialNb,word,20,23);
758     AliBitPacking::PackWord((UInt_t)globalFlag,word,10,10);
759     AliBitPacking::PackWord((UInt_t)version,word,12,19);
760     fDarcHeader->SetWord(word);
761
762     memcpy(&buffer[index], fDarcHeader->GetHeader(), (kDarcHeaderLength)*4); 
763     index += kDarcHeaderLength;
764
765     // no global input for the moment....
766     if (iDDL == 0)
767      fDarcHeader->SetGlobalOutput(gloTrigResp);
768     else 
769      fDarcHeader->SetGlobalOutput(0);
770
771     if (fScalerEvent) {
772       // 6 DARC scaler words
773       memcpy(&buffer[index], fDarcHeader->GetDarcScalers(),kDarcScalerLength*4);
774       index += kDarcScalerLength;
775     }
776     // end of darc word
777     buffer[index++] = fDarcHeader->GetEndOfDarc();
778
779     // 4 words of global board input + Global board output
780     memcpy(&buffer[index], fDarcHeader->GetGlobalInput(), (kGlobalHeaderLength)*4); 
781     index += kGlobalHeaderLength; 
782
783     if (fScalerEvent) {
784       // 10 Global scaler words
785       memcpy(fDarcHeader->GetGlobalScalers(), &buffer[index], kGlobalScalerLength*4);
786       index += kGlobalScalerLength;
787     }
788
789     // end of global word
790     buffer[index++] = fDarcHeader->GetEndOfGlobal();
791
792     // 8 regional cards per DDL
793     for (Int_t iReg = 0; iReg < 8; iReg++) {
794
795       // crate info
796       AliMUONTriggerCrate* crate = fCrateManager->Crate(iDDL, iReg);
797
798       if (!crate) 
799         AliWarning(Form("Missing crate number %d in DDL %d\n", iReg, iDDL));
800
801       // Regional card header
802       word = 0;
803
804       // set darc status word
805       fRegHeader->SetDarcWord(word);
806
807       regOut    = 0;
808       regInpHpt = regInpLpt = 0;
809       // fill darc word, not darc status for the moment (empty)
810       //see  AliMUONRegHeader.h for details
811       AliBitPacking::PackWord((UInt_t)eventPhys,word,31,31); 
812       AliBitPacking::PackWord((UInt_t)serialNb,word,19,24); 
813       AliBitPacking::PackWord((UInt_t)version,word,16,23);
814       AliBitPacking::PackWord((UInt_t)iReg,word,15,18);
815       AliBitPacking::PackWord((UInt_t)regOut,word,0,7); // waiting realistic output of AliMUONGlobalTrigger (oct 06 ?)
816       fRegHeader->SetWord(word);
817
818
819       // fill header later, need local response
820       Int_t indexReg = index;
821       index += kRegHeaderLength;
822
823       // 11 regional scaler word
824       if (fScalerEvent) {
825         memcpy(&buffer[index], fRegHeader->GetScalers(), kRegScalerLength*4);
826         index += kRegScalerLength;
827       }
828
829       // end of regional word
830       buffer[index++] = fRegHeader->GetEndOfReg();
831       
832       TObjArray *boards = crate->Boards();
833
834
835       // 16 local card per regional board
836       UShort_t localMask = 0x0;
837
838       for (Int_t iLoc = 0; iLoc < 16; iLoc++) {
839
840         // slot zero for Regional card
841         AliMUONLocalTriggerBoard* localBoard = (AliMUONLocalTriggerBoard*)boards->At(iLoc+1);
842
843         if (localBoard) { // if not empty slot
844
845           if ((iLocCard = localBoard->GetNumber()) != 0) {// if notified board
846
847             localMask |= (0x1 << iLoc); // local mask
848             if (isFired[iLocCard]) { // if card has triggered
849               locTrg  = (AliMUONLocalTrigger*)localTrigger->At(iEntries);
850               locCard = locTrg->LoCircuit();
851               locDec  = locTrg->GetLoDecision();
852               trigY = 0;
853               posY  = locTrg->LoStripY();
854               posX  = locTrg->LoStripX();
855               devX  = locTrg->LoDev();
856
857               AliDebug(4,Form("loctrg %d, posX %d, posY %d, devX %d\n", 
858                               locTrg->LoCircuit(),locTrg->LoStripX(),locTrg->LoStripY(),locTrg->LoDev()));
859             } else { //no trigger (see PRR chpt 3.4)
860               locDec = 0;
861               trigY = 1;
862               posY = 15;
863               posX = 0;
864               devX = 0x8;
865               // set local card id to -1
866               locCard = -1; 
867             }
868             // calculate regional input High and low Pt
869             UInt_t tmp1 = (locDec >> 2) & 0x3;
870             UInt_t tmp2 =  locDec & 0x3;
871             
872             regInpHpt |= tmp1 << (30 - iLoc*2);
873             regInpLpt |= tmp2 << (30 - iLoc*2);
874            
875             //packing word
876             word = 0;
877             AliBitPacking::PackWord((UInt_t)iLoc,word,19,22); //card id number in crate
878             AliBitPacking::PackWord((UInt_t)locDec,word,15,18);
879             AliBitPacking::PackWord((UInt_t)trigY,word,14,14);
880             AliBitPacking::PackWord((UInt_t)posY,word,10,13);
881             AliBitPacking::PackWord((UInt_t)devX,word,5,9);
882             AliBitPacking::PackWord((UInt_t)posX,word,0,4);
883
884             if (locCard == iLocCard) {
885               // add local cards structure
886               buffer[index++] = (locTrg->GetX1Pattern() | (locTrg->GetX2Pattern() << 16));
887               buffer[index++] = (locTrg->GetX3Pattern() | (locTrg->GetX4Pattern() << 16));
888               buffer[index++] = (locTrg->GetY1Pattern() | (locTrg->GetY2Pattern() << 16));
889               buffer[index++] = (locTrg->GetY3Pattern() | (locTrg->GetY4Pattern() << 16));
890               buffer[index++] = (Int_t)word; // data word
891               if (iEntries < nEntries-1)
892                 iEntries++;
893             } else {
894               buffer[index++] = 0; // 4 words for x1, x2, y1, y2
895               buffer[index++] = 0; 
896               buffer[index++] = 0; 
897               buffer[index++] = 0; 
898               buffer[index++] = (Int_t)word; // data word
899
900             }
901           } else {// number!=0
902           // fill with 10CDEAD word for 'non-notified' slots
903           for (Int_t i = 0; i < fLocalStruct->GetLength(); i++)
904             buffer[index++] = fLocalStruct->GetDisableWord(); 
905           }
906         } else { 
907           // fill with 10CDEAD word for empty slots
908           for (Int_t i = 0; i < fLocalStruct->GetLength(); i++)
909             buffer[index++] = fLocalStruct->GetDisableWord(); 
910         }// condition localBoard
911
912         // 45 regional scaler word
913         if (fScalerEvent) {
914           memcpy(&buffer[index], fLocalStruct->GetScalers(), kLocScalerLength*4);
915           index += kLocScalerLength;
916         }
917
918         // end of local structure words
919         buffer[index++] = fLocalStruct->GetEndOfLocal();
920
921       } // local card 
922       // fill regional header with local output
923       fRegHeader->SetInput(regInpLpt, 0);
924       fRegHeader->SetInput(regInpHpt, 1);
925       fRegHeader->SetMask(localMask);
926       memcpy(&buffer[indexReg],fRegHeader->GetHeader(),kRegHeaderLength*4);
927
928     } // Regional card
929     
930
931     // writting onto disk
932     // write DDL's
933     fHeader.fSize = (index + headerSize) * 4;// total length in bytes
934     fwrite((char*)(&fHeader),headerSize*4,1,fFile[iDDL]);
935     fwrite(buffer,sizeof(int),index,fFile[iDDL]);
936   
937   }
938   delete[] buffer;
939
940   fTimers[kWriteTrigger].Stop();
941   
942   return kTRUE;
943 }
944 //____________________________________________________________________
945 void AliMUONRawWriter::SetScalersNumbers()
946 {
947   // set numbers for scaler events for trigger headers
948   // since this is provided by the experiment
949   // put dummy numbers to check the monitoring
950
951   fDarcHeader->SetScalersNumbers();
952   fRegHeader->SetScalersNumbers();
953   fLocalStruct->SetScalersNumbers();
954  
955   fScalerEvent = kTRUE;
956 }
957