Gros chantier trigger:
[u/mrichter/AliRoot.git] / MUON / AliMUONTriggerIO.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 #include "AliMUONTriggerIO.h"
19 #include "AliMUONTriggerLut.h"
20 #include "AliMUONCalibParamNI.h"
21 #include "AliMUONVStore.h"
22
23 #include "AliMpCDB.h"
24 #include "AliMpHelper.h"
25 #include "AliMpConstants.h"
26 #include "AliMpDDL.h"
27 #include "AliMpFiles.h"
28 #include "AliMpDDLStore.h"
29 #include "AliMpLocalBoard.h"
30 #include "AliMpTriggerCrate.h"
31 #include "AliMUONGlobalCrateConfig.h"
32 #include "AliMUONRegionalTriggerConfig.h"
33 #include "AliMUONTriggerCrateConfig.h"
34
35 #include "AliLog.h"
36
37 #include <Riostream.h>
38 #include <TSystem.h>
39
40 /// \class AliMUONTriggerIO
41 ///
42 /// Handles read/write of masks and LUT to/from online files, 
43 /// to be used by Shuttle and Trigger DA.
44 /// 
45 /// \author Laurent Aphecetche, Christian Finck Subatech
46 /// \author Bogdan Vulpescu, LPC Clermont-Ferrand
47
48 /// \cond CLASSIMP
49 ClassImp(AliMUONTriggerIO)
50 /// \endcond
51
52
53 const UInt_t AliMUONTriggerIO::fgkLocalLutSize = 1 << 14; // 16384
54
55 //_____________________________________________________________________________
56 AliMUONTriggerIO::AliMUONTriggerIO() 
57     : TObject(), 
58       fRegionalTrigger(),
59       fGlobalCrate()
60 {
61   /// ctor
62 }
63
64 //_____________________________________________________________________________
65 AliMUONTriggerIO::AliMUONTriggerIO(const char* regionalFileToRead) 
66     :TObject(), 
67      fRegionalTrigger(),
68      fGlobalCrate()
69 {
70   /// ctor
71   ReadRegionalConfig(regionalFileToRead,0);
72 }
73
74 //_____________________________________________________________________________
75 AliMUONTriggerIO::~AliMUONTriggerIO()
76 {
77   /// dtor
78 }
79
80 //_____________________________________________________________________________
81 Bool_t 
82 AliMUONTriggerIO::DeCompAddress(UChar_t &ypos, UChar_t &ytri, UChar_t &xdev, UChar_t &xpos, 
83                                 UShort_t address) const
84 {  
85   /// decompose the 15-bits address
86   
87   UChar_t bitsYpos = 4;
88   UChar_t bitsYtri = 1;
89   UChar_t bitsXdev = 5;
90   //  UChar_t bitsXpos = 5;
91   
92   UShort_t maskYpos = 0x000F; // ...0 00001111
93   UShort_t maskYtri = 0x0001; // ...0 00000001
94   UShort_t maskXdev = 0x001F; // ...0 00011111
95   UShort_t maskXpos = 0x001F; // ...0 00011111
96   
97   ypos =  address                                  & maskYpos;
98   ytri = (address >>  bitsYpos)                    & maskYtri;
99   xdev = (address >> (bitsYpos+bitsYtri))          & maskXdev;
100   xpos = (address >> (bitsYpos+bitsYtri+bitsXdev)) & maskXpos;
101
102   // convert deviation format
103   // online: sign 1bit , dev 4bit
104   // sign    dev    trigger
105   // 0       1-15   mu-
106   // 1       1-15   mu+
107   // 0       0      mu+, mu- infinite momentum (unde)
108   // 1       0      no x-trigger
109   // offline: dev 5bit
110   // sign    dev    trigger
111   // -        0-14  mu-
112   // -       16-31  mu+
113   // -       15     mu+, mu- infinite momentum (unde)
114
115   Int_t iXdevOff, iXdevOn, iXdev, sign;
116   Bool_t trigx;
117
118   iXdev = xdev;
119
120   iXdevOn = sign = 0;
121   iXdevOn +=  iXdev & 0x0F;
122   sign    += (iXdev >> 4) & 0x01;
123   if (iXdevOn == 0) {
124     if (sign == 0) {
125       iXdevOff = 15;
126       trigx = kTRUE;
127     } else {
128       iXdevOff = 15;
129       trigx = kFALSE;
130     }
131   } else {
132     trigx = kTRUE;
133     if (sign == 0) {
134       iXdevOff = - iXdevOn + 15;  // gives range  0-14
135     } else {
136       iXdevOff = + iXdevOn + 15;  // gives range 16-30 !
137     }
138   }
139
140   xdev = iXdevOff;
141
142   return trigx;
143
144 }
145
146 //_____________________________________________________________________________
147 void 
148 AliMUONTriggerIO::FillLut(AliMUONTriggerLut& lut,
149                           Int_t icirc, UChar_t istripX, UChar_t idev,  
150                           Int_t lutLpt[16][2], Int_t lutHpt[16][2]) 
151 {
152   /// Fill the LUT histograms
153   
154   if (icirc == 0 && istripX == 0 && idev == 0) 
155   {
156     AliDebug(1,"Copy board, not filled ...");
157     return;
158   }
159   
160   Short_t iLptPlus, iLptMinu, iLptUnde;
161   Short_t iHptPlus, iHptMinu, iHptUnde;
162
163   iLptPlus = iLptMinu = iLptUnde = 0;
164   iHptPlus = iHptMinu = iHptUnde = 0;
165   
166   for (Int_t istripY=0; istripY<16; istripY++) 
167   {
168     if (lutLpt[istripY][1] == 0 && lutLpt[istripY][0] ==1)
169       iLptMinu=iLptMinu+(1 << istripY);
170     if (lutLpt[istripY][1] == 1 && lutLpt[istripY][0] ==0)
171       iLptPlus=iLptPlus+(1 << istripY);
172     if (lutLpt[istripY][1] == 1 && lutLpt[istripY][0] ==1)
173       iLptUnde=iLptUnde+(1 << istripY);
174     
175     if (lutHpt[istripY][1] == 0 && lutHpt[istripY][0] ==1)
176       iHptMinu=iHptMinu+(1 << istripY);
177     if (lutHpt[istripY][1] == 1 && lutHpt[istripY][0] ==0)
178       iHptPlus=iHptPlus+(1 << istripY);
179     if (lutHpt[istripY][1] == 1 && lutHpt[istripY][0] ==1)
180       iHptUnde=iHptUnde+(1 << istripY);
181     
182   } // loop on istripY
183   
184   lut.SetContent("LptMinu",icirc,istripX,idev,iLptMinu);
185   lut.SetContent("LptUnde",icirc,istripX,idev,iLptUnde);
186   lut.SetContent("LptPlus",icirc,istripX,idev,iLptPlus);
187
188   lut.SetContent("HptMinu",icirc,istripX,idev,iHptMinu);
189   lut.SetContent("HptUnde",icirc,istripX,idev,iHptUnde);
190   lut.SetContent("HptPlus",icirc,istripX,idev,iHptPlus);
191 }
192
193 //_____________________________________________________________________________
194 Int_t
195 AliMUONTriggerIO::ReadLocalMasks(const char* localFile, AliMUONVStore& localMasks) const
196 {
197   /// Fills the local masks store from file
198   
199   if ( !NofLocalBoards() )
200   {
201     AliError("No local board to read");
202     return 0;
203   }
204   
205   FILE* fp = fopen(gSystem->ExpandPathName(localFile),"r");
206   if (!fp)
207   {
208     AliError(Form("Could not read file %s",localFile));
209     return 0;
210   }
211   
212   UShort_t maskBuffer[8];
213   
214   Int_t nLocalBoards(0);
215   
216   while ( fread ( maskBuffer, 2, 8, fp ) )
217   {
218     Int_t localBoardId = LocalBoardId(nLocalBoards);
219     AliDebug(1,Form("LB %03d X1 %4x X2 %4x X3 %4x X4 %4x "
220                     "Y1 %4x Y2 %4x Y3 %4x Y4 %4x",
221                     localBoardId,
222                     maskBuffer[0],
223                     maskBuffer[1],
224                     maskBuffer[2],
225                     maskBuffer[3],
226                     maskBuffer[4],
227                     maskBuffer[5],
228                     maskBuffer[6],
229                     maskBuffer[7]));
230     
231     if ( localBoardId ) 
232     {
233       AliMUONVCalibParam* localBoard = new AliMUONCalibParamNI(1,8,localBoardId,0,0);
234       for ( Int_t index = 0; index < 8; ++index )
235       {
236         localBoard->SetValueAsInt(index,0,maskBuffer[index]);
237       }
238       localMasks.Add(localBoard);
239     }
240     
241     ++nLocalBoards;
242   }
243   
244   if ( nLocalBoards != NofLocalBoards() ) 
245   {
246     AliError(Form("Read %d out of %d local boards",
247                   nLocalBoards, NofLocalBoards()));
248   }
249   
250   fclose(fp);
251   
252   return nLocalBoards;
253 }
254
255 //_____________________________________________________________________________
256 void
257 AliMUONTriggerIO::ReadLocalLUT(AliMUONTriggerLut& lut,
258                                Int_t localBoardId,
259                                FILE* flut)
260 {
261   /// Read the LUT for one local board from an online file
262
263   UShort_t address;
264   
265   UChar_t buffer[fgkLocalLutSize];   // 32768 hpt/lpt addresses divided by two
266   UChar_t mask1 = 0xF0;
267   UChar_t mask2 = 0x0F;
268   UChar_t maskHpt = 0x0C;
269   UChar_t maskLpt = 0x03;
270   UChar_t lh, lpt, hpt;
271   
272   UChar_t xpos, xdev, ypos, ytri;
273   
274   Int_t lutLpt[16][2], lutHpt[16][2];
275
276   Int_t boardnr = localBoardId;
277   
278   AliDebug(1,Form("Reading LUT values for local board %d",boardnr));
279   
280   Int_t ny = 0;
281   Bool_t trigx = kFALSE;
282   
283   // read two lut addresses at once, 32768/2=16384 times
284   fread(buffer,fgkLocalLutSize,1,flut);
285
286   // create the 32767 addresses for the 4-bits lpt and hpt half-bytes
287   for (UShort_t ilut = 0; ilut < fgkLocalLutSize*2; ilut += 2) 
288   {
289     
290     // 1st 4-bits half-byte
291     address = ilut;   
292     lh = (buffer[ilut/2] & mask1) >> 4;
293     
294     // Lpt and Hpt response
295     hpt = (lh & maskHpt) >> 2;
296     lpt =  lh & maskLpt;
297     
298     // decompose the 15-bits address
299     trigx = DeCompAddress(ypos,ytri,xdev,xpos,address);
300     
301     // calculate group of y-strips
302     if (trigx && (ny < 16)) 
303     {
304       lutLpt[ny][0] =  lpt & 1;
305       lutLpt[ny][1] = (lpt & 2) >> 1;
306       lutHpt[ny][0] =  hpt & 1;
307       lutHpt[ny][1] = (hpt & 2) >> 1;
308       ny++;
309       if (ny == 16) 
310       {
311         ny = 0;
312         // ytri == 1 means no trigger in y-direction
313         if (ytri == 0) 
314         {
315           FillLut(lut,boardnr,xpos,xdev,lutLpt,lutHpt);
316         }
317       }
318     }
319     
320     // 2nd 4-bits half-byte
321     address = ilut+1; 
322     lh = (buffer[ilut/2] & mask2);
323     
324     // Lpt and Hpt response
325     hpt = (lh & maskHpt) >> 2;
326     lpt =  lh & maskLpt;
327     
328     // decompose the 15-bits address
329     trigx = DeCompAddress(ypos,ytri,xdev,xpos,address);
330     
331     // calculate group of y-strips
332     if (trigx && (ny < 16)) 
333     {
334       lutLpt[ny][0] =  lpt & 1;
335       lutLpt[ny][1] = (lpt & 2) >> 1;
336       lutHpt[ny][0] =  hpt & 1;
337       lutHpt[ny][1] = (hpt & 2) >> 1;
338       ny++;
339       if (ny == 16) 
340       {
341         ny = 0;
342         // ytri == 1 means no trigger in y-direction
343         if (ytri == 0) 
344         {
345           FillLut(lut,boardnr,xpos,xdev,lutLpt,lutHpt);
346         }
347       }
348     }
349   }
350 }
351
352 //_____________________________________________________________________________
353 Bool_t 
354 AliMUONTriggerIO::ReadLUT(const char* lutFileToRead, AliMUONTriggerLut& lut)
355 {
356   /// Fill the LUT object from online file
357   
358   if ( !NofLocalBoards() )
359   {
360     AliError("No local board id defined. Must read a regional file first");
361     return kFALSE;
362   }
363   
364   FILE* flut = fopen(gSystem->ExpandPathName(lutFileToRead),"rb");
365   if (!flut) 
366   {
367     AliError(Form("Could not read LUT file %s",lutFileToRead));
368     return kFALSE;
369   }   
370   
371   for ( Int_t i = 0; i < NofLocalBoards(); ++i ) 
372   {
373     ReadLocalLUT(lut,LocalBoardId(i),flut);
374   }
375   
376   fclose(flut);
377   
378   return kTRUE;
379   
380 }
381
382 //_____________________________________________________________________________
383 Bool_t 
384 AliMUONTriggerIO::ReadConfig(const char* localFile,
385                             const char* regionalFile,
386                             const char* globalFile,
387                             AliMUONVStore* localMasks,
388                             AliMUONRegionalTriggerConfig* regionalConfig,
389                             AliMUONGlobalCrateConfig* globalConfig)
390 {
391   /// Fill the various masks store from files
392   
393   if ( !regionalFile ) 
394   {
395     AliError("Must have a regional file name to proceeed");
396     return kFALSE;
397   }
398   
399   Int_t nCrates = ReadRegionalConfig(regionalFile, regionalConfig);
400   
401   if (!nCrates) return kFALSE;
402   
403   if (localMasks && localFile)
404   {
405     Int_t nLocal = ReadLocalMasks(localFile,*localMasks);
406     AliDebug(1,Form("Read masks for %d local boards",nLocal));
407   }
408   
409   Int_t nDarc = ReadGlobalConfig(globalFile, globalConfig);
410   AliDebug(1,Form("Read disable for %d DARC boards",nDarc));
411   
412   if (!nDarc) return kFALSE;
413   
414   return kTRUE;
415 }
416
417
418
419 //_____________________________________________________________________________
420  Int_t 
421  AliMUONTriggerIO::ReadGlobalConfig(const char* globalFile, AliMUONGlobalCrateConfig* globalConfig)
422 {
423   /// read the global crate file
424   /// the masks are disable bit for each crate, 8 per darc board
425   /// bit value 0 means enable, 1 means disable                                                 * 
426   
427   Int_t nDarc = 0;
428   if ( !(nDarc = globalConfig->ReadData(globalFile)) ) return 0;
429   
430   return nDarc;
431 }
432  
433 //_____________________________________________________________________________
434 Int_t
435 AliMUONTriggerIO::ReadRegionalConfig(const char* regionalFile, AliMUONRegionalTriggerConfig* regionalConfig)
436 {
437   /// Read regional file to fill  
438   Int_t nCrates = 0;
439   if ( !(nCrates = regionalConfig->ReadData(regionalFile)) ) return 0;
440
441   // read the mapping file also
442   if ( ! fRegionalTrigger.ReadData(regionalFile) ) return 0;
443
444   return nCrates;  
445 }
446
447
448 //_____________________________________________________________________________
449 Bool_t 
450 AliMUONTriggerIO::WriteLUT(const AliMUONTriggerLut& lut,
451                            const char* lutFileToWrite)
452 {
453   /// Convert an offline lut into an online (binary) lut file
454   
455   if ( !NofLocalBoards() )
456   {
457     AliError("No local board id defined. Must read a regional file first");
458     return kFALSE;
459   }
460   
461   FILE* flut = fopen(gSystem->ExpandPathName(lutFileToWrite),"wb");
462   if (!flut) 
463   {
464     AliError(Form("Could not create output LUT file %s",lutFileToWrite));
465     return kFALSE;
466   }   
467   
468   for ( Int_t i = 0; i < NofLocalBoards(); ++i ) 
469   {
470     WriteLocalLUT(lut,LocalBoardId(i),flut);
471   }
472   
473   fclose(flut);
474   
475   return kTRUE;
476 }
477
478
479 //_____________________________________________________________________________
480 Bool_t 
481 AliMUONTriggerIO::WriteConfig(const char* localFile,
482                              const char* regionalFile,
483                              const char* globalFile,
484                              AliMUONVStore* localMasks,
485                     AliMUONRegionalTriggerConfig* regionalConfig,
486                     AliMUONGlobalCrateConfig* globalConfig) const
487 {
488 /// write config files
489
490     Bool_t ok;
491     ok  = WriteLocalMasks(localFile, *localMasks, regionalConfig);
492     ok &= WriteRegionalConfig(regionalFile, regionalConfig);
493     ok &= WriteGlobalConfig(globalFile, globalConfig);
494     
495     return ok;
496
497
498 }
499
500  
501  //_____________________________________________________________________________
502 Bool_t 
503 AliMUONTriggerIO::WriteGlobalConfig(const char* globalFile, AliMUONGlobalCrateConfig* globalConfig) const
504 {
505     /// write global config
506
507   ofstream out;
508   Int_t disable = 0;
509   
510   out.open(globalFile);
511   if (!out.good())
512   {
513     AliError(Form("Could not create output global file %s", globalFile));
514     return kFALSE;
515   }
516    
517   out << globalConfig->GetName() << endl;
518   out << globalConfig->GetGlobalCrateEnable() << endl;
519   
520   // Jtag
521   out << globalConfig->GetJtagName() << endl;
522   out << Form("0x%08x", globalConfig->GetJtagVmeAddr()) << endl;
523   out << Form("%d %d %d", globalConfig->GetJtagClockDiv(), 
524               globalConfig->GetJtagRxPhase(), globalConfig->GetJtagRdDelay()) << endl;
525  
526   for (Int_t i = 0; i < globalConfig->GetJtagNofLines(); ++i)
527     out << Form("%d ", globalConfig->GetEnableJtag(i));
528   out << endl;
529
530   
531   for (Int_t i = 0; i < globalConfig->GetJtagNofLines(); ++i)
532   {
533     out << i << endl;
534     for (Int_t j = 0; j < globalConfig->GetJtagNofLines(); ++j)
535       out << Form(" %s", globalConfig->GetJtagCrateName(i,j).Data()) << endl;
536   }
537   
538   // first darc board
539   out << globalConfig->GetFirstDarcName() << endl;
540   out << Form("0x%08x", globalConfig->GetFirstDarcVmeAddr()) << endl;
541   out << globalConfig->GetFirstDarcType() << endl;
542   disable = globalConfig->GetFirstDarcDisable();
543   out << Form("0x%02x", disable) << endl;
544   out << Form("0x%x", globalConfig->GetFirstDarcL0Delay()) << endl;
545   out << Form("0x%x", globalConfig->GetFirstDarcL1TimeOut()) << endl;
546   out << Form("0x%x", globalConfig->GetFirstDarcGlobalL0()) << endl;
547   out << Form("0x%x", globalConfig->GetFirstDarcConfig()) << endl;
548   
549   // second darc board
550   out << globalConfig->GetSecondDarcName() << endl;
551   out << Form("0x%08x", globalConfig->GetSecondDarcVmeAddr()) << endl;
552   out << globalConfig->GetSecondDarcType() << endl;
553   disable = globalConfig->GetSecondDarcDisable();
554   out << Form("0x%02x", disable) << endl;
555   out << Form("0x%x", globalConfig->GetSecondDarcL0Delay()) << endl;
556   out << Form("0x%x", globalConfig->GetSecondDarcL1TimeOut()) << endl; 
557   out << Form("0x%x", globalConfig->GetSecondDarcGlobalL0()) << endl; 
558   out << Form("0x%x", globalConfig->GetSecondDarcConfig()) << endl; 
559   
560   // global board
561   out << globalConfig->GetGlobalName() << endl;
562   out << Form("0x%08x", globalConfig->GetGlobalVmeAddr()) << endl;
563   for (Int_t i = 0; i < globalConfig->GetGlobalNofRegisters(); ++i)
564     out << Form("0x%x", globalConfig->GetGlobalRegister(i)) << endl;
565   
566   // Fet board
567   out << globalConfig->GetFetName() << endl;
568   out << Form("0x%08x", globalConfig->GetFetVmeAddr()) << endl;
569   for (Int_t i = 0; i < globalConfig->GetFetNofRegisters(); ++i)
570     out << Form("0x%x", globalConfig->GetFetRegister(i)) << endl;
571   
572   return kTRUE;
573 }
574  
575 //_____________________________________________________________________________
576 Bool_t
577 AliMUONTriggerIO::WriteRegionalConfig(const char* regionalFile, AliMUONRegionalTriggerConfig* regionalConfig) const
578 {
579
580     /// write regional mask with the current configuration
581    /// if regional masks not defined, take the one from current configuration
582
583     ofstream out;
584     out.open(regionalFile);
585           
586     if (!out.good())
587     {
588       AliError(Form("Could not create output regional file %s",regionalFile));
589       return kFALSE;
590     }
591
592     Int_t nCrate = fRegionalTrigger.GetNofTriggerCrates();
593     if (!nCrate)
594     {
595       AliError("Could not write regional no configuration in memory");
596       return kFALSE;
597     }
598
599       
600    for (Int_t iCrate = 0; iCrate < nCrate; ++iCrate) 
601       {
602       AliMpTriggerCrate* crate = fRegionalTrigger.GetTriggerCrateFast(iCrate);
603       
604       AliMUONTriggerCrateConfig* crateConfig = regionalConfig->FindTriggerCrate(crate->GetName());
605       if (!crateConfig) 
606       {
607         AliError(Form("Cannot find crate %s in CDB", crate->GetName()));
608         return kFALSE;
609       }
610
611       out << crate->GetName()  << endl;
612       out << Form("%02x", crate->GetId())   << endl;
613       out << crateConfig->GetMode()  << endl;
614       out << crateConfig->GetCoinc() << endl;
615       out << Form("%04x", crateConfig->GetMask()) << endl;
616
617       for (Int_t iLocal = 0; iLocal < crate->GetNofLocalBoards(); ++iLocal) 
618       {
619         Int_t localBoardId = crate->GetLocalBoardId(iLocal);
620         
621         AliMpLocalBoard* board = fRegionalTrigger.FindLocalBoard(localBoardId);
622         
623         out << Form("%02d ", board->GetSlot())  
624             << board->GetName() 
625             << Form(" %03d ", localBoardId) 
626             << Form("%03x", board->GetSwitch()) 
627             << endl;
628  
629         out << " ";
630         for (Int_t i = 0; i < board->GetNofDEs(); ++i)
631           out << Form("%4d ", board->GetDEId(i));
632         out << endl;
633           
634         // print copy card numbers & TC
635         out << Form(" %4d %4d", board->GetInputXfrom(), board->GetInputXto());
636         out << Form(" %4d %4d", board->GetInputYfrom(), board->GetInputYto());
637         out << Form(" %4d",     board->GetTC()) << endl;
638       }
639     }
640     out.close();
641     
642     return kTRUE;
643 }
644
645
646 //_____________________________________________________________________________
647 Bool_t 
648 AliMUONTriggerIO::WriteLocalMasks(const char* localFile, AliMUONVStore& localMasks, AliMUONRegionalTriggerConfig* regionalConfig) const
649 {
650     /// write local mask
651     /// removing/adding enable for a local board need a update of the configuration 
652     /// before calling this method
653     /// mask are written for all boards including the copy card (Ch.F.)
654
655     FILE* fp = fopen(gSystem->ExpandPathName(localFile),"wb");
656     if (!fp) 
657     {
658       AliError(Form("Could not create output local file %s",localFile));
659       return kFALSE;
660     }   
661
662     UShort_t maskBuffer[8];
663
664     for (Int_t iCrate = 0; iCrate < regionalConfig->GetNofTriggerCrates(); ++iCrate) 
665     {
666       AliMUONTriggerCrateConfig* crate = regionalConfig->GetTriggerCrateFast(iCrate);
667       
668       UShort_t mask = crate->GetMask(); // getting mask from current config
669
670       for (Int_t iLocal = 0; iLocal < crate->GetNofLocalBoards(); ++iLocal) 
671       {
672         Int_t localBoardId = crate->GetLocalBoardId(iLocal);
673
674         if ( (mask >> iLocal ) & 0x1 ) 
675         {
676           AliMUONVCalibParam* localMask = 
677               static_cast<AliMUONVCalibParam*>(localMasks.FindObject(localBoardId));
678
679           for (Int_t index = 0; index < 8; ++index) 
680           {
681             maskBuffer[index] = localMask->ValueAsInt(index,0); 
682           }
683
684           fwrite ( maskBuffer, 2, 8, fp); 
685         }
686
687       }
688     }
689
690     fclose(fp);
691
692     return kTRUE;
693
694 }
695
696 //_____________________________________________________________________________
697 void
698 AliMUONTriggerIO::WriteLocalLUT(const AliMUONTriggerLut& lut,
699                                 Int_t localBoardId,
700                                 FILE* flut)
701 {
702   /// loop over the address for the 4-bits lpt and hpt decisions
703
704   const Int_t kMaskYpos = 0x0F;
705   const Int_t kMaskYtri = 0x01;
706   const Int_t kMaskXdev = 0x1F;
707   const Int_t kMaskXpos = 0x1F;
708
709   UChar_t buffer[fgkLocalLutSize];  // 32768 hpt/lpt addresses divided by two
710   Int_t bc = 0;
711   
712   for (UInt_t i = 0; i < fgkLocalLutSize*2; ++i) 
713   {
714     Int_t lutLpt[2] = { 0 };
715     Int_t lutHpt[2] = { 0 };
716     
717     // decompose address
718     Int_t iYpos =   i                    & kMaskYpos;   
719     Int_t iYtri = ( i >>   4           ) & kMaskYtri;
720     Int_t iXdev = ( i >> ( 4 + 1 )     ) & kMaskXdev;
721     Int_t iXpos = ( i >> ( 4 + 1 + 5 ) ) & kMaskXpos;
722     
723     // convert deviation format
724     // online: sign 1bit , dev 4bit
725     // sign    dev    trigger
726     // 0       1-15   mu-
727     // 1       1-15   mu+
728     // 0       0      mu+, mu- infinite momentum (unde)
729     // 1       0      no x-trigger
730     // offline: dev 5bit
731     // sign    dev    trigger
732     // -        0-14  mu-
733     // -       16-31  mu+
734     // -       15     mu+, mu- infinite momentum (unde)
735     Int_t iXdevOn  = 0;
736     Int_t iXdevOff = 0;
737     Int_t sign     = 0;
738     Bool_t trigx = kFALSE;
739     iXdevOn +=  iXdev & 0x0F;
740     sign    += (iXdev >> 4) & 0x01;
741     if (iXdevOn == 0) {
742       if (sign == 0) {
743         iXdevOff = 15;
744         trigx = kTRUE;
745       } else {
746         iXdevOff = 15;
747         trigx = kFALSE;
748       }
749     } else {
750       trigx = kTRUE;
751       if (sign == 0) {
752         iXdevOff = - iXdevOn + 15;  // gives range  0-14
753       } else {
754         iXdevOff = + iXdevOn + 15;  // gives range 16-30 !
755       }
756     }
757     iXdev = iXdevOff;
758
759     // iYtri == 1 means no trigger in y-direction
760     if (iYtri == 0 && trigx) 
761     {
762       lut.GetLutOutput(localBoardId,iXpos,iXdev,iYpos,lutLpt,lutHpt);
763     }
764     
765     // fill byte
766     if (i%2 == 0) 
767     {
768       // upper half-byte
769       buffer[bc] = 0;       
770       buffer[bc] += lutHpt[1] << 7;
771       buffer[bc] += lutHpt[0] << 6;
772       buffer[bc] += lutLpt[1] << 5;
773       buffer[bc] += lutLpt[0] << 4;
774     } else {
775       // lower half-byte
776       buffer[bc] += lutHpt[1] << 3;
777       buffer[bc] += lutHpt[0] << 2;
778       buffer[bc] += lutLpt[1] << 1;
779       buffer[bc] += lutLpt[0] << 0;
780       bc++;
781     }
782   }
783   fwrite(&buffer,bc,1,flut);
784 }  
785
786 //_____________________________________________________________________________
787 Int_t 
788 AliMUONTriggerIO::LocalBoardId(Int_t index) const
789 {  
790   /// Return the i-th localBoardId, or -1 if index is out of bounds
791
792   AliMpLocalBoard* board = fRegionalTrigger.GetLocalBoard(index);
793   if ( ! board ) return -1;
794   
795   return board->GetId(); 
796 }
797