Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Related Pages

ConfigurationUtility.cxx

00001 #include "ConfigurationUtility.h"
00002 #include "SctApiException.h"
00003 #include "primParams.h"
00004 
00005 namespace SctApi{
00006 #define fToInt(val) ((int)((val)+0.5))
00007 
00008 const static short tokens[20]={0x01, 0x03, 0x05, 0x07, 0x0b,
00009                                0x0d, 0x0f, 0x15, 0x17, 0x1b,
00010                                0x1d, 0x1f, 0x2b, 0x2d, 0x2f,
00011                                0x35, 0x37, 0x3b, 0x3d, 0x3f};
00012 
00013 const char *chipRoles[] = {"MISSING", "DEAD", "END", "MASTER", "SLAVE", "LONELY", "PARANOID"};
00014 
00015 void ConfigUtility::setToken(ABCDModule* module, unsigned token, int link0, int link1) {
00016   // Set up defaults...
00017   for(unsigned int theChip=0; theChip<N_SCT_CHIPS; theChip++){
00018        module->chip[theChip].basic.config.outputBypass = 0;
00019        module->chip[theChip].basic.config.inputBypass = 0;
00020        module->chip[theChip].basic.config.master = 1;        /* active low */
00021        module->chip[theChip].basic.config.end = 0;           /* active high */
00022        module->chip[theChip].basic.config.feedThrough  = 1;  /* active low  */
00023   }
00024 
00025   for(unsigned int theChip=0; theChip<N_SCT_CHIPS; theChip++){
00026     
00027     if( (token >> theChip) & 0x1 ) { /* chip to be read out */
00028 
00029       if(theChip==0) {
00030         if(link0) {
00031           if((token&0x003F)==0x0001) { /* only M0 in use */
00032             setChipRole(module,theChip,LONELY);
00033           } else {
00034             setChipRole(module,theChip,MASTER);
00035           }
00036         } else {
00037           setChipRole(module,theChip,END);
00038         }
00039 
00040       } else if(theChip==6) {
00041         if (link1) { 
00042           if((token&0x0FC0)==0x0040) { /* only M8 in use */
00043             setChipRole(module,theChip,LONELY);
00044           } else {
00045             setChipRole(module,theChip,MASTER);
00046           }
00047         } else {
00048           setChipRole(module,theChip,END);
00049         }
00050 
00051       } else if(theChip<6) {
00052         /* if( (link0<2) && (pow(2,(theChip+1))>(token&0x3F)) ) { dpsf */
00053         if( (link0<2) && (1<<(theChip+1)>(token&0x3F)) ) {
00054           setChipRole(module,theChip,END);
00055         } else {
00056           setChipRole(module,theChip,SLAVE);
00057         }
00058 
00059       } else {
00060         /* if( (link1<2) && (pow(2,(theChip+1))>token) ) {  dpsf */
00061         if( (link1<2) && (1<<(theChip+1)>token) ) {
00062           setChipRole(module,theChip,END);
00063         } else {
00064           setChipRole(module,theChip,SLAVE);
00065         }
00066       }
00067 
00068     } else {
00069       setChipRole(module,theChip,DEAD);
00070     }
00071   }
00072   return;
00073 }
00074 
00075 void ConfigUtility::modifyVar(ABCDModule* p_module, UINT32 typ, FLOAT32 val){
00076   if (isBOCRegister(typ)) return;
00077   if (!p_module) throw SctApiException("Null pointer exception in ConfigUtililty::modifyVar");
00078   ABCDModule &module = *p_module;
00079   
00080   
00081   switch (typ){
00082   case ST_TOKEN:
00083     {
00084       /*
00085        * This variable iterates over a set of token/data passing
00086        * schemes to determine the functionality of each token link.
00087        * The sequence sets all the combinations to read-out
00088        * n chips by first testing the bypass token (chip n-2 to n) 
00089        * for all combinations of (n-2) chips. Secondly trying the 
00090        * direct token (n-1 to n) for all combinations of (n-1) chips.
00091        *
00092        * For configurations 0-19, both datalinks are exercised at once.
00093        * For the remaining configurations, only one datalink is
00094        * used at once, as outlined below:
00095        *
00096        * o Even Configurations 20-34 read out chip S9 via datalink 0
00097        *   using the bypass link between E5 and S9.
00098        * 
00099        * o Odd  Configurations 21-35 read out chip S1 via datalink 1
00100        *   using the bypass link between E13 and S1.
00101        *
00102        * o Even configurations 36-60 read out chip M8 via datalink 0
00103        *   using first the bypass link between S4 and M8 and then
00104        *   the direct link between E5 and M8.
00105        *
00106        * o Odd  configurations 37-61 read out chip M0 via datalink 1
00107        *   using first the bypass link between S12 and M0 and then
00108        *   the direct link between E13 and M0.
00109        *
00110        * Only cases 0-35 have been implememted in the design of the
00111        * barrel hybrid. The logical inconsistency in the order between 
00112        * cases 20-35 and 36-61 is done such that the subset of the 
00113        * schemes used by the barrel design form a consecutive series.
00114        *
00115        * Orignal code by Lars Eklund, March 2001
00116        */ 
00117       int myVal = fToInt(val);
00118       
00119       if(myVal<20) {              /* use both datalinks */
00120     setToken(&module, (tokens[myVal] + (tokens[myVal] << 6)),1,1);
00121     
00122       } else if(myVal<36) {       /* use datalink 0 */
00123     if(!((int)myVal%2)) {
00124       setToken(&module, (tokens[(myVal-20)/2+12] + (0x1 << 7)),2,0);
00125     } else {                /* use datalink 1 */
00126       setToken(&module, (0x2 + (tokens[(myVal-21)/2+12] << 6)),0,2);
00127     }
00128       } else { // only possible for forward modules
00129     if(!(myVal%2)) {
00130       setToken(&module, (tokens[((myVal-36)/2+7)] + (1 << 6)),2,0);
00131     } else {
00132       setToken(&module, (0x1 + (tokens[((myVal-37)/2+7)] << 6)),0,2);
00133     }
00134       }
00135       break;
00136     }
00137   case MVAR_GROUP_ID:
00138     {
00139       module.groupId = fToInt(val);
00140       break;
00141     }
00142   case MVAR_ACTIVE:
00143     {
00144       module.active = fToInt(val);
00145       break;
00146     }
00147   case MVAR_SELECT:
00148     {
00149       module.select = fToInt(val);
00150       
00151       if(module.select) {
00152     for(int c=0; c<12; c++) {
00153       module.chip[c].address |= 0x10;
00154         }
00155       } else {
00156     for(int c=0; c<12; c++) {
00157       module.chip[c].address &= ~0x10;
00158     }
00159       }
00160       break;
00161     }
00162   default:
00163 #warning "Suggest using variableType to check for known module level variable"
00164     {
00165       // The rest are chip parameters
00166       for(int ichip=0; ichip<12; ichip++) {
00167         modifyVar(p_module, ichip, typ, val);
00168       }
00169     }
00170     break;
00171   }
00172 }
00173 
00174 void ConfigUtility::modifyVar(ABCDModule* module, unsigned ichip, UINT32 typ, FLOAT32 val){
00175   if (!module) throw SctApiException("Null pointer exception in ConfigUtililty::modifyVar");
00176   ABCDChip &chip = module->chip[ichip];
00177 
00178 #warning "Suggest using variableType to check that typ is known chip level variable"
00179 
00180   switch(typ) {
00181   case ST_ELAPSED: 
00182     // Do nothing
00183     break;
00184   case ST_VTHR: 
00185     chip.basic.vthr = (char) fToInt(val/2.5);
00186     break;
00187   case ST_VCAL:
00188     chip.basic.vcal = (char) fToInt(val/0.625);
00189     break;
00190   case ST_STROBE_DELAY:
00191     chip.basic.delay = (char) fToInt(val);
00192     break;
00193   case ST_PREAMP:
00194     chip.basic.preamp = (char) fToInt(val/9.2);
00195     break;
00196   case ST_SHAPER:
00197     chip.basic.shaper = (char) fToInt(val/1.2);
00198     break;
00199   case ST_TRIM:
00200     for(int i=0; i<128; i++) {
00201       chip.trim[i] = (char) fToInt(val);
00202     }
00203     break;
00204   case ST_MASK:
00205     {
00206       UINT32 myval = (UINT32) fToInt(val);
00207       UINT32 mask = myval;
00208       for(int i=0; i<16; i++) {
00209         mask = (mask << 2) + myval;
00210       }
00211 
00212       for(int i=0; i<4; i++) {
00213         chip.basic.mask[i] = mask;
00214       }
00215     }
00216     break;
00217   case ST_ROLE:
00218     switch(fToInt(val)) {
00219     case END:
00220       chip.basic.config.master = 1;  // active low
00221       chip.basic.config.end = 1;     // active high
00222       chip.basic.config.feedThrough = 1; // active low
00223       break;
00224     case MASTER:
00225       chip.basic.config.master = 0;  // active low
00226       chip.basic.config.end = 0;     // active high
00227       chip.basic.config.feedThrough = 1;
00228       break;
00229     case SLAVE:
00230       chip.basic.config.master = 1;  // active low
00231       chip.basic.config.end = 0;     // active high
00232       chip.basic.config.feedThrough = 1;
00233       break;
00234     case LONELY:
00235       chip.basic.config.master = 0;  // active low
00236       chip.basic.config.end = 1;     // active high
00237       chip.basic.config.feedThrough = 1;
00238       break;
00239     case PARANOID:
00240       chip.basic.config.master = 0;  // active low
00241       chip.basic.config.end = 1;     // active high
00242       chip.basic.config.feedThrough = 1;
00243     case DEAD:
00244     default:
00245       module->chip[(ichip+1)%12].basic.config.outputBypass = 1;
00246       module->chip[(ichip+11)%12].basic.config.inputBypass = 1;
00247     case MISSING:
00248       break;
00249     } // End switch role
00250 
00251   case ST_NMASK:
00252     {
00253       int channels = fToInt(val);
00254       if(channels > 128) channels = 128;
00255 
00256       for(int i=0; i<4; i++) {
00257         // How many channels in this group
00258         int chan = channels - i*32;
00259         if(chan >= 32) {
00260           chip.basic.mask[i] = 0x00000000;
00261         } else {
00262           int value = 0;
00263           for(int b=0; b<chan; b++) {
00264             value <<= 1;
00265             value ++;
00266           }
00267           chip.basic.mask[i] = ~value;
00268         }
00269       }
00270     }
00271     break;
00272   case ST_CAL_MODE:
00273     chip.basic.config.calibMode = fToInt(val);
00274     break;
00275   case ST_COMPRESSION:
00276     chip.basic.config.readoutMode = fToInt(val);
00277     break;
00278   case ST_TRIM_RANGE:
00279     chip.basic.config.trimRange = fToInt(val);
00280     break;
00281   case ST_EDGE_DETECT:
00282     chip.basic.config.edgeDetect = fToInt(val);
00283     break;
00284   case ST_SEND_MASK:
00285     chip.basic.config.mask = fToInt(val)?1:0;
00286     break;
00287   case ST_ACCUMULATE:
00288     chip.basic.config.accumulate = fToInt(val);
00289     break;
00290   case ST_FEEDTHROUGH:
00291     chip.basic.config.feedThrough = fToInt(val);
00292     break;
00293   case ST_ACTIVE:
00294     chip.active = fToInt(val);
00295     break;
00296 
00297 #ifdef DO_TOKENS_BY_CHIP
00298   case ST_BYPASS:
00299     {
00300       /*
00301        * A method used to select certain predetermined bypass configurations.
00302        * Made obsolete by ST_TOKEN (below) but included here for reasons of
00303        * backward compatibility. Recoded to use setToken function.
00304        */
00305       UINT8 int_val = (UINT8)((val+0.5)/1.0);
00306       switch(int_val){
00307       case 0: /* ME---- ME---- */
00308         setToken(module, 0x03 +(0x03<<6),1,1);
00309         break;
00310       case 1: /* MSE--- MSE--- */
00311         setToken(module, 0x07 +(0x07<<6),1,1);
00312         break;
00313       case 2: /* MSSE-- MSSE-- */
00314         setToken(module, 0x0F +(0x0F<<6),1,1);
00315         break;
00316       case 3: /* MSSSE- MSSSE- */
00317         setToken(module, 0x1F +(0x1F<<6),1,1);
00318         break;
00319         /* case 4 is the default configuration */
00320       case 5: /* MDE--- MDE--- */
00321         setToken(module, 0x05 +(0x05<<6),1,1);
00322         break;
00323       case 6: /* MSDE-- MSDE-- */
00324         setToken(module, 0x0b +(0x0b<<6),1,1);
00325         break;
00326       case 7: /* MSSDE- MSSDE- */
00327         setToken(module, 0x17 +(0x17<<6),1,1);
00328         break;
00329       case 8: /* MSSSDE MSSSDE */
00330         setToken(module, 0x2f +(0x2f<<6),1,1);
00331         break;
00332       case 9: /* MSSSSS DSSSSE */
00333         setToken(module, 0x3f +(0x3e<<6),2,0);
00334         break;
00335       case 10: /* DSSSSE MSSSSS */
00336         setToken(module, 0x3e +(0x3F<<6),0,2);
00337         break;
00338       case 11: /* MSSSSS SSSSSE */
00339         setToken(module, 0x3f +(0x3f<<6),2,0);
00340         break;
00341       case 12: /* SSSSSE MSSSSS */
00342         setToken(module, 0x3f +(0x3F<<6),0,2);
00343         break;
00344       default: /* MSSSSE MSSSSE */
00345         setToken(module, 0x3F +(0x3F<<6),1,1);
00346         break;
00347       }
00348       break;
00349     }
00350 
00351   case ST_TOKEN:
00352     {
00353       /*
00354        * This variable iterates over a set of token/data passing
00355        * schemes to determine the functionality of each token link.
00356        * The sequence sets all the combinations to read-out
00357        * n chips by first testing the bypass token (chip n-2 to n) 
00358        * for all combinations of (n-2) chips. Secondly trying the 
00359        * direct token (n-1 to n) for all combinations of (n-1) chips.
00360        *
00361        * For configurations 0-19, both datalinks are exercised at once.
00362        * For the remaining configurations, only one datalink is
00363        * used at once, as outlined below:
00364        *
00365        * o Even Configurations 20-34 read out chip S9 via datalink 0
00366        *   using the bypass link between E5 and S9.
00367        * 
00368        * o Odd  Configurations 21-35 read out chip S1 via datalink 1
00369        *   using the bypass link between E13 and S1.
00370        *
00371        * o Even configurations 36-60 read out chip M8 via datalink 0
00372        *   using first the bypass link between S4 and M8 and then
00373        *   the direct link between E5 and M8.
00374        *
00375        * o Odd  configurations 37-61 read out chip M0 via datalink 1
00376        *   using first the bypass link between S12 and M0 and then
00377        *   the direct link between E13 and M0.
00378        *
00379        * Only cases 0-35 have been implememted in the design of the
00380        * barrel hybrid. The logical inconsistency in the order between 
00381        * cases 20-35 and 36-61 is done such that the subset of the 
00382        * schemes used by the barrel design form a consecutive series.
00383        *
00384        * Orignal code by Lars Eklund, March 2001
00385        */
00386 
00387       int myVal = fToInt(val);
00388 
00389       if(myVal<20) {              /* use both datalinks */
00390         setToken(module, (tokens[(int)myVal] + (tokens[(int)myVal] << 6)),1,1);
00391       } else if(myVal<36) {       /* use datalink 0 */
00392         if(!((int)myVal%2)) {
00393           setToken(module, (tokens[(int)(myVal-20)/2+12] + (0x1 << 7)),2,0);
00394         } else {                /* use datalink 1 */
00395           setToken(module, (0x2 + (tokens[((int)myVal-21)/2+12] << 6)),0,2);
00396         }
00397       } else { // only possible for forward modules
00398         if(!((int)myVal%2)) {
00399           setToken(module, (tokens[(int)((myVal-36)/2+7)] + (1 << 6)),2,0);
00400         } else {
00401           setToken(module, (0x1 + (tokens[(int)((myVal-37)/2+7)] << 6)),0,2);
00402         }
00403       }
00404       break;
00405     }
00406 #endif
00407   case ST_QTHR: 
00408     {
00409       ABCDCaldata &calPtr = chip.caldata;
00410       float v, vv;
00411 
00412       switch(calPtr.rc_function){
00413       case 1: /* polynomial */
00414         v = calPtr.rc_params[0] + 
00415           val * (calPtr.rc_params[1] + 
00416                  (val * calPtr.rc_params[2]) );
00417         break; 
00418       case 2: /* grillo */
00419         if((val==0)|| (calPtr.rc_params[1]==0))
00420           vv = 0;
00421         else
00422           vv = calPtr.rc_params[2] / 
00423             (calPtr.rc_params[1] *val);
00424         v  = calPtr.rc_params[0] + 
00425           calPtr.rc_params[2] / (float) sqrt(1+(vv*vv)); 
00426         break; 
00427       case 3: /* exp */
00428         if(calPtr.rc_params[1]==0)
00429           v = 0;
00430         else
00431           v = calPtr.rc_params[2] + 
00432             calPtr.rc_params[0]/(1+ (float)exp(-val/calPtr.rc_params[1]));
00433         break;  
00434       case 4: /* linear fit */
00435         v = calPtr.rc_params[0] + 
00436           (val * calPtr.rc_params[1]);
00437         break; 
00438       default:
00439         v = 0;
00440         break;
00441       }
00442 
00443       UINT8 int_val = ((UINT8)((v+1.25)/(float)2.5));  /* 2.5mV / DAC bit */
00444       chip.basic.vthr = int_val;
00445       break;
00446     }
00447 
00448   case ST_QCAL:
00449     /*
00450      * calculate the actual vcal step size taking into
00451      * account the capacitor correction factor:
00452      * step size = (c_factor * 0.0625) fC / DAC bit 
00453      */
00454     {
00455       FLOAT32 step = (float) 0.0625 * chip.caldata.c_factor;
00456       UINT8 int_val = (UINT8)((val+(step/2))/step);
00457       chip.basic.vcal = int_val;
00458       break;
00459     }
00460   case ST_TARGET:
00461     {
00462       /*
00463        * record the target to which the chip has been trimmed
00464        * added PWP 07.01.03
00465        */
00466       UINT8 int_val = ((UINT8)((val+1.25)/(float)2.5));  /* 2.5mV / DAC bit */
00467 
00468       /* int_val must be in range if declared UINT8
00469          if(int_val<0x00) int_val = 0x00;
00470          if(int_val>0xff) int_val = 0xff;
00471       */
00472       chip.target = int_val;
00473       break;
00474     }
00475 
00476   case ST_TTHR:
00477     {
00478       /*
00479        * set the threshold in mV wrt the trim target
00480        * added PWP 07.01.03
00481        */
00482       UINT8 int_val = ((UINT8)((val+1.25)/(float)2.5));  /* 2.5mV / DAC bit */
00483       int_val += chip.target;
00484 
00485       /*
00486         if(int_val<0x00) int_val = 0x00;
00487         if(int_val>0xff) int_val = 0xff;
00488       */
00489       chip.basic.vthr = int_val;
00490       break;
00491     }
00492 
00493   default:
00494     break;
00495   } // End switch var
00496 
00497 }
00498 
00499 INT32 ConfigUtility::setChipRole(ABCDModule *module, UINT32 theChip, ABCD_ROLES role){
00500 //   cout << "Set chip " << theChip << " role to " << chipRoles[role] << endl;
00501 
00502   ABCDChip*   chipPtr;
00503   ABCDConfig* configPtrLast;  /* chip (n-1) */ 
00504   ABCDConfig* configPtr;      /* chip n     */
00505   ABCDConfig* configPtrNext;  /* chip (n+1) */
00506 
00507   UINT32 lastChip, nextChip;
00508 
00509   if(theChip>N_SCT_CHIPS-1) return -1;  /* chip out of range */
00510   if(module->active==0) return -2;  /* module inactive */
00511 
00512   chipPtr = &module->chip[theChip];
00513   if(chipPtr->active==0) return -3; /* chip inactive */
00514 
00515   lastChip = theChip-1;
00516   nextChip = theChip+1;
00517 
00518   if(theChip==0)  lastChip = 11;
00519   if(theChip==11) nextChip =  0;
00520 
00521   configPtrLast = &module->chip[lastChip].basic.config;
00522   configPtr     = &module->chip[theChip].basic.config;
00523   configPtrNext = &module->chip[nextChip].basic.config;
00524 
00525   switch(role){
00526     case MISSING:
00527       /* who cares! */
00528       break;
00529     case DEAD:
00530       configPtrNext->outputBypass = 1;
00531       configPtrLast->inputBypass  = 1;
00532       break;
00533     case END:
00534       configPtr->master = 1;
00535       configPtr->end    = 1;
00536       configPtr->feedThrough = 1;
00537       break;
00538     case MASTER:
00539       configPtr->master = 0;
00540       configPtr->end    = 0;
00541       configPtr->feedThrough = 1;  /* active low */
00542       break;
00543     case SLAVE:
00544       configPtr->master = 1;
00545       configPtr->end    = 0;
00546       configPtr->feedThrough = 1;
00547       break;
00548     case LONELY:
00549       configPtr->master = 0;
00550       configPtr->end    = 1;
00551       configPtr->feedThrough = 1;
00552       break;
00553     case PARANOID:
00554       configPtrNext->outputBypass = 1;
00555       configPtrLast->inputBypass  = 1;
00556       configPtr->master = 0;
00557       configPtr->end    = 1;
00558       configPtr->feedThrough = 1;
00559       break;
00560     default:
00561       break;
00562   }
00563 
00564   return 0;
00565 }
00566 
00567 ConfigUtility::ConfigVarType ConfigUtility::variableType(UINT32 typ){
00568   switch(typ) {
00569   case ST_RX_DELAY:
00570   case ST_RX_DELAY0:
00571   case ST_RX_DELAY1:
00572   case ST_RX_THRESHOLD:
00573   case ST_RX_THRESHOLD0:
00574   case ST_RX_THRESHOLD1:
00575   case ST_TX_CURRENT:
00576   case ST_TX_MARKSPACE:
00577   case ST_TX_DELAY:
00578   case ST_TX_COARSE:
00579   case ST_TX_FINE:
00580     return BOC_CHANNEL_CONFIG_VAR;
00581   case SCT_SCAN_BOC_BPM_PHASE:
00582   case SCT_SCAN_BOC_BREG_PHASE:
00583   case SCT_SCAN_BOC_V0_PHASE:
00584   case SCT_SCAN_BOC_V1_PHASE:
00585   case SCT_SCAN_BOC_V_PHASES:
00586   case SCT_SCAN_BOC_VRN_FINE:
00587   case SCT_SCAN_TX_CHANNELS:
00588   case SCT_SCAN_RAW_TX_CHANNELS:
00589     return BOC_GLOBAL_CONFIG_VAR;
00590   case ST_TOKEN:
00591     //  case ST_BYPASS:
00592   case MVAR_GROUP_ID:
00593   case MVAR_ACTIVE:
00594   case MVAR_SELECT:
00595     return MODULE_GLOBAL_CONFIG_VAR;
00596   case ST_VTHR: 
00597   case ST_VCAL:
00598   case ST_STROBE_DELAY:
00599   case ST_PREAMP:
00600   case ST_SHAPER:
00601   case ST_TRIM:
00602   case ST_MASK:
00603   case ST_ROLE:
00604   case ST_NMASK:
00605   case ST_CAL_MODE:
00606   case ST_COMPRESSION:
00607   case ST_TRIM_RANGE:
00608   case ST_EDGE_DETECT:
00609   case ST_SEND_MASK:
00610   case ST_ACCUMULATE:
00611   case ST_FEEDTHROUGH:
00612   case ST_ACTIVE:
00613 
00614   case ST_QTHR: 
00615   case ST_QCAL:
00616   case ST_TARGET:
00617   case ST_TTHR:
00618     return MODULE_CHIP_CONFIG_VAR;
00619     return MODULE_CHANNEL_CONFIG_VAR;
00620   default:
00621     return UNKNOWN_CONFIG_VAR;
00622   }
00623 }
00624 
00625 }

Generated on Fri Sep 16 18:01:49 2005 for SCT DAQ/DCS Software - C++ by doxygen 1.3.5