/************************************************************************************* * masterPrimFuncts_sct.c * * synopsis: Contains the SCT-specific primitive functions which are used only by * the MDSP. * * in this file: sendConfig, rwModuleData, rwModuleVariable. * * related files: * masterPrimFuncts.c: MDSP primitives common to both detectors. * listManager.c: Routines which manage the execution of a primitive list and * writing the reply data. * primFuncts.h: Declares the structure tag which communicates necessary information * to primitive functions. * primParams.h: Defines primitive ids which are used to index the array of pointers * to primitive functions, structure tags for primitive data and reply * data, and prototypes of primitive functions. * primFuncts.c: Contains primitive execution functions and the function which ini- * tializes the array of pointers to the primitive execution functions. * serialStreams.c: Contains routines which send and build serial streams to send to * the detector electronics. * * Douglas Ferguson, UW Madison (510) 486-5230 dpferguson@lbl.gov ************************************************************************************/ #include #include #include #include #include #include #include #include "resources.h" #include "registerIndices.h" #include "comRegDfns.h" #include "primParams.h" #include "serialStreams.h" #include "moduleMaskLUT_sct.h" #pragma CODE_SECTION(sendConfig, "xcode"); #pragma CODE_SECTION(rwModuleData, "xcode"); #pragma CODE_SECTION(rwModuleVariable, "xcode"); extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ extern far Module moduleConfigSet[N_MODULE_CONFIG_SETS][N_TOTMODULES]; extern far ModuleMaskData moduleMaskData[]; extern far RodConfig rodConfig; extern far CmdBuff cmdBuffer[]; UINT8 chipLut[N_CHIPS]= {M0_CHIP, S1_CHIP, S2_CHIP, S3_CHIP, S4_CHIP, E5_CHIP, M8_CHIP, S9_CHIP, S10_CHIP, S11_CHIP, S12_CHIP, E13_CHIP}; /************************************************************************************ * sendConfig * * synopsis: Sends module configuration data to the detector electronics. * * arguments * IN: * port: The serial port; can be SP0 (0), SP1 or SP_BOTH (2) * * module[2]: The modules to be configured. There are two independent serial * streams, so two modules can be configured at the same time. If * module[i]= NO_MODULE, no data is sent for that index; similarly if * module[i]= ALL_MODULES, the MDSP configures all modules for which the * configuration is present in the indicated configuration set. * * chip: The chip to configure (from ABCDChip.h); typically set to ALL_CHIPS. * * setLinks: If set, the routine will automatically set the ROD's command link * masks to the appropriate values for each module configured. If not * set no attempt is made to alter the command masks, and the serial * streams are broadcast to all enabled command links. * * cfgSet: The ID of the desired module cfg. data set to be sent. These are * defined in primParams_sct.h * * groupId: Modules can be configured separately according to their group IDs; * if set to ALL_GROUPS then no selection is made using this variable. * * dataType: The type of configuration data to send; this can be either BASIC, * TRIM or both data types (=> ALL). The dataTypes are defined in * primParams_sct.h * * activeOnly: If set, only modules with the active flag set are configured. * * enableDataTaking: If set, after the configuration data is sent, the modules * are placed into data-taking mode with an enable data-taking * command. * * OUT: none. * * author: Douglas Ferguson * * modifications/bugs: * - Use a standardized routine for input error checking, 10.07.04 dpsf ************************************************************************************/ INT32 sendConfig(PrimData *primData) { INT32 returnCode= SUCCESS, status; SendConfigIn *sendConfigIn= (SendConfigIn *) primData->priBodyPtr; UINT8 i, port, loop= FALSE, setLinks, cfgSet, groupId, activeOnly, enableDataTaking, module[2], chip, valid; UINT32 dataType; port= sendConfigIn->port; module[0]= sendConfigIn->module[0]; module[1]= sendConfigIn->module[1]; chip= sendConfigIn->chip; setLinks= sendConfigIn->setLinks; cfgSet= sendConfigIn->cfgSet; groupId= sendConfigIn->groupId; dataType= sendConfigIn->dataType; activeOnly= sendConfigIn->activeOnly; enableDataTaking= sendConfigIn->enableDataTaking; /* default reply length: */ primData->repBodyLength= 0; //Check dataType: valid= ( (dataType == CONFIG_MODULE_ALL) || (dataType == CONFIG_MODULE_TRIM) ||(dataType == CONFIG_MODULE_BASIC) ); if (!valid) { newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "sendConfig", "Invalid data type!\n", __FILE__, __LINE__); return returnCode; } //Check module index & config. set: if (module[0] == NO_MODULE) module[0]= module[1]; else if (module[1] == NO_MODULE) module[1]= module[0]; for (i= 0; i<2; ++i) { status= moduleIndexCheck(cfgSet, module[i], FALSE, TRUE, FALSE); if (status != SUCCESS) { addError(&returnCode, status, "sendConfig", "moduleIndexCheck", __FILE__, __LINE__); return returnCode; } } //Check that the chip number is valid: valid= (chip == ALL_CHIPS); for (i=0; i the ABCDBasic, * ABCDChip or entire ABCDModule structure. The trim DACs are an exception * to this rule. * * If only parts of an ABCDChip structure are to be loaded onto the MDSP, * the input data (which follows the primitive's input structure) must * stacked in the order: 1) config register data or ABCDBasic structure, * 2) calibration data, and then finally trim DAC data. If ALL_CHIPS is * selected, the chips are then stacked in order. * * OUT: ABCDModule: If reading module config data, the primitive's reply contains * the data, which is an entire module configuration structure. * If writing or copying, the routine returns nothing. * * author: Douglas Ferguson * * modifications/bugs: * - Use a standardized routine for input error checking, 10.07.04 dpsf * * - Initialize of the ROD command and data line masks if the data is being * placed in the PHYSICS configuration database, and test to make sure * that any given formatter only has modules with the same bandwidth * connected. 15.07.04 dpsf ************************************************************************************/ INT32 rwModuleData(PrimData *primData) { INT32 returnCode= SUCCESS, status; RwModuleDataIn *rwModuleDataIn= (RwModuleDataIn *) primData->priBodyPtr; RwModuleDataOut *rwModuleDataOut= (RwModuleDataOut *) primData->repBodyPtr; UINT32 fRead, srcCfgSet, cfgSet, cfgBitfield, module, chip, dataType; UINT32 cfg, min, max, cmin, cmax, i, c, m, mi, valid, mask; UINT8 basic, fCopy, fmtLink[2], cmdLine; Module *modulePtr, *srcModPtr; Chip *chipPtr, *srcChipPtr; UINT32 *src; fRead= rwModuleDataIn->fRead; //=> read/write fCopy= rwModuleDataIn->fCopy; //=> or copy between sets. srcCfgSet= rwModuleDataIn->copySrcCfgSet; //source cfgSet= rwModuleDataIn->cfgSet; //destination. cfgBitfield= rwModuleDataIn->cfgBitfield; //dest. is bitfield module= rwModuleDataIn->module; //module index (can be all) chip= rwModuleDataIn->chip; //chip index (can be all) dataType= rwModuleDataIn->dataType; //Type of data to write/copy. //Default reply length- module cfg. data if reading, zero otherwise. if (fRead) primData->repBodyLength= SIZEOF(RwModuleDataOut); else primData->repBodyLength= 0; //The basic structure is compound; test whether we're doing the whole of it: basic= ((dataType & CONFIG_MODULE_BASIC) == CONFIG_MODULE_BASIC); /******************************************************************/ //Check validity of the routine's inputs: /* fRead => read out module data, & !fRead => write it (as in several other primitives). If writing, there must be input data beyond the input structure. If copying however, the info. is alreay on the ROD & there is no input data beyond the structure; so to keep the meaning of the fRead flag consistent with other primitives and also be able to distinguish between writing and copying, only one operation is permitted per primitive: */ if ((fRead) && (fCopy)) { newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "rwModuleData", "Only one operation (read/write/copy) per primitive.\n", __FILE__, __LINE__); return returnCode; } /*==> Check if the module index is in range. <==*/ status= moduleIndexCheck(cfgSet, module, FALSE, FALSE, cfgBitfield); if (status != SUCCESS) { addError(&returnCode, status,"rwModuleData", "moduleIndexCheck", __FILE__, __LINE__); return returnCode; } if (!cfgBitfield) cfgSet= 1<= N_MODULE_CONFIG_SETS)) ) { newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "rwModuleData", "Invalid value for (src)cfgSet.\n", __FILE__, __LINE__); return returnCode; } /* Test the integrity of the dataType- the *_other config module data cannot be included unless the entire surrounding structure is (basic for basic-other, chip for chip-other, and module for module-other. Several factors lie behind this restriction: 1) The chip-other & module-other information is expected to be effectively static. 2) The entire basic structure is not much bigger than the basic-other data. 3) It is complicated to copy non-structured information, and 4) decidedly dangerous to do so if the module structure ever changes. Note basic == basic-other +cfg */ i= 0; //borrow i as flag. if (dataType != CONFIG_MODULE_ALL) { if (dataType & CONFIG_MODULE_OTHER) i= 1; if ((dataType & CONFIG_MODULE_CHIP_OTHER) && (dataType != CONFIG_MODULE_CHIP)) i= 1; if ((dataType & CONFIG_MODULE_BASIC_OTHER) && (!(dataType & CONFIG_MODULE_CFG))) i= 1; } if (i) { newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "rwModuleData", "Invalid dataType: 'other' data included without the " "enclosing structure.\n", __FILE__, __LINE__); return returnCode; } //Test the primitive's input data size (borrow variables): if ((fCopy) || (fRead)) m= SIZEOF(RwModuleDataIn); else { m= SIZEOF(RwModuleDataIn); i= (chip == ALL_CHIPS)? N_CHIPS:1; if (dataType == CONFIG_MODULE_ALL) m+= SIZEOF(ABCDModule); else if (dataType == CONFIG_MODULE_CHIP) m+= i*SIZEOF(ABCDChip); else { //ABCDChip sub-structures: if ((dataType & CONFIG_MODULE_CFG) && (!basic)) m+= i*SIZEOF(ABCDConfig); else if (basic) m+= i*SIZEOF(ABCDBasic); if (dataType & CONFIG_MODULE_CALDATA) m+= i*SIZEOF(ABCDCaldata); if (dataType & CONFIG_MODULE_TRIM) m+= i*SIZEOF(chipPtr->trim); } } if (m != primData->priBodyLength) { newError(&returnCode, PRIM_DATA_ERROR, FATAL_ERR, "rwModuleData", "The primitive body length is incorrect.\n", __FILE__, __LINE__); return returnCode; } /******************************************************************/ //if (!cfgBitfield) cfgSet= 1<present) continue; copyMem(srcModPtr, modulePtr, SIZEOF(Module)); } else { for (c=cmin; cdataPresent & (1<chip[c]; chipPtr= &modulePtr->chip[c]; /* dataPresent bitfield lumps all types of chip data into one bit (expand later if necessary). Note that if a full module cfg. is written to or copied, the chip data must be present too, so this info being over-written will have no effect. */ modulePtr->dataPresent|= 1<basic.config, &chipPtr->basic.config, SIZEOF(ABCDConfig)); } else if (basic) { copyMem(&srcChipPtr->basic, &chipPtr->basic, SIZEOF(ABCDBasic)); } if (dataType & CONFIG_MODULE_CALDATA) { copyMem(&srcChipPtr->caldata, &chipPtr->caldata, SIZEOF(ABCDCaldata)); } if (dataType & CONFIG_MODULE_TRIM) { copyMem(&srcChipPtr->trim[0], &chipPtr->trim[0], SIZEOF(chipPtr->trim)); } } //whole vs. sub-chip structures } //chip } //module vs. chip } //module } //cfg. set } //Copying data between cfg sets. /******************************************************************/ if (fRead) { for (cfg=0; cfgpresent= TRUE; modulePtr->moduleNumber= m; if (!modulePtr->select) cmdLine= srcModPtr->pTTC; else cmdLine= srcModPtr->rTTC; fmtLink[0]= srcModPtr->rx[0]; fmtLink[1]= srcModPtr->rx[1]; if ( (module == ALL_MODULES) ||( (fmtLink[0] == DEFAULT_DATA_LINK) &&(fmtLink[1] == DEFAULT_DATA_LINK)) ) { modulePtr->rx[0]= fmtLink[0]= moduleMaskLUT[m].fmtLink[0]; modulePtr->rx[1]= fmtLink[1]= moduleMaskLUT[m].fmtLink[1]; } if ((module == ALL_MODULES) || (cmdLine == DEFAULT_TTC)) { modulePtr->pTTC= cmdLine= moduleMaskLUT[m].cmdLine; } /* dataPresent bitfield contains 1 bit per chip, together with flags to indicate that the all the global module information is present. (also see r/w module var.) */ modulePtr->dataPresent= (MODULE_GLOBAL_DATA) +(MODULE_PRESENT); modulePtr->dataPresent|= 0xfff; //Is this reference data (module => physics)? : if (cfg == PHYSICS_CONFIG_SET) { //Mask data is loaded from the PHYSICS cfg. modulePtr->dataPresent|= (MODULE_MASK_DATA); /* Update the module's index in the ROD's global link database, and add it to the initial mask set (for PHYSICS-- the SCAN set does not alter the ROD masks): */ status= setMaskConfig(m, cmdLine, fmtLink); if (status != SUCCESS) { addError(&returnCode, status,"rwModuleData","setMaskConfig", __FILE__, __LINE__); return returnCode; } sprintf(genStr, "Module index %02d uses cmd line %02d, " "formatter links 0x%02x & 0x%02x.\n", m, cmdLine, fmtLink[0], fmtLink[1]); newInformation(__FILE__, __LINE__, genStr); //Update the INIT mask configuration set: i= (DATA_LINK_PLAY) +(COMMAND_LINK_ON) +(LINK_CFG_ON); setLinkMasks(m, SP0, i, UPDATE_MASK, MASK_SET_INIT); } } else { /* If looping, reset to beginning of input. Note that this is *not* actually a pointer to a full set of module cfg. data. */ src= (UINT32 *) srcModPtr; for (c=cmin; cchip[c]; /* dataPresent bitfield lumps all types of chip data into one bit (expand later if necessary). Note that if a full module cfg. is written to or copied, the chip data must be present too, so this info being over-written will have no effect. */ modulePtr->dataPresent|= 1<basic.config, SIZEOF(ABCDConfig)); src+= SIZEOF(ABCDConfig); } else if (basic) { copyMem(src, &chipPtr->basic, SIZEOF(ABCDBasic)); src+= SIZEOF(ABCDBasic); } if (dataType & CONFIG_MODULE_CALDATA) { copyMem(src, &chipPtr->caldata, SIZEOF(ABCDCaldata)); src+= SIZEOF(ABCDCaldata); } if (dataType & CONFIG_MODULE_TRIM) { copyMem(src, &chipPtr->trim[0], SIZEOF(chipPtr->trim)); src+= SIZEOF(chipPtr->trim); } } //whole vs. sub-chip structures } //chip } //module vs. chip } //module } //cfg. set } //Writing module data to ROD /******************************************************************/ //If copying or writing, update the mask info (used by MDSP): if ( ((fCopy) || (!fRead)) & (basic)) { //masks are in basic struct for (cfg=0; cfgdataPresent & 0xfff) == 0xfff) modulePtr->normalMasks= 0xf; for (c=0; cdataPresent & (1<chip[c].normalMasks= 0xf; for (i=0; i<4; ++i) { //i => calibration line check mask= 0x11111111< channels 0-31, 32-63, 64-95, 96-127 for (mi=0; mi<4; ++mi) { if ((modulePtr->chip[c].basic.mask[mi] & mask) != mask) { modulePtr->normalMasks &= ~(mask); modulePtr->chip[c].normalMasks &= ~(mask); } } //mi } //i } //c } //m } //cfg } //do mask update. return returnCode; } /************************************************************************************ * rwModuleVariable * * synopsis: Changes or retrieves chip register settings inside a pre-loaded * module structure (in one of the structure sets). * * arguments * IN: read: If set, indicates that the variable is to be read from the * structure & returned via the reply list. #define RW_MODULE_VARIABLE (1 + (SET_ROD_MODE)) #define R_RW_MODULE_VARIABLE 100 struct RW_MODULE_VARIABLE_IN { UINT32 read, sendToModule, structId, groupId, module, chip, varType, dataLen; MDAT32 *data; }; struct RW_MODULE_VARIABLE_OUT { UINT32 dataLen; MDAT32 *data; }; #define MVAR_GROUP_ID 100 #define MVAR_ACTIVE 101 #define R_RW_MODULE_VARIABLE 103 //variable types defined in ABCDScans.h typedef struct { UINT32 fRead, cfgSet, groupId, module, chip, varType; UINT32 info; for writing: output message? UINT32 dataLen; for writing: length of data (e.g. mask= 4) } RwModuleVariableIn_v103; //If writing, data follows directly after structure. typedef struct { UINT32 nModData, dataLen; } RwModuleVariableOut_v103; //If reading, data follows directly after structure. #define MVAR_GROUP_ID 100 #define MVAR_ACTIVE 101 #define MVAR_PRESENT 102 extern far Module moduleConfigSet[N_MODULE_CONFIG_SETS][N_TOTMODULES]; * * author: Douglas Ferguson * * modifications/bugs: * - Use a standardized routine for input error checking, 10.07.04 dpsf ************************************************************************************/ INT32 rwModuleVariable(PrimData *primData) { INT32 returnCode= SUCCESS, status; RwModuleVariableIn *rwModuleVarIn= (RwModuleVariableIn *) primData->priBodyPtr; RwModuleVariableOut *rwModuleVarOut= (RwModuleVariableOut *) primData->repBodyPtr; UINT8 fRead, cfgSet, cfgBitfield, groupId, module, chip, varType; UINT32 nModData, dataLen; MDAT32 *data, val; UINT8 info1, info, cfg, mod, min, max, c, cmin, cmax, pCheck, setMasks; UINT32 i; Module *modulePtr; fRead= rwModuleVarIn->fRead; cfgSet= rwModuleVarIn->cfgSet; cfgBitfield= rwModuleVarIn->cfgBitfield; groupId= rwModuleVarIn->groupId; module= rwModuleVarIn->module; chip= rwModuleVarIn->chip; varType= rwModuleVarIn->varType; if (!fRead) { info1= rwModuleVarIn->info; dataLen= rwModuleVarIn->dataLen; data= (MDAT32 *) ((UINT32 *) rwModuleVarIn +SIZEOF(RwModuleVariableIn)); primData->repBodyLength= 0; } else { nModData= 0; dataLen= 0; //will be incremented later. data= (MDAT32 *) ((UINT32 *) rwModuleVarOut +SIZEOF(RwModuleVariableOut)); primData->repBodyLength= SIZEOF(RwModuleVariableOut); } /*==> Check if the module index is in range. <==*/ status= moduleIndexCheck(cfgSet, module, FALSE, FALSE, cfgBitfield); if (status != SUCCESS) { addError(&returnCode, status,"rwModuleVariable", "moduleIndexCheck", __FILE__, __LINE__); return returnCode; } if (!cfgBitfield) cfgSet= 1<present); else { if (fRead) pCheck= TRUE; //Reading: get present flag for modules. else { //Writing: //If turning present flag off (data == 0), check 1st. if (!(*data)) pCheck= modulePtr->present; /* If turning flag on, must be done for individual modules and the data must have been pre-loaded. The actual check is done below in the section dedicated to the present flag. */ else pCheck= TRUE; } } if ( (!pCheck) ||((groupId != MODULE_GROUP_ALL) && (modulePtr->groupId != groupId)) ) continue; if (fRead) ++nModData; /* Module presense is treated differently than the other variables due to the global implications for the ROD. If turning it off, the routine will also turn off its mask in the INIT mask set on the ROD. If turning it on, it will undo this action provided that there was actual module information (with masks) there in the 1st place. */ if (varType == MVAR_PRESENT) { if (fRead) { *data++= (MDAT32) modulePtr->present; ++dataLen; ++primData->repBodyLength; } else { setMasks= ( (cfgSet == PHYSICS_CONFIG_SET) &&(modulePtr->dataPresent & MODULE_MASK_DATA) ); if (!(*data)) { //Turn off present flag: modulePtr->present= (UINT8) *data; i= (DATA_LINK_SKIP) +(COMMAND_LINK_OFF) +(LINK_CFG_OFF); info= info1; //Print message for all present modules. } else { if (modulePtr->dataPresent & MODULE_GLOBAL_DATA) { modulePtr->present= (UINT8) *data; i= (DATA_LINK_PLAY) +(COMMAND_LINK_ON) +(LINK_CFG_ON); info= info1; } else {setMasks= info= FALSE;} } //Update the INIT masks: if (setMasks) setLinkMasks(mod, SP0, i, UPDATE_MASK, MASK_SET_INIT); } } else if (varType == MVAR_SELECT) { if (fRead) { *data++= (MDAT32) modulePtr->select; ++dataLen; ++primData->repBodyLength; } else { modulePtr->select= (UINT8) *data; setMasks= ( (cfgSet == PHYSICS_CONFIG_SET) &&(modulePtr->dataPresent & MODULE_MASK_DATA) ); if (!(*data)) c= modulePtr->pTTC; //Use primary command line. else c= modulePtr->rTTC; //Use redundant command line. if (setMasks) { setLinkMasks(mod, SP0, COMMAND_LINK_OFF, UPDATE_MASK, MASK_SET_INIT); moduleMaskData[mod].cmdLine= c; setLinkMasks(mod, SP0, COMMAND_LINK_ON, UPDATE_MASK, MASK_SET_INIT); } } } else if (varType == MVAR_GROUP_ID) { if (fRead) { *data++= (MDAT32) modulePtr->groupId; ++dataLen; ++primData->repBodyLength; } else { modulePtr->groupId= (UINT8) *data; } } else if (varType == MVAR_ACTIVE) { if (fRead) { *data++= (MDAT32) modulePtr->active; ++dataLen; ++primData->repBodyLength; } else { modulePtr->active= (UINT8) *data; } } else { for (c= cmin; c < cmax; ++c) { if (fRead) { status= getChipVariable(modulePtr, c, varType, &val); *data++= val; ++dataLen; ++primData->repBodyLength; } else { status= setChipVariable(modulePtr, c, varType, *data); } if (status != SUCCESS) { sprintf(genStr,"%s%d%s","Unknown chip variable! (", varType,")\n"); newError(&returnCode, PARAM_ERROR, FATAL_ERR, "rwModuleVariable", genStr, __FILE__, __LINE__); return returnCode; } } } if (fRead) { rwModuleVarOut->nModData= nModData; rwModuleVarOut->dataLen= dataLen; } else if (info) { sprintf(genStr,"%s%d%s%d%s0x%02x %s%d%s%f%s", "Setting set ",cfg, ", module ", mod, ", chip ", chip, " variable type ", varType, " to value ", *data,".\n"); newInformation(__FILE__, __LINE__, genStr); } } //Loop over modules. } //Loop over cfg. sets. return returnCode; }