Hi Adrian,
Please put this statement in your startup script just before iocInit:
asynReport 1 BPM1
That will print out the contents of the parameter library, which should show if the parameters that are reported as missing actually exist.
Mark
From: Adrian Martinez <adrian.martinez at orolia.com>
Sent: Monday, July 11, 2022 9:05 AM
To: Mark Rivers <rivers at cars.uchicago.edu>
Cc: tech-talk <tech-talk at aps.anl.gov>
Subject: RE: EPICS compilation errors
All the code that I sent you belongs to AsynDrvr.cpp. This file also includes this part of the code where setup() is called, depending on the device (BPM1 or BPM2):
#ifdef __BPM2__
int AsynBPM2DrvrConfigure(const char *portName, int index )
EWBAsynPortDrvr *drvr = (EWBAsynPortDrvr *)new asynBPMDrvr(portName, index);
asynStatus status = drvr->setup();
/* EPICS iocsh shell commands */
static const iocshArg initArg0 = { "portName",iocshArgString};
static const iocshArg initArg1 = { "index",iocshArgInt};
static const iocshArg * const initArgs[] = {&initArg0, &initArg1};
static const iocshFuncDef initFuncDef = {"AsynBPM2DrvrConfigure",2,initArgs};
static void initCallFunc(const iocshArgBuf *args)
AsynBPM2DrvrConfigure(args[0].sval, args[1].ival);
void AsynBPM2DrvrRegister(void)
iocshRegister(&initFuncDef,initCallFunc);
epicsExportRegistrar(AsynBPM2DrvrRegister);
int AsynBPM1DrvrConfigure(const char *portName, int index )
EWBAsynPortDrvr *drvr = (EWBAsynPortDrvr *)new asynBPMDrvr(portName, index);
asynStatus status = drvr->setup();
/* EPICS iocsh shell commands */
static const iocshArg initArg0 = { "portName",iocshArgString};
static const iocshArg initArg1 = { "index",iocshArgInt};
static const iocshArg * const initArgs[] = {&initArg0, &initArg1};
static const iocshFuncDef initFuncDef = {"AsynBPM1DrvrConfigure",2,initArgs};
static void initCallFunc(const iocshArgBuf *args)
AsynBPM1DrvrConfigure(args[0].sval, args[1].ival);
void AsynBPM1DrvrRegister(void)
iocshRegister(&initFuncDef,initCallFunc);
epicsExportRegistrar(AsynBPM1DrvrRegister);
Regarding the
EWBAsynPortDrvr(), this class inherits from asynPortDriver. Its constructor is:
/**
* Constructor for the asynWBPortDrvr class.
* This class is an helper class:
* must have a child class and call a parent class
* \param[in] portName The name of the asyn port driver to be created.
* \param[in] max_nprm Maximum number of scope parameters
EWBAsynPortDrvr::EWBAsynPortDrvr(const char *portName,int max_nprm)
: asynPortDriver(portName,
(asynInt32Mask | asynFloat64Mask | asynOctetMask | asynInt32ArrayMask | asynFloat32ArrayMask | asynDrvUserMask), /* Interface mask */
(asynInt32Mask | asynFloat64Mask | asynOctetMask | asynInt32ArrayMask | asynFloat32ArrayMask ), /* Interrupt mask */
0, /* asynFlags. This driver does not block and it is not multi-device, so flag is 0 */
0, /* Default priority */
0), /* Default stack size*/
pRoot(NULL), driverName(portName)
afld.syncflags=AWB_SYNC_DERIVED; //when not define we derive
fldPrms = std::vector<EWBAsynPrm>( max_nprm,afld);
syncNow=EWBSync::EWB_AM_RW;
}
Regarding the creataParam method, you are right. I have overridden the createParam() method. I attach the different versions of createParam:
/**
* Create a asyn parameter and link it to a WB field
* With this method: the name given to the process variable will be auto-generated in the format
* \<reg_name\>_\<field_name\>
* \note If there is only one field named 'value' the generated name will only have the reg_name
* \param[in] fld A WBField that is going to be link with the parameter
* \param[in] pIndex PV index
* \param[in] syncflags Select in which mode we want to sync between PV and device/library.
* \return Returns a asynSuccess if everything is okay. Otherwise asynParamAlreadyExists if the parameter already exists, or asynBadParamIndex if
* adding this parameter would exceed the size of the parameter list and asynError is the WBField is not valid.
* \see AsynWBSync for the type of synchronization
asynStatus EWBAsynPortDrvr::createParam(EWBField* fld,int *pIndex, uint32_t syncflags)
TRACE_CHECK_PTR(fld,asynError);
TRACE_CHECK_PTR(fld->getReg(),asynError);
if(fld->getName()==fld->getReg()->getName() || (fld->getName()=="value" && fld->getReg()->getFields().size()==1))
ss << fld->getReg()->getName();
ss << fld->getReg()->getName() << "_" << fld->getName();
return this->createParam(ss.str().c_str(),fld, pIndex, syncflags);
* Create a asyn parameter and link it to a WB field
* \param[in] name The name of this parameter
* \param[in] pPrm A WBField that is going to be link with the parameter
* \param[in] pIndex PV index.
* \param[in] syncflags Select in which mode we want to sync between PV and device/library.
* \return Returns a asynSuccess if everything is okay. Otherwise asynParamAlreadyExists if the parameter already exists, or asynBadParamIndex if
* adding this parameter would exceed the size of the parameter list and asynError is the WBField is not valid.
* \see AsynWBSync for the type of synchronization
asynStatus EWBAsynPortDrvr::createParam(const char* name, EWBParam* pPrm,int *pIndex, uint32_t syncflags)
asynStatus status=asynError;
if(pPrm && pPrm->isValid())
pIndex=(pIndex)?pIndex:&tmp;
if(pPrm->getType() == EWBParam::EWBF_STRING)
else if(pPrm->getType() & EWBParam::EWBF_TM_TYPE_FIELD)
if(pPrm->getType() & EWBParam::EWBF_TM_FIXED_POINT){
TRACE_P_WARNING("Unknown type 0x%x for Param %s (pv:%s)",pPrm->getType(), pPrm->getCName(), name);
status = asynPortDriver::createParam(name,atype,pIndex);
fldPrms[*pIndex].pPrm=pPrm;
fldPrms[*pIndex].syncflags=syncflags;
fldPrms[*pIndex].atype=atype;
setStringParam(*pIndex, pPrm->getString().c_str()); break; //TODO:CHECK this
setIntegerParam(*pIndex,pPrm->getU32()); break;
setDoubleParam(*pIndex,pPrm->getFloat()); break;
TRACE_P_WARNING("Type 0x%x not handled",atype);
EWBField *pFld=pPrm->castField();
TRACE_P_DEBUG("#%03d:%-15s ; val:%s (flgsync=x%03x, %s) => %s.%s.%s (0x%08X) ",
*pIndex,name,pPrm->getString().c_str(),
syncflags,(atype==asynParamInt32)?"I32":"U64",
pFld->getReg()->getPrtNode()->getCName(),pFld->getReg()->getCName(),pFld->getCName(),
pFld->getReg()->getOffset(true));
EWBParamStr *pPrmStr=pPrm->castParamStr();
TRACE_P_DEBUG("#%03d:%-15s ; val:%s (flgsync=x%03x, %s) => key:%s ",
*pIndex,name,pPrm->getString().c_str(),syncflags,
(atype==asynParamOctet)?"Oct":((atype==asynParamInt32)?"I32":"U64"),
* Create parameters for internal use of the IOC
* This parameters will not be synchronized with our device. This function override the standard
* asynPortDriver::createParam(), and only add the syncflags to AWB_SYNC_PRMLIST or AWB_SYNC_DERIVED
* \param[in] name The name of this parameter
* \param[in] atype The type of parameters A WBField that is going to be link with the parameter
* \param[in] pIndex PV index.
* \param[in] syncflags Select in which mode we want to sync. As we don't communicate with the device we can not set AWB_SYNC_DEVICE or AWB_SYNC_WBSTRUCT
* \return Returns a asynSuccess if everything is okay. Otherwise asynParamAlreadyExists if the parameter already exists, or asynBadParamIndex if
* adding this parameter would exceed the size of the parameter list and asynError is the syncflags is not valid.
* \see AsynWBSync for the type of synchronization
asynStatus EWBAsynPortDrvr::createParam(const char* name, asynParamType atype,int *pIndex,uint32_t syncflags)
asynStatus status=asynError;
TRACE_CHECK_VA(!(syncflags & EWB_SYNC_FLG_DEV),status,"Bad sync mode :%d",syncflags);
pIndex=(pIndex)?pIndex:&tmp;
status=asynPortDriver::createParam(name,atype,pIndex);
if( status==asynSuccess )
fldPrms[*pIndex].pPrm=NULL;
fldPrms[*pIndex].syncflags=syncflags;
fldPrms[*pIndex].atype=atype;
TRACE_P_DEBUG("#%03d:%-15s (flgsync=x%03x, %s:%d)",*pIndex,name,syncflags,paramVal::typeNames[atype], atype);
case asynParamOctet: setStringParam(*pIndex,""); break;
case asynParamInt32: setIntegerParam(*pIndex,0); break;
case asynParamFloat64: setDoubleParam(*pIndex,0); break;
default: TRACE_P_WARNING("Type 0x%x not handled",atype);
Finally, I have done the test that you have proposed including a print at the end of asynDrvr::setupEWBPeriphCtl() and a date print immediately after
iocInit but everything seems to be working fine. I attach the log of the ioc startup:
# /root/topBPM/bin/linux-arm/AsynDrvr1 /root/topBPM/iocBoot/iocAsynDrvr1/st_bpm1.cmd
#!../../bin/linux-arm/AsynDrvr
Can't open envPaths: No such file or directory
##Set the DATADIR (store autosave, datalog, etc.)
epicsEnvSet( "TOP","/root/topBPM")
epicsEnvSet( "DATADIR","." )
epicsEnvSet( "IOCPATH","/root" )
epicsEnvSet( "EPICS_CA_MAX_ARRAY_BYTES","45000")
epicsEnvSet( "BPM","BPM1")
epicsEnvSet( "CHANNEL", "Cha")
##Set the host EPICS name
epicsEnvSet("EPICS_HOST_1",SL-SCL-CM3:DIA-BPM-3)
## Register all support components
dbLoadDatabase ("dbd/AsynDrvr1.dbd")
AsynDrvr_registerRecordDeviceDriver(pdbbase)
AsynDrvrConfigure( "BPM1", 0, "./datalog" )
**************************************END OF setupEWBPeriphCtl()********************************************
## Load record instances for BPM-1
dbLoadRecords( "db/7s_ctl.db", "user=SL-SCL-CM3:DIA-BPM-3, PORT=BPM1, ADDR=0, TIMEOUT=0" )
dbLoadRecords( "db/7s_bpm_time.db", "user=SL-SCL-CM3:DIA-BPM-3, PORT=BPM1, ADDR=0, TIMEOUT=1, MACROTIME=SL-SCL-CM3:TIM-EVR-3" )
# dbLoadRecords( "db/7s_pm_slw_idx.db", "user=${EPICS_HOST_1}, PORT=${BPM}, ADDR=0, TIMEOUT=1" )
## Set this to see messages from mySub
## Run this to trace the stages of iocInit
## setup autosave files and directories
set_savefile_path("/home/epics-user/data/autosave")
set_requestfile_path("/root/topBPM/iocBoot/iocAsynBPM1")
set_pass1_restoreFile("auto_settings_BPM1.sav")
# Number of sequenced backup files (e.g., 'auto_settings.sav0') to write
save_restoreSet_NumSeqFiles(0)
save_restoreSet_DatedBackupFiles(0)
#cd "${TOP}/iocBoot/${IOC}"
############################################################################
## EPICS Base built Jul 1 2022
############################################################################
2022/07/11 10:54:15.414 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_PosMesEna
SL-SCL-CM3:DIA-BPM-3:PosMesEnaStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.414 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_Alarm
SL-SCL-CM3:DIA-BPM-3:AlarmStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.414 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_Acqst
SL-SCL-CM3:DIA-BPM-3:AcqstStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.414 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_SelfClbEna
SL-SCL-CM3:DIA-BPM-3:SelfClbStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.414 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_CableClbEna
SL-SCL-CM3:DIA-BPM-3:CableClbStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.415 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_get_idle
SL-SCL-CM3:DIA-BPM-3:IdleEnaStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.415 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Cavity_present
SL-SCL-CM3:DIA-BPM-3:CavityPresentStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.415 asynPortDriver:drvUserCreate: addr=0, cannot find parameter disable_calibration
SL-SCL-CM3:DIA-BPM-3:DisableCalibrationStat devAsynInt32::initCommon drvUserCreate
2022/07/11 10:54:15.415 asynPortDriver:drvUserCreate: addr=0, cannot find parameter ctl_pps_utc_sw
SL-SCL-CM3:DIA-BPM-3:PpsUtcSoftRb devAsynInt32::initCommon drvUserCreate
reboot_restore: entry for file 'auto_settings_BPM1.sav'
reboot_restore: Found filename 'auto_settings_BPM1.sav' in restoreFileList.
*** restoring from '/home/epics-user/data/autosave/auto_settings_BPM1.sav' at initHookState 7 (after record/device init) ***
37 PVs had no saved value.
reboot_restore: done with file 'auto_settings_BPM1.sav'
iocRun: All initialization complete
2022/07/11 10:54:15.945194 --> DATE AFTER IOCINIT
create_monitor_set("auto_settings_BPM1.req", 1, "id=SL-SCL-CM3:DIA-BPM-3")
## Create info_x.req file in current directory (Use req_info2auto.sh to obtain auto_x.req)
epics>
Let me know if you see something wrong in the code or if you need another part of the code.
CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know the content is safe.
You are creating your parameters in asynDrvr::setupEWBPeriphCtl(), which is called from asynDrvr::setup(). However, the code you sent does not show where asynDrvr::setup() is called
from.
Your driver does not inherit directly from asynPortDriver, but rather from EWBAsynPortDrvr() so I don't know what it's constructor does.
There are things I don't understand. The definitions of asynPortDriver::createParam() are:
asynPortDriver.h: virtual asynStatus createParam( const char *name, asynParamType type, int *index);
asynPortDriver.h: virtual asynStatus createParam(int list, const char *name, asynParamType type, int *index);
So it takes either 3 or 4 arguments. You are sometimes calling it with 3 arguments, as it typical:
createParam( "enable_compensation", asynParamInt32, &idxEnableCompensation);
However, here you are calling it with 2 arguments
createParam( "ntp_status", asynParamInt32 );
And here with only 1 argument:
The argument is always a pointer, and the next to last is always asynParamType, but here your have not passed asynParamType.
createParam( pIdle, &idxIdle );
All of this suggests to me that you have overridden the createParam() method in ways you have not shown.
The symptoms you have suggest that asynDrvr::setup() has not completed before iocInit. That could happen if asynDrvr::setup() is being called from
some other thread.
You can see whether this is true by adding asynPrint statements in asynDrvr::setupEWBPeriphCtl() with ASYN_TRACE_ERROR and see if those messages are all complete
before iocInit is done. Add a "date" statement to your startup script immediately after iocInit.
asynDrvr::asynDrvr( const char *portName, int index )
:EWBAsynPortDrvr( portName, MAX_NUM_SCOPE_PARAMS )
pBgd = (EWBBridge*)new EWBBgdAXICon( WB2_ROOT_PERIPH_OFFSET, WB2_PERIPH_MAPPING_SIZE,
WB2_PM_SLW_PERIPH_OFFSET, (uint32_t)WB2_PM_SLW_PERIPH_LAST, WB2_PM_SLW_BLOCKSIZE,
WB2_PM_RAW_PERIPH_OFFSET, (uint32_t)WB2_PM_RAW_PERIPH_LAST, WB2_PM_RAW_BLOCKSIZE);
//Then define the root of the bus
pRoot = new EWBBus( pBgd, 0x0, NULL );
if(pRoot->isValid()==false){
printf("ERROR while creating pRoot!");
EWBTrace::getInstance().setLevel(EWBTrace::DEBUG);
EWBTrace::getInstance().setLevel(EWBTrace::ERROR);
EWBTrace::getInstance().setLevel(EWBTrace::ERROR);
// Setup for all the params needed in the driver. Create all the params included in each periph
asynStatus asynDrvr::setup()
AsynStatusObj status = asynSuccess;
}
asynStatus asynDrvr::setupEWBPeriphCtl()
AsynStatusObj status = asynSuccess;
pPrhCtl = new EWBPeriph(this->pRoot,WB2_PRH_ARGS( CTL ));
lastreg = new EWBReg( pPrhCtl, WB2_REG_ARGS( CTL, CTRL ));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, RSTSW )));
pPosMes = new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, POSMESENA ),0);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM ), 1), &idxAlarm , EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV); // TS3
pAcqst = new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ACQST ),0);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, USERBUFDUMP )), &idxDumpBuffer, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
pChannelCalib = new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, SELFCLBENA ));
createParam(pChannelCalib, &idxChannelCalib, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV | EWB_SYNC_FLG_PRE);
// createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, CABLECLBENA )), &idxCableCalib, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
pCableCalib = new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, CABLECLBENA ));
createParam( pCableCalib, &idxCableCalib, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, CNF_RDY )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, BPM_RDY )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_X )), &idxAlarmX, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_Y )), &idxAlarmY, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_I )), &idxAlarmI, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_P )), &idxAlarmP, EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_X_ACK )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_Y_ACK )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_I_ACK )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, ALARM_P_ACK )));
pIdle = new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, GET_IDLE ));
createParam( pIdle, &idxIdle );
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, CTRL, BPMSTATE )), &idxBpmState, EWB_SYNC_FLG_PRE | EWB_SYNC_FLG_POST | EWB_SYNC_FLG_DEV);
// Code to set the machine in Startup mode in each driver reboot
lastreg = new EWBReg( pPrhCtl, WB2_REG_ARGS( CTL, OVERAGE ));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, OVERAGE, ADC_TOP )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, OVERAGE, ADC_BOTTOM )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, OVERAGE, ADC_RIGHT )));
createParam( new EWBField( lastreg, WB2_FIELD_ARGS( CTL, OVERAGE, ADC_LEFT )));
createParam( "calibration_msg", asynParamOctet, &idxCalibrationMsg );
setStringParam( idxCalibrationMsg, "Please, select calibration to calibrate the system" );
createParam( "reset_calibration", asynParamInt32, &idxResetCalibration);
setIntegerParam( idxResetCalibration, 1 );
createParam( "Cavity_present", asynParamInt32, &idxCavityPresent);
setIntegerParam( idxCavityPresent, 0 );
createParam( "disable_calibration", asynParamInt32, &idxDisableCalibration);
setIntegerParam( idxDisableCalibration, 1);
createParam( "nfs_status", asynParamInt32);
// This PV allow to enable-disable the coupling compensation, using caput command
createParam( "enable_compensation", asynParamInt32, &idxEnableCompensation);
setIntegerParam( idxEnableCompensation, 0 );
createParam( "ntp_status", asynParamInt32 );
}
In addition to this, the driver code contains other functions such as postWriteFromPv(), preReadToPv(), postReadToPv()... used to execute diferrent conditions depending on the PVs
flags.
Do you need any other part of the code?
CAUTION: This email originated from outside of the organization.
Do not click links or open attachments unless you recognize the sender and know the content is safe.
Hi Adrian,
2022/07/06 10:46:59.429 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_RstSw
SL-SCL-CM3:DIA-BPM-3:ResetSoftStat devAsynInt32::initCommon drvUserCreate
This error is not shown for all the PVs and not always for the same PVs. For example, the first compilation shows error for PV1, PV2 and PV3, and the second compilation (immediately) shows error for PV2, PV4 and PV5.
Summing up, it is almost impossible to compile with 0 errors.
First, let me clarify. Those are not compile errors, they are errors at run time, almost certainly during iocInit when the record is being initialized.
This sounds like a race condition where not all parameters have been created before iocInit is called.
Your driver should be creating all of the parameters in the constructor, which will run in the main thread of the startup script. It is OK if createParam() is called in another function that is called from the constructor, but if it
is done in another thread then the constructor must wait for that thread to complete.
It would probably be helpful if you shared your driver code so we could look for the problem.
Mark
Hello,
I am developing an epics driver using epics-3.15.5 and asyn-4-33. The driver works correctly but, sometimes (aprox 90% of the time), returns an error when the procces variables (PV) are initialized:
2022/07/06 10:46:59.429 asynPortDriver:drvUserCreate: addr=0, cannot find parameter Ctrl_RstSw
SL-SCL-CM3:DIA-BPM-3:ResetSoftStat devAsynInt32::initCommon drvUserCreate
This error is not shown for all the PVs and not always for the same PVs. For example, the first compilation shows error for PV1, PV2 and PV3, and the second compilation (immediately) shows error for PV2, PV4 and PV5. Summing up, it is almost impossible to
compile with 0 errors.
These errors just affect to PV readbacks, which never change its values, although the value can be read correctly in the memory register corresponding to the modified PV.
The error could be related with the asynPortDriver class so, createParam function from asynPortDriver.cpp it is working correctly, creating the param list with all PVs (it has been checked using a for loop after each createParam invocation):
Last createParam invocation to add mrf_time PV
PUSH = mrf_time
VALS[0] = Ctrl_RstSw
VALS[1] = Ctrl_PosMesEna
VALS[2] = Ctrl_Alarm
VALS[3] = Ctrl_Acqst
VALS[4] = Ctrl_UserBufDump
VALS[5] = Ctrl_SelfClbEna
VALS[6] = Ctrl_CableClbEna
VALS[7] = Ctrl_cnf_rdy
VALS[8] = Ctrl_bpm_rdy
VALS[9] = Ctrl_alarm_x
VALS[10] = Ctrl_alarm_y
VALS[11] = Ctrl_alarm_i
VALS[12] = Ctrl_alarm_p
VALS[13] = Ctrl_alarm_x_ack
VALS[14] = Ctrl_alarm_y_ack
VALS[15] = Ctrl_alarm_i_ack
VALS[16] = Ctrl_alarm_p_ack
VALS[17] = Ctrl_get_idle
VALS[18] = Ctrl_BpmState
VALS[19] = overage_adc_top
VALS[20] = overage_adc_bottom
VALS[21] = overage_adc_right
VALS[22] = overage_adc_left
VALS[23] = calibration_msg
VALS[24] = reset_calibration
VALS[25] = Cavity_present
VALS[26] = disable_calibration
VALS[27] = nfs_status
VALS[28] = enable_compensation
VALS[29] = ntp_status
VALS[30] = ctl_pps_utc_sw
VALS[31] = syncTimeMode
VALS[32] = mrf_time
VALS.SIZE() = 33
The problem comes when drvUserCreate() function is invocated and check all the PVs included in the param list.
/** Called by asynManager to pass a pasynUser structure and drvInfo string to the driver;
* Assigns pasynUser->reason based on the value of the drvInfo string.
* This base class implementation looks up the drvInfo string in the parameter list.
* \param[in] pasynUser pasynUser structure that driver will modify
* \param[in] drvInfo String containing information about what driver function is being referenced
* \param[out] pptypeName Location in which driver can write information.
* \param[out] psize Location where driver can write information about size of pptypeName */
asynStatus asynPortDriver::drvUserCreate(asynUser *pasynUser,
const char *drvInfo,
const char **pptypeName, size_t *psize)
{
static const char *functionName = "drvUserCreate";
asynStatus status;
int index;
int addr;
status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
status = this->findParam(addr, drvInfo, &index); // ¡¡¡ERROR!!!
if (status) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s: addr=%d, cannot find parameter %s\n",
driverName, functionName, addr, drvInfo);
return(status);
}
pasynUser->reason = index;
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"%s:%s: drvInfo=%s, index=%d\n",
driverName, functionName, drvInfo, index);
return(asynSuccess);
}
findParam() is not able to find all the PVs and the if statement is executed. I have print each index after the findParam() execution and the param list has not all the PVs, missing just the ones not found.
Thanks in advance, Adrián.
|