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