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