//DevMpf.cc /********************COPYRIGHT NOTIFICATION********************************** This software was developed under a United States Government license described on the COPYRIGHT_UniversityOfChicago file included as part of this distribution. ****************************************************************************/ /* Current Author: Marty Kraimer Original Author: Jim Kowalkowski (for Hideos) Date: 01JUL98 */ #include #include #include #include #include #include #include extern "C" { #include "dbDefs.h" #include "link.h" #include "dbAccess.h" #include "recSup.h" #include "dbScan.h" } #include "Message.h" #include "ConnectMessage.h" #include "DevMpf.h" // Timeout to wait for connect reply message to come back (seconds) #define CONNECT_TIMEOUT 2 int DevMpfDebug = 0; static void callDeviceSupport(CALLBACK* cback); DevMpf::DevMpf(dbCommon* pr, link* pl,bool iointvalid) : ioscanpvt(0), iointValid(iointvalid), status(0), precord(pr), plink(pl), userParm(0), pMessageClient(0), connectState(connectNo), replyMessage(0), pCallbackRetry(0) { char name[40]; int i; if(plink->type!=VME_IO) { epicsPrintf("%s INP is not a vme link\n",precord->name); precord->pact = true; return(this); } pMessageClient = new MessageClient(DevMpf::messageClientCallback, (void *)precord); vmeio *pvmeio=(vmeio*)&(plink->value); // first field of parm is always the server name for(i=0; pvmeio->parm[i] && pvmeio->parm[i]!=',' && pvmeio->parm[i]!=' '; i++) name[i]=pvmeio->parm[i]; if(pvmeio->parm[i]) userParm = &pvmeio->parm[i+1]; name[i]='\0'; callbackSetCallback(callDeviceSupport,&cb); callbackSetPriority(precord->prio,&cb); callbackSetUser(precord,&cb); if(iointvalid) scanIoInit(&ioscanpvt); precord->dpvt=this; connectWait = semBCreate(SEM_Q_FIFO, SEM_EMPTY); status = pMessageClient->bind(name,pvmeio->card); if(status) { epicsPrintf("MPF::bind error. server %s Record %s\n", name,precord->name); precord->pact = true; return(this); } status = semTake(connectWait, CONNECT_TIMEOUT*sysClkRateGet()); if (status == ERROR) epicsPrintf("%s DevMpf::DevMpf connect timeout\n",precord->name); return(this); } long DevMpf::linconv(void* v,int pass) { dbCommon* precord=(dbCommon*)v; DevMpf* pdevMpf=(DevMpf*)precord->dpvt; if(pdevMpf==0) return(0); pdevMpf->convert(precord,pass); return(0); } void DevMpf::connectIO(dbCommon*,Message *message) { delete message; if(connectState==connectYes) return; callbackRequest(&cb); } void DevMpf::receiveReply(dbCommon *precord,Message *message) { printf("%s DevMpf::receiveReply called\n",precord->name); delete message; } void DevMpf::outOfBandIO(dbCommon *precord,Message *message) { printf("%s DevMpf::outOfBandIO called\n",precord->name); delete message; } long DevMpf::convert(dbCommon*,int) { return(0); } int DevMpf::send(Message *pmessage) { return(send(pmessage,replyTypeNone)); } int DevMpf::sendReply(Message *pmessage) { return(send(pmessage,replyTypeCompleteIO)); } int DevMpf::send(Message *pmessage,replyType type) { pmessage->setClientType((int32)type); int status = pMessageClient->send(pmessage); if(status==0) { if(type==replyTypeCompleteIO) precord->pact = TRUE; } else { delete pmessage; recGblSetSevr(precord,COMM_ALARM,INVALID_ALARM); } return(status); } long DevMpf::ioint(int , dbCommon* pcommon,IOSCANPVT* iopvt) { DevMpf* pdevMpf=(DevMpf*)pcommon->dpvt; if(!pdevMpf->iointValid) return(0); if(pdevMpf==0) return(0); *iopvt=pdevMpf->ioscanpvt; return(0); } long DevMpf::read_write(void* v) { dbCommon* pcommon = (dbCommon*)v; DevMpf* pdevMpf=(DevMpf*)pcommon->dpvt; if(pdevMpf==0 || pdevMpf->connectState!=connectYes) { if(pdevMpf->connectState==connectQueueFull) pdevMpf->connectState = connectYes; recGblSetSevr(pcommon,COMM_ALARM,INVALID_ALARM); if(pdevMpf->replyMessage) { delete pdevMpf->replyMessage; pdevMpf->replyMessage = 0; } return(MPF_NoConvert); } if(pcommon->pact==TRUE && pdevMpf->replyMessage==0) { if(DevMpfDebug) epicsPrintf("%s PACT true and no reply message\n"); recGblSetSevr(pcommon,COMM_ALARM,INVALID_ALARM); return(MPF_NoConvert); } long rc = 0; if(pdevMpf->replyMessage!=0) { rc=pdevMpf->completeIO(pcommon,pdevMpf->replyMessage); pdevMpf->replyMessage=0; // allow next message to be handled } else { rc=pdevMpf->startIO(pcommon); } return rc; } typedef long (*processCall)(dbCommon *); static void callDeviceSupport(CALLBACK* cback) { dbCommon* pc; void *dummy; callbackGetUser(dummy,cback); pc = (dbCommon *)dummy; rset *prset=(struct rset *)(pc->rset); processCall pcall = (processCall)(prset->process); /* process the record */ dbScanLock(pc); (*pcall)(pc); dbScanUnlock(pc); } void DevMpf::callbackAgain(void *pvt) { CallbackRetry *pCallbackRetry = (CallbackRetry *)pvt; pCallbackRetry->pDevMpf->messageClientCallback( pCallbackRetry->message,pCallbackRetry->clientPvt); } void DevMpf::messageClientCallback(Message *message,void *clientPvt) { dbCommon *pcommon = (dbCommon *)clientPvt; DevMpf *pdevMpf = (DevMpf *)pcommon->dpvt; if(message->getType()==messageTypeConnect) { ConnectMessage *pConnectMessage = (ConnectMessage *)message; pdevMpf->connectState = pConnectMessage->status; if (pdevMpf->connectState == connectYes) semGive(pdevMpf->connectWait); } if(!interruptAccept) { if(!pdevMpf->pCallbackRetry) { pdevMpf->pCallbackRetry = (CallbackRetry *)calloc(1,sizeof(CallbackRetry)); pdevMpf->pCallbackRetry->wdId = new WatchDog; } CallbackRetry *pCallbackRetry = pdevMpf->pCallbackRetry; pCallbackRetry->pDevMpf = pdevMpf; pCallbackRetry->message = message; pCallbackRetry->clientPvt = clientPvt; pCallbackRetry->wdId->start( 1,callbackAgain,(void *)pCallbackRetry); return; } dbScanLock(pcommon); if(message->getType()==messageTypeConnect) { ConnectMessage *pConnectMessage = (ConnectMessage *)message; pdevMpf->connectState = pConnectMessage->status; pdevMpf->connectIO(pcommon,message); } else if(message->getType()==messageTypeOutOfBand) { pdevMpf->outOfBandIO(pcommon,message); } else { replyType type = (replyType)message->getClientType(); switch(type) { case replyTypeNone: pdevMpf->outOfBandIO(pcommon,message); break; case replyTypeCompleteIO: if(pdevMpf->replyMessage) { epicsPrintf("%s DevMpf new message before previous processed\n", pcommon->name); } else { pdevMpf->replyMessage = message; callbackRequest(&pdevMpf->cb); } break; case replyTypeReceiveReply: pdevMpf->receiveReply(pcommon,message); break; default: epicsPrintf("%s DevMpf illegal replyType\n"); } } dbScanUnlock(pcommon); }