/****************************************************************************** * * Title : ABCDconfig.c * Version: 18 August 2004 * * Description: ABCD module configuration structure utility functions * Related files: ABCDconfig.h * Documentation: http://s.home.cern.ch/s/sct/public/sctdaq/sctdaq.html * * Author: Peter W Phillips, P.W.Phillips@rl.ac.uk * * Revised: Douglas Ferguson Jan/Feb 2003 * Some minor bugfixes, and inclusion of a few #defines to allow * the same file to be shared between the MDSP and DAQ code. * Added Group ID to module structure. * Revised: Peter W Phillips 21 March 2003 * bugfixes to setChipRole * new expression for "Grillo" function in setChipVariable * added code for other fit functions in getChipVariable * Revised: Douglas Ferguson March 19th 2003 * Add SCT_ROD #define & code stub to allow the DSP code to * be switched between SCT & PIXEL. * Revised: Peter W Phillips 25 March 2003 * Add interim code to vary selected BOC parameters * Revised: Douglas Ferguson 26 March 2003 * Changed BOC setting code to use routine setBocVariable, * which uses a BOC configuration structure to store BOC * settings for modules. 1st pass. * Revised: Peter W Phillips 18 August 2003 * setChipVariable rewritten with math performed using INT32. * The previous code, using UINT8, was not robust in cases of * underflow/overflow. This version will substitute the * minimum or maximum permitted value in cases where a value * outside the range has been requested. * Also - add ST_FEEDTHROUGH to put modules into clk/2 mode * without recourse to the power supply system... * ******************************************************************************/ #if !defined(SCT_ROD) #if defined(I_AM_MASTER_DSP) #pragma CODE_SECTION(stub1, "xcode"); #endif void stub1() { //define a mini function so that file can always be included in } //the project. #else /****************************************************************************** * Header files * ******************************************************************************/ #include #include #include #include #include #ifdef I_AM_MASTER_DSP #include "resources.h" #include "fxnPragma_sct.h" #else #include "fxnProto_sct.h" #endif #include "sctStructure.h" #include "ABCDchip.h" #include "ABCDscans.h" short tokens[20]={0x01, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x0f, 0x15, 0x17, 0x1b, 0x1d, 0x1f, 0x2b, 0x2d, 0x2f, 0x35, 0x37, 0x3b, 0x3d, 0x3f}; /****************************************************************************** * Static Function Declarations * ******************************************************************************/ /****************************************************************************** * Global Functions * ******************************************************************************/ #if (!defined(I_AM_MASTER_DSP)) /*============================================================================= * showConfigChipBasic() *============================================================================= * * prints contents of ABCDBasic structure to the console * */ void showConfigChipBasic(ABCDChip *chip){ printf(" config MSB->LSB %d %d %d %d %d %d %d %d %d %d %d\n", chip->basic.config.feedThrough, chip->basic.config.end, chip->basic.config.master, chip->basic.config.outputBypass, chip->basic.config.inputBypass, chip->basic.config.accumulate, chip->basic.config.mask, chip->basic.config.edgeDetect, chip->basic.config.trimRange, chip->basic.config.calibMode, chip->basic.config.readoutMode); printf(" mask 3->0 0x%08x %08x %08x %08x\n", chip->basic.mask[3], chip->basic.mask[2], chip->basic.mask[1], chip->basic.mask[0]); printf(" vthr 0x%02x vcal 0x%02x delay 0x%02x preamp 0x%02x shaper 0x%02x\n", chip->basic.vthr, chip->basic.vcal, chip->basic.delay, chip->basic.preamp, chip->basic.shaper); return; } /*============================================================================= * showConfigChipCaldata() *============================================================================= * * prints contents of ABCDCaldata structure to the console * */ void showConfigChipCaldata(ABCDChip *chip){ printf(" rc_function %d p0 %3.2e p1 %3.2e p2 %3.2e c_factor %3.2f\n", chip->caldata.rc_function, chip->caldata.rc_params[0], chip->caldata.rc_params[1], chip->caldata.rc_params[2], chip->caldata.c_factor); printf(" trim_target %d\n", chip->target); return; } /*============================================================================= * showConfigChipTrim() *============================================================================= * * prints contents of ABCD trim array to the console * */ void showConfigChipTrim(ABCDChip *chip){ int channel, index; for(index=0;index<4;index++){ printf(" index %d 0x",index); for(channel=index;channel<128;channel+=4){ printf("%x ",chip->trim[channel]); } } return; } /*============================================================================= * showConfigChip() *============================================================================= * * prints contents of ABCDChip structure to the console * */ void showConfigChip(ABCDChip *chip){ printf("Chip Address 0x%02d Active 0d%d\n", chip->address, chip->active); showConfigChipBasic(chip); showConfigChipCaldata(chip); showConfigChipTrim(chip); return; } /*============================================================================= * showConfigModule() *============================================================================= * * prints contents of ABCDModule structure to the console * */ void showConfigModule(ABCDModule *module){ int chipIndex; ABCDChip *chip; printf("Module Active %d Select %d pTTC %d rTTC %d Group ID %d.\n", module->active, module->select, module->pTTC, module->rTTC, module->groupId); for(chipIndex=0;chipIndexchip[chipIndex]; showConfigChip(chip); } return; } /*============================================================================= * writeConfigModule() *============================================================================= * * writes contents of ABCDModule structure to a text file * */ INT32 writeConfigModule(ABCDModule *module, char* filename){ FILE* file; int chipIndex; int channel, start, word, nibble; UINT32 data; ABCDChip *chip; file = fopen(filename,"w"); if (file == NULL){ printf("writeConfigModule: cannot open file\n",filename); return (-1); } fprintf(file, "Module Active %d Select %d pTTC %d rTTC %d Group ID %d\n", module->active, module->select, module->pTTC, module->rTTC, module->groupId); for(chipIndex=0;chipIndexchip[chipIndex]; fprintf(file,"Chip %02d address 0x%02x active %d\n", chipIndex, chip->address, chip->active); fprintf(file," config MSB->LSB %d %d %d %d %d %d %d %d %d %d %d\n", chip->basic.config.feedThrough, chip->basic.config.end, chip->basic.config.master, chip->basic.config.outputBypass, chip->basic.config.inputBypass, chip->basic.config.accumulate, chip->basic.config.mask, chip->basic.config.edgeDetect, chip->basic.config.trimRange, chip->basic.config.calibMode, chip->basic.config.readoutMode); fprintf(file," mask 3->0 0x%08x 0x%08x 0x%08x 0x%08x\n", chip->basic.mask[3], chip->basic.mask[2], chip->basic.mask[1], chip->basic.mask[0]); fprintf(file," vthr 0x%02x vcal 0x%02x delay 0x%02x preamp 0x%02x shaper 0x%02x\n", chip->basic.vthr, chip->basic.vcal, chip->basic.delay, chip->basic.preamp, chip->basic.shaper); fprintf(file," rc_function %d p0 %3.2e p1 %3.2e p2 %3.2e c_factor %3.2f\n", chip->caldata.rc_function, chip->caldata.rc_params[0], chip->caldata.rc_params[1], chip->caldata.rc_params[2], chip->caldata.c_factor); fprintf(file," trim-target %d\n", chip->target); for(start=0;start<128;start+=32){ fprintf(file," trim %02x-%02x ",start,start+31); channel = start; for(word=0;word<4;word++){ data = 0; for(nibble=0;nibble<7;nibble++){ data|=(chip->trim[channel++]&0x0f); data<<=4; } data|=(chip->trim[channel++]&0x0f); fprintf(file," %08x",data); } fprintf(file,"\n"); } } fclose(file); return 0; } /*============================================================================= * readConfigModule() *============================================================================= * * reads contents of ABCDModule structure from a text file * */ INT32 readConfigModule(ABCDModule *module, char* filename){ FILE* file; char line[128]; int nargs; int chipIndex; int start, stop; int word, nibble; UINT32 arg[12]; FLOAT32 farg[4]; ABCDChip *chip = 0; file = fopen(filename,"r"); if (file == NULL){ printf("readConfigModule: cannot open file\n",filename); return (-1); } while(fgets(line,128,file) != (char*) NULL) { if(strncmp(line,"Module",6)==0){ /* first useful line */ nargs=sscanf(line, "Module Active %d Select %d pTTC %d rTTC %d Group ID %d", &arg[0], &arg[1], &arg[2], &arg[3], &arg[4]); module->active = (UINT8) arg[0]; module->select = (UINT8) arg[1]; module->pTTC = (UINT8) arg[2]; module->rTTC = (UINT8) arg[3]; module->groupId = (UINT8) arg[4]; chip=0; } else if(strncmp(line,"Chip",4)==0){ /* new chip */ nargs=sscanf(line,"Chip %d address 0x%x active %d", &chipIndex, &arg[0], &arg[1]); if((chipIndex>=0)&&(chipIndexchip[chipIndex]; chip->address = (UINT8) arg[0]; chip->active = (UINT8) arg[1]; } else{ chip = 0; } } else if(strncmp(line," config",8)==0){ /* basic line 1 */ nargs=sscanf(line, " config MSB->LSB %d %d %d %d %d %d %d %d %d %d %d", &arg[0], &arg[1], &arg[2], &arg[3], &arg[4], &arg[5], &arg[6], &arg[7], &arg[8], &arg[9], &arg[10]); if(chip){ chip->basic.config.feedThrough = arg[0]; chip->basic.config.end = arg[1]; chip->basic.config.master = arg[2]; chip->basic.config.outputBypass = arg[3]; chip->basic.config.inputBypass = arg[4]; chip->basic.config.accumulate = arg[5]; chip->basic.config.mask = arg[6]; chip->basic.config.edgeDetect = arg[7]; chip->basic.config.trimRange = arg[8]; chip->basic.config.calibMode = arg[9]; chip->basic.config.readoutMode = arg[10]; } } else if(strncmp(line," mask",6)==0){ /* basic line 2 */ nargs=sscanf(line," mask 3->0 0x%x 0x%x 0x%x 0x%x ", &arg[0], &arg[1], &arg[2], &arg[3]); if(chip){ chip->basic.mask[3] = arg[0]; chip->basic.mask[2] = arg[1]; chip->basic.mask[1] = arg[2]; chip->basic.mask[0] = arg[3]; } } else if(strncmp(line," vthr",6)==0){ /* basic line 3 */ nargs=sscanf(line, " vthr 0x%x vcal 0x%x delay 0x%x preamp 0x%x shaper 0x%x ", &arg[0], &arg[1], &arg[2], &arg[3], &arg[4]); if(chip){ chip->basic.vthr = (UINT8) arg[0]; chip->basic.vcal = (UINT8) arg[1]; chip->basic.delay = (UINT8) arg[2]; chip->basic.preamp = (UINT8) arg[3]; chip->basic.shaper = (UINT8) arg[4]; } } else if(strncmp(line," rc_function",11)==0){ /* caldata */ nargs=sscanf(line," rc_function %d p0 %f p1 %f p2 %f c_factor %f", &arg[0], &farg[0], &farg[1], &farg[2], &farg[3]); if(chip){ chip->caldata.rc_function = arg[0]; chip->caldata.rc_params[0] = farg[0]; chip->caldata.rc_params[1] = farg[1]; chip->caldata.rc_params[2] = farg[2]; chip->caldata.c_factor = farg[3]; } } else if(strncmp(line," trim-target",13)==0){ /* trim target */ nargs=sscanf(line," trim-target %d", &arg[0]); if(chip){ chip->target= arg[0]; } } else if(strncmp(line," trim",6)==0){ /* trimdata */ nargs=sscanf(line," trim %x-%x %x %x %x %x", &start, &stop, &arg[0], &arg[1], &arg[2], &arg[3]); if(chip){ for(word=0;word<4;word++){ for(nibble=7;nibble>=0;nibble--){ chip->trim[start+nibble]=(UINT8)(arg[word]&0x0f); arg[word]>>=4; } start+=8; } } } } /* end (while) */ if(file){ fclose(file); } return 0; } #elif (!defined(I_AM_NT_HOST)) /* !RODTS */ /*============================================================================= * setChipRole() *============================================================================= * * configure the ROLE of a chip * * The derived "variable" ST_ROLE acts upon * o the MASTER, END and FEEDTHROUGH bits of chip n, * o the OUTPUT_BYPASS bit of chip (n-1) and * o the INPUT_BYPASS bit of chip (n+1) * to set a chip as * o MISSING * o DEAD use BYPASS to route data around this chip * o END set END bit * o MASTER set MASTER bit * o SLAVE a "normal" chip * o LONELY both MASTER and END (!!) * o PARANOID both LONELY and DEAD (!!!!) * * In SCTDAQ this functionality was built directly into the command generator. * Here we modify the contents of the config register, as stored in the * ABCDChip sturcture, to achieve the same effect. * * Since this function may act upon the configuration structure for each of * up to three chips, a pointer to the ABCDModule structure must be supplied. * * Revised PWP 21.03.03 */ INT32 setChipRole(ABCDModule *module, UINT32 theChip, ABCD_ROLES role){ ABCDChip* chipPtr; ABCDConfig* configPtrLast; /* chip (n-1) */ ABCDConfig* configPtr; /* chip n */ ABCDConfig* configPtrNext; /* chip (n+1) */ UINT32 lastChip, nextChip; if(theChip>N_SCT_CHIPS-1) return -1; /* chip out of range */ if(module->active==0) return -2; /* module inactive */ chipPtr = &module->chip[theChip]; if(chipPtr->active==0) return -3; /* chip inactive */ lastChip = theChip-1; nextChip = theChip+1; if(theChip==0) lastChip = 11; if(theChip==11) nextChip = 0; configPtrLast = &module->chip[lastChip].basic.config; configPtr = &module->chip[theChip].basic.config; configPtrNext = &module->chip[nextChip].basic.config; switch(role){ case MISSING: /* who cares! */ break; case DEAD: configPtrNext->outputBypass = 1; configPtrLast->inputBypass = 1; break; case END: configPtr->master = 1; /* active low */ configPtr->end = 1; /* active high */ configPtr->feedThrough = 1; /* active low */ break; case MASTER: configPtr->master = 0; configPtr->end = 0; configPtr->feedThrough = 1; break; case SLAVE: configPtr->master = 1; configPtr->end = 0; configPtr->feedThrough = 1; break; case LONELY: configPtr->master = 0; configPtr->end = 1; configPtr->feedThrough = 1; case PARANOID: configPtrNext->outputBypass = 1; configPtrLast->inputBypass = 1; configPtr->master = 0; configPtr->end = 1; configPtr->feedThrough = 1; break; default: break; } return 0; } /*============================================================================= * setToken() *============================================================================= * * configure the ROLES of all chips according to the bypass configuration * represented by the bit pattern TOKEN * * based on SCTDAQ's st_configure_token * * original code by Lars Eklund, February 2001 */ void setToken(ABCDModule* module, unsigned token, int link0, int link1) { UINT8 theChip, linkMod; //Set up the link masks for this token type: if ((link0) && (link1)) linkMod= LINK_MOD_BOTH; else if (link0) linkMod= LINK_MOD_LOWER; else linkMod= LINK_MOD_UPPER; setLinkMasks(module->moduleNumber, SP0, DATA_LINK_PLAY, linkMod, MASK_SET_SEARCH); // Set up defaults... for(theChip=0; theChipchip[theChip].basic.config.outputBypass = 0; module->chip[theChip].basic.config.inputBypass = 0; module->chip[theChip].basic.config.master = 1; /* active low */ module->chip[theChip].basic.config.end = 0; /* active high */ module->chip[theChip].basic.config.feedThrough = 1; /* active low */ } for(theChip=0; theChip> theChip) & 0x1 ) { /* chip to be read out */ if(theChip==0) { if(link0) { if((token&0x003F)==0x0001) { /* only M0 in use */ setChipRole(module,theChip,LONELY); } else { setChipRole(module,theChip,MASTER); } } else { setChipRole(module,theChip,END); } } else if(theChip==6) { if (link1) { if((token&0x0FC0)==0x0040) { /* only M8 in use */ setChipRole(module,theChip,LONELY); } else { setChipRole(module,theChip,MASTER); } } else { setChipRole(module,theChip,END); } } else if(theChip<6) { /* if( (link0<2) && (pow(2,(theChip+1))>(token&0x3F)) ) { dpsf */ if( (link0<2) && (1<<(theChip+1)>(token&0x3F)) ) { setChipRole(module,theChip,END); } else { setChipRole(module,theChip,SLAVE); } } else { /* if( (link1<2) && (pow(2,(theChip+1))>token) ) { dpsf */ if( (link1<2) && (1<<(theChip+1)>token) ) { setChipRole(module,theChip,END); } else { setChipRole(module,theChip,SLAVE); } } } else { setChipRole(module,theChip,DEAD); } } return; } /*============================================================================= * setChipVariable() *============================================================================= * * Operates upon the contents of ABCDChip structure, setting the variable * denoted by "typ" to the value given by argument "val". * * If the selected chip is marked INACTIVE, the structure contents remain * unchanged with the exception of the case where the function has been * called to change the state of the ACTIVE flag. If the module is marked * INACTIVE, the request is always ignored. * * Although the ABCDChip structure now stores the register values in terms * of bits, for reasons of compatibility with SCTDAQ this routine still * operates upon the DAC and delay values in terms of the following units: * o vthr - mV * o vcal - mV * o delay - bits * o preamp - microA * o shaper - microA * o TrimDAC - bits * * The desired value is in all cases supplied as type FLOAT32. Coersion * to the nearest possible value is integrated into this routine. * * Hence it can be seen that this routine is similar in content to an * amalgam of SCTDAQ's st_coerce_variable and st_configure_variable. * * Revised PWP 18.08.2004 - the coersion of user inputs is now handled correctly. * Example: a user requests a threshold value of 640mV, corresponding to a * (physically impossible) count of 0x100 from an 8 bit DAC. In the previous * version of the code, the calculations were done using UINT8, hence a value of * 0x00 would be set. This can cause considerable confusion! In this version of * the code, calculations are done using INT32. The result DAC setting is tested * against both high and low limits to ensure that overflow and underflow are * handled safely. */ INT32 setChipVariable(ABCDModule *module, UINT32 theChip, UINT32 typ, FLOAT32 val){ ABCDCaldata * calPtr; ABCDChip * chipPtr; UINT32 channel, c; UINT32 mask; UINT32 uint_val; INT32 int_val; float step; float v; if(theChip>N_SCT_CHIPS-1) return -1; /* chip out of range */ if(module->active==0) return -2; /* module inactive */ chipPtr = &module->chip[theChip]; if(typ!=ST_ACTIVE){ if(chipPtr->active==0) return -3; /* chip inactive */ } switch(typ) { case ST_VTHR: /* * revised PWP 03.09.04 - protection against wraparound */ int_val = (INT32)((val+1.25)/(float)2.5); /* 2.5mV / DAC bit */ if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; /* 8 bit DAC */ chipPtr->basic.vthr = (UINT8) int_val; break; case ST_VCAL: int_val = (INT32)((val+0.312)/(float)0.625); /* 0.625mV / DAC bit */ if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; /* 8 bit DAC */ chipPtr->basic.vcal = (UINT8) int_val; break; case ST_STROBE_DELAY: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0x00) int_val = 0x00; else if(int_val>0x3f) int_val = 0x3f; /* 6 bit register */ chipPtr->basic.delay = (UINT8) int_val; break; case ST_PREAMP: int_val = (INT32)((val+4.6)/(float)9.2); /* 9.2uA / bit */ if (int_val<0x00) int_val=0x00; else if(int_val>0x1f) int_val=0x1f; /* 5 bit DAC */ chipPtr->basic.preamp = (UINT8) int_val; break; case ST_SHAPER: int_val = (INT32)((val+0.6)/(float)1.2); /* 1.2uA / bit */ if (int_val<0x00) int_val=0x00; else if(int_val>0x1f) int_val=0x1f; /* 5 bit DAC */ chipPtr->basic.shaper = (UINT8) int_val; break; case ST_TRIM: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>3) int_val=15; for (channel=0; channeltrim[channel] = (UINT8) int_val; } break; case ST_MASK: /* * Select one of four predefined mask patterns. * Used during digital tests. */ int_val = (INT32)((val+0.5)/(float)1.0); switch(int_val) { case 0: mask = 0x00000000; break; case 1: mask = 0x55555555; break; case 4: mask = 0xaaaaaaaa; break; default: mask = 0xffffffff; break; } for (channel=0; channel<4; channel++){ chipPtr->basic.mask[channel] = mask; } break; case ST_ROLE: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>6) int_val=6; setChipRole(module,theChip, (ABCD_ROLES) int_val); break; case ST_NMASK: /* * Mask the first "val" channels of a module. This may be used * togther with SEND_MASK to generate an event of fixed length. * Used during digital tests. */ int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>128) int_val=128; unmaskAllChannels(chipPtr->basic.mask); for (channel=0;channelbasic.mask,channel); } break; case ST_CAL_MODE: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>3) int_val=3; chipPtr->basic.config.calibMode = (UINT8) int_val; break; case ST_COMPRESSION: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>3) int_val=3; chipPtr->basic.config.readoutMode = (UINT8) int_val; break; case ST_TRIM_RANGE: int_val = (INT32)((val+0.5)/(float)1.0); if (int_val<0) int_val=0; else if(int_val>3) int_val=3; chipPtr->basic.config.trimRange = (UINT8) int_val; break; case ST_EDGE_DETECT: int_val = (INT32)((val+0.5)/(float)1.0); int_val = (int_val>0 ? 1 : 0); chipPtr->basic.config.edgeDetect = (UINT8) int_val; break; case ST_SEND_MASK: int_val = (INT32)((val+0.5)/(float)1.0); int_val = (int_val>0 ? 1 : 0); chipPtr->basic.config.mask = (UINT8) int_val; break; case ST_ACCUMULATE: int_val = (INT32)((val+0.5)/(float)1.0); int_val = (int_val>0 ? 1 : 0); chipPtr->basic.config.accumulate = (UINT8) int_val; break; case ST_FEEDTHROUGH: int_val = (INT32)((val+0.5)/(float)1.0); int_val = (int_val>0 ? 1 : 0); chipPtr->basic.config.feedThrough = (UINT8) int_val; break; case ST_ACTIVE: int_val = (INT32)((val+0.5)/(float)1.0); int_val = (int_val>0 ? 1 : 0); chipPtr->active = (UINT8) int_val; break; case ST_BYPASS: /* * A method used to select certain predetermined bypass configurations. * Made obsolete by ST_TOKEN (below) but included here for reasons of * backward compatibility. Recoded to use setToken function. */ int_val = (INT32)((val+0.5)/(float)1.0); switch(int_val){ case 0: /* ME---- ME---- */ setToken(module, 0x03 +(0x03<<6),1,1); break; case 1: /* MSE--- MSE--- */ setToken(module, 0x07 +(0x07<<6),1,1); break; case 2: /* MSSE-- MSSE-- */ setToken(module, 0x0F +(0x0F<<6),1,1); break; case 3: /* MSSSE- MSSSE- */ setToken(module, 0x1F +(0x1F<<6),1,1); break; /* case 4 is the default configuration */ case 5: /* MDE--- MDE--- */ setToken(module, 0x05 +(0x05<<6),1,1); break; case 6: /* MSDE-- MSDE-- */ setToken(module, 0x0b +(0x0b<<6),1,1); break; case 7: /* MSSDE- MSSDE- */ setToken(module, 0x17 +(0x17<<6),1,1); break; case 8: /* MSSSDE MSSSDE */ setToken(module, 0x2f +(0x2f<<6),1,1); break; case 9: /* MSSSSS DSSSSE */ setToken(module, 0x3f +(0x3e<<6),2,0); break; case 10: /* DSSSSE MSSSSS */ setToken(module, 0x3e +(0x3F<<6),0,2); break; case 11: /* MSSSSS SSSSSE */ setToken(module, 0x3f +(0x3f<<6),2,0); break; case 12: /* SSSSSE MSSSSS */ setToken(module, 0x3f +(0x3F<<6),0,2); break; default: /* MSSSSE MSSSSE */ setToken(module, 0x3F +(0x3F<<6),1,1); break; } break; case ST_TOKEN: /* * This variable iterates over a set of token/data passing * schemes to determine the functionality of each token link. * The sequence sets all the combinations to read-out * n chips by first testing the bypass token (chip n-2 to n) * for all combinations of (n-2) chips. Secondly trying the * direct token (n-1 to n) for all combinations of (n-1) chips. * * For configurations 0-19, both datalinks are exercised at once. * For the remaining configurations, only one datalink is * used at once, as outlined below: * * o Even Configurations 20-34 read out chip S9 via datalink 0 * using the bypass link between E5 and S9. * * o Odd Configurations 21-35 read out chip S1 via datalink 1 * using the bypass link between E13 and S1. * * o Even configurations 36-60 read out chip M8 via datalink 0 * using first the bypass link between S4 and M8 and then * the direct link between E5 and M8. * * o Odd configurations 37-61 read out chip M0 via datalink 1 * using first the bypass link between S12 and M0 and then * the direct link between E13 and M0. * * Only cases 0-35 have been implememted in the design of the * barrel hybrid. The logical inconsistency in the order between * cases 20-35 and 36-61 is done such that the subset of the * schemes used by the barrel design form a consecutive series. * * Orignal code by Lars Eklund, March 2001 */ if(val<20) { /* use both datalinks */ setToken(module, (tokens[(int)val] + (tokens[(int)val] << 6)),1,1); } else if(val<36) { /* use datalink 0 */ if(!((int)val%2)) { setToken(module, (tokens[(int)(val-20)/2+12] + (0x1 << 7)),2,0); } else { /* use datalink 1 */ setToken(module, (0x2 + (tokens[((int)val-21)/2+12] << 6)),0,2); } } else { // only possible for forward modules if(!((int)val%2)) { setToken(module, (tokens[(int)((val-36)/2+7)] + (1 << 6)),2,0); } else { setToken(module, (0x1 + (tokens[(int)((val-37)/2+7)] << 6)),0,2); } } break; case ST_SELECT: int_val = (INT32)((val+0.5)/(float)1.0); module->select = int_val?1:0; if(module->select) { for(c=0; cchip[c].address |= 0x10; } } else { for(c=0; cchip[c].address &= ~0x10; } } break; case ST_QTHR: calPtr = &chipPtr->caldata; switch(calPtr->rc_function){ case 1: /* polynomial */ v = calPtr->rc_params[0] + val * (calPtr->rc_params[1] + (val * calPtr->rc_params[2]) ); break; case 2: /* grillo */ if(calPtr->rc_params[2]==0) v = calPtr->rc_params[0]; else v = calPtr->rc_params[0] + (calPtr->rc_params[1]*val) / (float) sqrt(1.0 + pow((calPtr->rc_params[1]*val/calPtr->rc_params[2]),2)); break; case 3: /* exp */ if(calPtr->rc_params[1]==0) v = 0; else v = calPtr->rc_params[2] + calPtr->rc_params[0]/(1+ (float)exp(-val/calPtr->rc_params[1])); break; case 4: /* linear fit */ v = calPtr->rc_params[0] + (val * calPtr->rc_params[1]); break; default: v = 0; break; } int_val = (INT32)((v+1.25)/(float)2.5); /* 2.5mV / DAC bit */ if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; chipPtr->basic.vthr = (UINT8) int_val; break; case ST_QCAL: /* * calculate the actual vcal step size taking into * account the capacitor correction factor: * step size = (c_factor * 0.0625) fC / DAC bit */ step = (float) 0.0625 * chipPtr->caldata.c_factor; int_val = (INT32)((val+(step/2))/step); if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; chipPtr->basic.vcal = (UINT8) int_val; break; case ST_TARGET: /* * record the target to which the chip has been trimmed */ int_val = (INT32)((val+1.25)/(float)2.5); /* 2.5mV / DAC bit */ if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; chipPtr->target = (UINT8) int_val; break; case ST_TTHR: /* * set the threshold in mV wrt the trim target */ int_val = (INT32)((val+1.25)/(float)2.5); /* 2.5mV / DAC bit */ int_val += (INT32) chipPtr->target; if (int_val<0x00) int_val = 0x00; else if(int_val>0xff) int_val = 0xff; chipPtr->basic.vthr = (UINT8) int_val; break; /* * BOC TX parameters - act only upon the PRIMARY TX CHANNEL * TODO - range checking */ case ST_TX_CURRENT: /* * set the TX laser current */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->pTTC, BOC_VAR_TXCURRENT, uint_val); break; case ST_TX_DELAY: /* * set the TX delay * NB. there are in fact two BPM delay registers, fine and coarse. * Here we merge both 8 bit registers into one 16 bit field. */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->pTTC, BOC_VAR_TXFINE, uint_val); setBocVariable(module->pTTC, BOC_VAR_TXCOARSE, (uint_val>>8)); break; case ST_TX_FINE: /* * set the TX fine delay */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->pTTC, BOC_VAR_TXFINE, uint_val); break; case ST_TX_COARSE: /* * set the TX coarse delay */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->pTTC, BOC_VAR_TXCOARSE, (uint_val>>8)); break; case ST_TX_MARKSPACE: /* * set the TX MarkSpace ratio */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->pTTC, BOC_VAR_TXMARKSPACE, uint_val); break; /* * BOC RX parameters * TODO - range checking */ case ST_RX_THRESHOLD: /* * set the RX thresholds for datalinks 0 and 1 */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[0], BOC_VAR_RXTHRESHOLD, uint_val); setBocVariable(module->rx[1], BOC_VAR_RXTHRESHOLD, uint_val); break; case ST_RX_THRESHOLD0: /* * set the RX threshold for datalink 0 only */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[0], BOC_VAR_RXTHRESHOLD, uint_val); break; case ST_RX_THRESHOLD1: /* * set the RX threshold for datalink 1 only */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[1], BOC_VAR_RXTHRESHOLD, uint_val); break; case ST_RX_DELAY: /* * set the RX delay for datalinks 0 and 1 */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[0], BOC_VAR_RXDELAY, uint_val); setBocVariable(module->rx[1], BOC_VAR_RXDELAY, uint_val); break; case ST_RX_DELAY0: /* * set the RX delay for datalink 0 only */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[0], BOC_VAR_RXDELAY, uint_val); break; case ST_RX_DELAY1: /* * set the RX delay for datalink 1 only */ uint_val = (UINT32) ((val+0.5)/(float)1.0); setBocVariable(module->rx[1], BOC_VAR_RXDELAY, uint_val); break; default: return -4; //break; } return 0; } /*============================================================================= * getChipVariable() *============================================================================= * * Operates upon the contents of ABCDChip structure, returning the * present setting of the variable denoted by "typ". * * Although the ABCDChip structure now stores the register values in terms * of bits, for reasons of compatibility with SCTDAQ this routine still * returns the DAC and delay values in terms of the following units: * o vthr - mV * o vcal - mV * o delay - bits * o preamp - microA * o shaper - microA * o TrimDAC - bits * * revised PWP 21.03.03 */ INT32 getChipVariable(ABCDModule *module, UINT32 theChip, UINT32 typ, FLOAT32 *val){ ABCDCaldata * calPtr; ABCDChip * chipPtr; float step; if(theChip>N_SCT_CHIPS-1) return -1; /* chip out of range */ chipPtr = &module->chip[theChip]; switch(typ) { case ST_VTHR: *val = (float) (chipPtr->basic.vthr * 2.5); /* 2.5mV / DAC bit */ break; case ST_VCAL: *val = (float) (chipPtr->basic.vcal * 0.625); /* 0.625mV / DAC bit */ break; case ST_STROBE_DELAY: *val = (float) chipPtr->basic.delay; break; case ST_PREAMP: *val = (float) (chipPtr->basic.preamp * 9.2); /* 9.2uA / bit */ break; case ST_SHAPER: *val = (float) (chipPtr->basic.shaper * 1.2); /* 1.2uA / bit */ break; case ST_CAL_MODE: *val = (float) chipPtr->basic.config.calibMode; break; case ST_COMPRESSION: *val = (float) chipPtr->basic.config.readoutMode; break; case ST_TRIM_RANGE: *val = (float) chipPtr->basic.config.trimRange; break; case ST_EDGE_DETECT: *val = (float) chipPtr->basic.config.edgeDetect; break; case ST_SEND_MASK: *val = (float) chipPtr->basic.config.mask; break; case ST_ACCUMULATE: *val = (float) chipPtr->basic.config.accumulate; break; case ST_FEEDTHROUGH: *val = (float) chipPtr->basic.config.feedThrough; break; case ST_ACTIVE: if(module->active){ *val = (float) chipPtr->active; }else{ *val = (float) 0.0; } break; case ST_SELECT: *val = (float) (module->select * 1.0); /* Select Flag status */ break; case ST_QTHR: calPtr = &chipPtr->caldata; *val = 0; switch(calPtr->rc_function){ case 1: /* polynomial */ /* * y = p0 +p1x +p2x^2 * x = (-p1 + sqrt((p1*p1)-(4*p2*(p0-y)))) / 2*p2 */ if(calPtr->rc_params[2]!=0){ *val = (float) (-calPtr->rc_params[1] + sqrt( (calPtr->rc_params[1]*calPtr->rc_params[1]) - (4*calPtr->rc_params[2]*(calPtr->rc_params[0]-(chipPtr->basic.vthr*2.5))) )) / (2*calPtr->rc_params[2]); } break; case 2: /* grillo */ /* * y = p0 + p1x(sqrt(1+(p1x/p2)^2)) * x = (y-p0)/p1(1-((y-p0)/p2)) */ if(calPtr->rc_params[2]!=0){ step = calPtr->rc_params[1]* ((float)1.0-(((chipPtr->basic.vthr*2.5)-calPtr->rc_params[0])/calPtr->rc_params[2])); if(step!=0){ *val = (float) ((chipPtr->basic.vthr*2.5)-calPtr->rc_params[0])/step; } } break; case 3: /* exp */ /* * y = p2 + p0/( 1 + exp(-x/p1)) * x = p1 * log( p0/(y-p2) -1) */ if( ( (chipPtr->basic.vthr*2.5) - calPtr->rc_params[2]) !=0){ step = ( calPtr->rc_params[0] / ( (chipPtr->basic.vthr*2.5) - calPtr->rc_params[2]) -1); if(step>0.0){ *val = -(float) (calPtr->rc_params[1] * log(step)); } } break; case 4: /* linear fit */ /* * y = p0 + p1x * x = (y-p0)/p1 */ if(calPtr->rc_params[1]!=0){ *val = (float) ((chipPtr->basic.vthr*2.5) - calPtr->rc_params[0]) / calPtr->rc_params[1]; } break; default: break; } break; case ST_QCAL: /* * calculate the actual vcal setting taking into * account the capacitor correction factor: * step size = (c_factor * 0.0625) fC / DAC bit */ calPtr = &chipPtr->caldata; step = (float) 0.0625 * chipPtr->caldata.c_factor; *val = (float) (chipPtr->basic.vcal * step); break; case ST_TARGET: /* * return the target in mV to which the chip has been trimmed * added PWP 07.01.03 */ *val = (float) (chipPtr->target * 2.5); /* 2.5mV / DAC bit */ break; case ST_TTHR: /* * return the threshold in mV after subraction of the trim target * added PWP 07.01.03 */ *val = (float) ((chipPtr->basic.vthr - chipPtr->target) * 2.5); /* 2.5mV / DAC bit */ break; default: *val = 0; return -4; //break; } return 0; } #endif /* !MDSP/!I_AM_NT_HOST */ #endif /* SCT function block. */