示例#1
0
static void dbCaTask(void *arg)
{
    taskwdInsert(0, NULL, NULL);
    SEVCHK(ca_context_create(ca_enable_preemptive_callback),
        "dbCaTask calling ca_context_create");
    dbCaClientContext = ca_current_context ();
    SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
        "ca_add_exception_event");
    epicsEventSignal(startStopEvent);

    /* channel access event loop */
    while (TRUE){
        do {
            epicsEventMustWait(workListEvent);
        } while (dbCaCtl == ctlPause);
        while (TRUE) { /* process all requests in workList*/
            caLink *pca;
            short  link_action;
            int    status;

            epicsMutexMustLock(workListLock);
            if (!(pca = (caLink *)ellGet(&workList))){  /* Take off list head */
                epicsMutexUnlock(workListLock);
                if (dbCaCtl == ctlExit) goto shutdown;
                break; /* workList is empty */
            }
            link_action = pca->link_action;
            pca->link_action = 0;
            if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
            epicsMutexUnlock(workListLock);         /* Give back immediately */
            if (link_action & CA_CLEAR_CHANNEL) {   /* This must be first */
                dbCaLinkFree(pca);
                /* No alarm is raised. Since link is changing so what? */
                continue; /* No other link_action makes sense */
            }
            if (link_action & CA_CONNECT) {
                status = ca_create_channel(
                      pca->pvname,connectionCallback,(void *)pca,
                      CA_PRIORITY_DB_LINKS, &(pca->chid));
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_create_channel %s\n",
                        ca_message(status));
                    printLinks(pca);
                    continue;
                }
                dbca_chan_count++;
                status = ca_replace_access_rights_event(pca->chid,
                    accessRightsCallback);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask replace_access_rights_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                continue; /*Other options must wait until connect*/
            }
            if (ca_state(pca->chid) != cs_conn) continue;
            if (link_action & CA_WRITE_NATIVE) {
                assert(pca->pputNative);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        pca->dbrType, pca->nelements,
                        pca->chid, pca->pputNative,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutNative = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            if (link_action & CA_WRITE_STRING) {
                assert(pca->pputString);
                if (pca->putType == CA_PUT) {
                    status = ca_array_put(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString);
                } else if (pca->putType==CA_PUT_CALLBACK) {
                    status = ca_array_put_callback(
                        DBR_STRING, 1,
                        pca->chid, pca->pputString,
                        putCallback, pca);
                } else {
                    status = ECA_PUTFAIL;
                }
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_array_put %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
                epicsMutexMustLock(pca->lock);
                if (status == ECA_NORMAL) pca->newOutString = FALSE;
                epicsMutexUnlock(pca->lock);
            }
            /*CA_GET_ATTRIBUTES before CA_MONITOR so that attributes available
             * before the first monitor callback                              */
            if (link_action & CA_GET_ATTRIBUTES) {
                status = ca_get_callback(DBR_CTRL_DOUBLE,
                    pca->chid, getAttribEventCallback, pca);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_get_callback %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_NATIVE) {
                size_t element_size;
    
                element_size = dbr_value_size[ca_field_type(pca->chid)];
                epicsMutexMustLock(pca->lock);
                pca->pgetNative = dbCalloc(pca->nelements, element_size);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(
                    ca_field_type(pca->chid)+DBR_TIME_STRING,
                    ca_element_count(pca->chid),
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
            if (link_action & CA_MONITOR_STRING) {
                epicsMutexMustLock(pca->lock);
                pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
                epicsMutexUnlock(pca->lock);
                status = ca_add_array_event(DBR_TIME_STRING, 1,
                    pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
                if (status != ECA_NORMAL) {
                    errlogPrintf("dbCaTask ca_add_array_event %s\n",
                        ca_message(status));
                    printLinks(pca);
                }
            }
        }
        SEVCHK(ca_flush_io(), "dbCaTask");
    }
shutdown:
    taskwdRemove(0);
    if (dbca_chan_count == 0)
        ca_context_destroy();
    else
        fprintf(stderr, "dbCa: chan_count = %d at shutdown\n", dbca_chan_count);
    epicsEventSignal(startStopEvent);
}
void popupPvInfo(DisplayInfo *displayInfo)
{
    DlElement *pE;
    Record **records;
    chid chId;
    int i, status;
    Record *pR;
    Channel *pCh;
    char descName[MAX_TOKEN_LENGTH];
    char *pDot;
    double connTimeout;

#if DEBUG_PVINFO
    XUngrabPointer(display,CurrentTime);
#endif

  /* Check if another call is in progress */
    if(pvInfo) {
	medmPostMsg(1,"popupPvInfo: "
	  "Another PV Info request is already in progress\n"
	  "  It is probably having problems\n"
	  "  Wait for it to finish\n");
	return;
    }

  /* Create the dialog box if it has not been created */
    if(!pvInfoS) createPvInfoDlg();

  /* Get the records */
    records = getPvInfoFromDisplay(displayInfo, &nPvInfoPvs, &pE);
    if(!records) return;
    pvInfoElement = pE;

  /* Allocate space */
    pvInfo = (PvInfo *)calloc(nPvInfoPvs, sizeof(PvInfo));
    if(!pvInfo) {
	medmPostMsg(1,"popupPvInfo: Memory allocation error\n");
	if(records) free(records);
	if(pvInfoS && XtIsManaged(pvInfoS)) return;
    }

  /* Loop over the records, initialize, and initiate search for DESC */
    for(i=0; i < nPvInfoPvs; i++) {
      /* Initialize */
	pvInfo[i].pvChid = NULL;
	pvInfo[i].pvOk = False;
	pvInfo[i].timeOk = False;
	pvInfo[i].descChid = NULL;
	pvInfo[i].descOk = False;
	strcpy(pvInfo[i].descVal, NOT_AVAILABLE);
#if defined(DBR_CLASS_NAME) && DO_RTYP
	pvInfo[i].rtypOk = False;
	strcpy(pvInfo[i].rtypVal, NOT_AVAILABLE);
#endif

      /* Check for a valid record */
	if(records[i]) {
	    pR = pvInfo[i].record = records[i];
	    pCh = getChannelFromRecord(pR);
	    if(!pCh) continue;
	    if(!pCh->chid) continue;
	    chId = pvInfo[i].pvChid = pCh->chid;
	} else continue;
	pvInfo[i].pvOk = True;

      /* Don't try the others unless the PV is connected */
	if(ca_state(chId) != cs_conn || !ca_read_access(chId))
	  continue;

      /* Construct the DESC name */
	strcpy(descName,ca_name(chId));
	pDot = strchr(descName,'.');
	if(pDot) {
	  /* Assume it is a name with a field and replace the field
	   * with DESC */
	    strcpy(pDot,".DESC");
	} else {
	  /* Append .DESC */
	    strcat(descName,".DESC");
	}
      /* Search for the DESC */
	status = ca_search(descName, &pvInfo[i].descChid);
	if(status == ECA_NORMAL) {
	    pvInfo[i].descOk = True;
	} else {
	    medmPostMsg(1,"popupPvInfo: DESC: ca_search for %s: %s\n",
	      descName, ca_message(status));
	}
    }

  /* Free the records, they are now stored in pvInfo */
    if(records) free(records);

  /* Wait for the searches (Timeouts should be uncommon) */
    status=ca_pend_io(CA_PEND_IO_TIME);
    if(status != ECA_NORMAL) {
	medmPostMsg(1,"popupPvInfo: Waited %g seconds.  "
	  "Did not find the DESC information (%s).\n",
	  CA_PEND_IO_TIME, descName);
    }

  /* Loop over the records and do the gets */
    nPvInfoCbs = 0;
    for(i=0; i < nPvInfoPvs; i++) {
	if(!pvInfo[i].pvOk) continue;

      /* Don't try the others unless the PV is connected */
	chId = pvInfo[i].pvChid;
	if(ca_state(chId) != cs_conn || !ca_read_access(chId))
	  continue;

      /* Get the DESC */
	if(ca_state(pvInfo[i].descChid) == cs_conn &&
	  ca_read_access(pvInfo[i].descChid)) {
	  /* Do the get */
	    status = ca_get_callback(DBR_STRING, pvInfo[i].descChid,
	      pvInfoDescGetCb, &pvInfo[i]);
	    if(status == ECA_NORMAL) {
		nPvInfoCbs++;
	    } else {
		pvInfo[i].descOk = False;
		medmPostMsg(1,"pvInfoConnectCb: DESC: ca_array_get_callback"
		  " for %s: %s\n",
		  ca_name(pvInfo[i].descChid), ca_message(status));
	    }
	} else {
	    pvInfo[i].descOk = False;
	}

      /* Get the time value as a string */
	status = ca_get_callback(DBR_TIME_STRING, chId, pvInfoTimeGetCb,
	  &pvInfo[i]);
	if(status == ECA_NORMAL) {
	    nPvInfoCbs++;
	} else {
	    medmPostMsg(1,"popupPvInfo: STAMP: ca_get_callback for %s: %s\n",
	      ca_name(chId), ca_message(status));
	}

#if defined(DBR_CLASS_NAME) && DO_RTYP
      /* Get the RTYP */
	status = ca_get_callback(DBR_CLASS_NAME, chId, pvInfoRtypGetCb,
	  &pvInfo[i]);
	if(status == ECA_NORMAL) {
	    nPvInfoCbs++;
	} else {
	    medmPostMsg(1,"popupPvInfo: RTYP: ca_get_callback for %s: %s\n",
	      ca_name(chId), ca_message(status));
	}
#endif
    }

  /* Add a timeout and poll if there are callbacks
   *   The timeout is a safety net and should never be called
   *   All callbacks should come back inside the EPICS_CA_CONN_TMO
   *   Wait for 2 times this */
    if(nPvInfoCbs) {
	ca_poll();     /* May not be really necessary here */
	status = envGetDoubleConfigParam(&EPICS_CA_CONN_TMO, &connTimeout);
	if (status == 0) pvInfoTime = (unsigned long)(2000.*connTimeout+.5);
	else pvInfoTime = PVINFO_TIMEOUT;
	pvInfoTimeoutId = XtAppAddTimeOut(appContext, pvInfoTime,
	  pvInfoTimeout, NULL);
	pvInfoTimerOn = True;
    } else {
	pvInfoWriteInfo();
    }

#if DEBUG_PVINFO
    print("popupPvInfo: nPvInfoCbs=%d timeout=%ld\n",
      nPvInfoCbs, nPvInfoCbs?pvInfoTime:0L);
#endif
}