Example #1
0
static void accessRightsCallback(struct access_rights_handler_args arg)
{
    caLink *pca = (caLink *)ca_puser(arg.chid);
    struct link	*plink;
    struct pv_link *ppv_link;
    dbCommon *precord;

    assert(pca);
    if (ca_state(pca->chid) != cs_conn)
        return; /* connectionCallback will handle */
    epicsMutexMustLock(pca->lock);
    plink = pca->plink;
    if (!plink) goto done;
    pca->hasReadAccess = ca_read_access(arg.chid);
    pca->hasWriteAccess = ca_write_access(arg.chid);
    if (pca->hasReadAccess && pca->hasWriteAccess) goto done;
    ppv_link = &plink->value.pv_link;
    precord = ppv_link->precord;
    if (precord &&
        ((ppv_link->pvlMask & pvlOptCP) ||
         ((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
        scanOnce(precord);
done:
    epicsMutexUnlock(pca->lock);
}
Example #2
0
static void connectionCallback(struct connection_handler_args args)
{
    CHNODE *pNode = (CHNODE *)ca_puser(args.chid);
	AttachChannelAccess	*pacacc = (AttachChannelAccess *)pNode->acacc;
    //printf("PV(%s) state(%d)\n", ca_name(args.chid),ca_state(args.chid));
    if ( args.op == CA_OP_CONN_UP ) 
	{
        //int dbrType;
        //pNode->nElems  = ca_element_count(pNode->ch_id);
        //pNode->dbfType = ca_field_type(pNode->ch_id);
        pNode->onceConnected = 1;
        pNode->status = ECA_CONN;
		pacacc->ConnectionStatusObj(pNode->objname, ECA_CONN );
		//++leesi
		//ca_create_subscription (pNode->dbrequest, 0, pNode->ch_id, DBE_VALUE|DBE_ALARM, eventCallback, (void*)pNode, NULL);
		ca_create_subscription (pNode->dbrequest, 0, pNode->ch_id, DBE_VALUE|DBE_ALARM, eventCallback, (void*)pNode, &(pNode->ev_id));
		//ca_clear_event(pNode->ev_id);
    }
    else if ( args.op == CA_OP_CONN_DOWN ) {
        pNode->status = ECA_DISCONN;
		pacacc->ConnectionStatusObj(pNode->objname, ECA_DISCONN );
		pacacc->UpdateObj(pNode->objname, -1,0,0);
    }
	else
	{
		qDebug("NO PV - pv(%s)", pNode->pvname.toStdString().c_str());
	}
};
Example #3
0
static void eventCallback(struct event_handler_args args)
{
    CHNODE *pNode = (CHNODE *)ca_puser(args.chid);
	AttachChannelAccess	*pacacc = (AttachChannelAccess *)pNode->acacc;
    pNode->dbfType = ca_field_type(pNode->ch_id);

	QString pvname = ca_name(args.chid);
	QString strvalue;
	unsigned int chindex = pNode->chindex;

    if( args.status != ECA_NORMAL ) 
	{
		printChidInfo(args.chid,"eventCallback");
    } 
	else 
	{
		QString objName = pNode->objname;
		if(objName.contains("CATableList", Qt::CaseInsensitive) == true)
		{
			struct dbr_time_string *pdata = (struct dbr_time_string*)args.dbr;
			QTableWidgetItem *pItem = pNode->pItem;
			strvalue = QString(pdata->value);
			pItem->setText(strvalue);

			//CATableList *pTable = (CATableList*)pItem->tableWidget();
			//pItem->setStatusTip(QString("PVname : ").append(pvname).append(QString(", Value: ")).append(strvalue));
			//pTable->TableUpdate();
			return;
		};

		//++leesi
		switch(pNode->dbrequest)
		{
			//case DBR_GR_CHAR:
			case DBR_TIME_STRING:
				{
					struct dbr_time_string *pdata = (struct dbr_time_string*)args.dbr;
					strvalue = QString(pdata->value);
					pacacc->UpdateObj(pNode->objname, strvalue, pdata->severity);
				}
				break;
			case DBR_GR_DOUBLE:
			default:
				{
					struct dbr_gr_double* pdata = (struct dbr_gr_double*)args.dbr;
					if(objName.contains("CAPopUp", Qt::CaseInsensitive) == true)
						qDebug("PVName: %s, Value:%f", pvname.toStdString().c_str(), pdata->value);
#if 0
					//for test,,,
					static int count = 0;
					qDebug("CAMon Value:%f, count(%d)",pdata->value, count++);
#endif
					pacacc->UpdateObj(pNode->objname, pdata->value, pdata->severity, pdata->precision);
				}
				break;
		};
    };
};
Example #4
0
static void exceptionCallback(struct exception_handler_args args)
{
    chid	chid = args.chid;
    CHNODE *pNode = (CHNODE *)ca_puser(args.chid);
	if(pNode == NULL ) return;
    if(chid) printChidInfo(chid,"exceptionCallback");
    //long	stat = args.stat; /* Channel access status code*/
    //const char  *channel;
    //static char *noname = "unknown";
    //channel = (chid ? ca_name(chid) : noname);
	//qDebug("No PV - pv(%s)", pNode->pvname.toStdString().c_str());
};
Example #5
0
static void stateHandler (struct connection_handler_args chargs) {
	/* callback */
	pvInfo *info = ca_puser(chargs.chid);

	if (info->connectprefix) {
		/* queue event to handle the Tcl callback */
		connectionEvent * cev = ckalloc(sizeof(connectionEvent));
		
		cev->ev.proc = stateHandlerInvoke;
		cev->info = info;
		cev->op = chargs.op;
		Tcl_ThreadQueueEvent(info->thrid, (Tcl_Event*)cev, TCL_QUEUE_TAIL);
		Tcl_ThreadAlert(info->thrid);
	}
}
Example #6
0
static void connection_handler ( struct connection_handler_args args )
{
    pv *ppv = ( pv * ) ca_puser ( args.chid );
    if ( args.op == CA_OP_CONN_UP ) {
        nConn++;
        if (!ppv->onceConnected) {
            ppv->onceConnected = 1;
                                /* Set up pv structure */
                                /* ------------------- */

                                /* Get natural type and array count */
            ppv->dbfType = ca_field_type(ppv->chid);
            ppv->dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */
            if (dbr_type_is_ENUM(ppv->dbrType))                /* Enums honour -n option */
            {
                if (enumAsNr) ppv->dbrType = DBR_TIME_INT;
                else          ppv->dbrType = DBR_TIME_STRING;
            }
            else if (floatAsString &&
                     (dbr_type_is_FLOAT(ppv->dbrType) || dbr_type_is_DOUBLE(ppv->dbrType)))
            {
                ppv->dbrType = DBR_TIME_STRING;
            }
                                /* Set request count */
            ppv->nElems   = ca_element_count(ppv->chid);
            ppv->reqElems = reqElems > ppv->nElems ? ppv->nElems : reqElems;

                                /* Issue CA request */
                                /* ---------------- */
            /* install monitor once with first connect */
            ppv->status = ca_create_subscription(ppv->dbrType,
                                                ppv->reqElems,
                                                ppv->chid,
                                                eventMask,
                                                event_handler,
                                                (void*)ppv,
                                                NULL);
        }
    }
    else if ( args.op == CA_OP_CONN_DOWN ) {
        nConn--;
        ppv->status = ECA_DISCONN;
        print_time_val_sts(ppv, reqElems);
    }
}
static void medmReplaceAccessRightsEventCb(
  struct access_rights_handler_args args)
{
    Channel *pCh = (Channel *) ca_puser(args.chid);
    Boolean readAccessChangedToRead = False;

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(!pCh || !pCh->pr) {
	medmPostMsg(0,"medmReplaceAccessRightsEvent: "
	  "Invalid channel information\n");
	return;
    }

  /* Determine if the rights are changing from no read to read */
    if(!pCh->pr->readAccess && ca_read_access(pCh->chid)) {
	readAccessChangedToRead = True;
    }
  /* Change the access rights in the Record */
    pCh->pr->readAccess = ca_read_access(pCh->chid);
    pCh->pr->writeAccess = ca_write_access(pCh->chid);
    if(pCh->pr->updateValueCb)
      pCh->pr->updateValueCb((XtPointer)pCh->pr);

  /* Do a get as in medmConnectEventCb.  The get will cause the
     graphical info callback to be called.  This is necessary for some
     objects if the access rights are changing from no read to
     read. */
    if(pCh->pr->connected && pCh->previouslyConnected
      && readAccessChangedToRead) {
	int status = ca_array_get_callback(
	  dbf_type_to_DBR_CTRL(ca_field_type(args.chid)),
	  1, args.chid, medmUpdateGraphicalInfoCb, NULL);
	if(status != ECA_NORMAL) {
	    medmPostMsg(0,"medmReplaceAccessRightsEventCb: %s\n",
	      ca_message(status));
	}
    }
}
Example #8
0
/*
 * get the access rights:
 * note that even though there is separate read and write access, the rights
 * as of R3.14.1 are actually [ NONE, READ, and READ/WRITE]. If this changes,
 * things could get interesting.
 */
static void
getAccessRights( struct access_rights_handler_args args)
{
	Channel *chan = ca_puser(args.chid);
	Connector *conp;
	int readAccess, writeAccess;

	readAccess = ca_read_access(chan->chan_id);
	writeAccess = ca_write_access(chan->chan_id);
	chan->writeAccess = writeAccess?1:0;
	chan->readAccess = readAccess?1:0;

	DEBUGP printf("Channel %s read %d write %d\n", chan->chan_name, readAccess, writeAccess);
	/*
	 * user now allowed to write to this PV
	 */
	epicsMutexLock( processFlag);
	for( conp=chan->first_connector; conp; conp=conp->next_chan)
	    if( conp->newAccess)
		(*conp->newAccess)(conp);
	epicsMutexUnlock( processFlag);
	
}
// Channel Access callback
// Should be invoked with the control info 'get' data,
// requested in the connection handler.
void ProcessVariable::control_callback(struct event_handler_args arg)
{
    ProcessVariable *me = (ProcessVariable *) ca_puser(arg.chid);
    LOG_ASSERT(me != 0);
    if (arg.status != ECA_NORMAL)
    {
        LOG_MSG("ProcessVariable(%s) control_callback failed: %s\n",
                me->getName().c_str(),  ca_message(arg.status));
        return;
    }
    try
    {
        {
            Guard guard(__FILE__, __LINE__, *me);
            if (me->state != GETTING_INFO  ||  me->id == 0)
            {
                LOG_MSG("ProcessVariable(%s) received control_callback while %s, id=0x%lX\n",
                        me->getName().c_str(), me->getStateStr(guard), (unsigned long) me->id);
                return;
            }
            // For native type DBR_xx, use DBR_TIME_xx, and native count:
            me->dbr_type  = ca_field_type(me->id) + DBR_TIME_STRING;
            me->dbr_count = ca_element_count(me->id);
            me->state     = CONNECTED;
            // Setup the PV info.
            if (!me->setup_ctrl_info(guard, arg.type, arg.dbr))
                return;
        }
        // Notify listeners that PV is now fully connected.
        me->firePvConnected();
    }
    catch (GenericException &e)
    {
        LOG_MSG("ProcessVariable(%s) control_callback exception:\n%s\n",
                me->getName().c_str(), e.what());
    }
}
Example #10
0
/*
 * callback from connection handler: change the state of the channel valid
 * flag depending on the connection being up or down.
 * ASSUMPTIONS: chan_id is valid.
 */
static void
connect_callback(struct connection_handler_args args)
{
    Connector *conp;
    
    Channel *chan = ca_puser( args.chid);
    int status;
    
    DEBUGP printf("connect callback %p\n", chan);
    switch( args.op)
    {
    case CA_OP_CONN_UP:
    	if( chan->initData == 1)
	{
		chan->maxelement = ca_element_count(chan->chan_id);
		chan->chan_type = ca_field_type(chan->chan_id);
		chan->initData = 0;
	}
	/*
	 * note that a dropped and recreated connection can cause a free and alloc. This
	 * is not always redundant, as software may have restarted with different sizes
	 * for the field!
	 */
	if( chan->createData == 1 )
	{
		if( chan->dataval)
			free( chan->dataval);
		chan->dataval = calloc(dbr_size[chan->chan_type], chan->maxelement+1);
	}

	chan->readAccess = ca_read_access( chan->chan_id);
	chan->writeAccess = ca_write_access( chan->chan_id);
	status = ca_array_get_callback( dbf_type_to_DBR_CTRL(ca_field_type(chan->chan_id)), 1, chan->chan_id, getChanInfo, (void*)chan);
	SEVCHK(status, "connect_callback : ca_get_DBR_CTRL_event failed");
	status = ca_replace_access_rights_event( chan->chan_id, getAccessRights);
	SEVCHK(status, "connect_callback : ca_replace_access_rights_event failed");

	chan->valid = 1;
	chan->outstanding = 0;
	if( chan->monitor)
	{
	    chan->status = 100;	/* MAGIC: an absurd status */
	    status = ca_add_array_event(dbf_type_to_DBR_STS(chan->chan_type), chan->maxelement, chan->chan_id, monitorCallback, chan, 
		    		(double) 0.0, (double) 0.0, (double) 0.0, &(chan->eventId));
	    SEVCHK(status, "connect_callback : ca_add_event failed");
	    status = ca_flush_io();
	    SEVCHK(status, "connect_callback : ca_flush_io failed");
	}
	break;
	
    case CA_OP_CONN_DOWN:
	if( chan->valid && chan->eventId)
	    ca_clear_event(chan->eventId);
	chan->valid = 0;
	chan->status = 99;
	
	/*
	 * update the access rights and severity for all the connectors
	 */
	for(conp=chan->first_connector; conp ; conp=conp->next)
	{
	    if(conp->newAccess)
		(*conp->newAccess)(conp);
	    if( conp->newState)
	    	(*conp->newState)(conp);
	}
	
	break;
    default:
	break;
    }

    return;
}
static void medmUpdateChannelCb(struct event_handler_args args) {
    Channel *pCh = (Channel *)ca_puser(args.chid);
    Boolean statusChanged = False;
    Boolean severityChanged = False;
    Boolean zeroAndNoneZeroTransition = False;
    Record *pr;
    double value;
    int nBytes;
    int allocBytes;

#if DEBUG_CHANNEL_CB || DEBUG_LARGE_ARRAY
    const char *pvname=ca_name(args.chid);
    print("medmUpdateChannelCb: %s\n",pvname);
    if(args.status != ECA_NORMAL) {
	char buf[80];
	envGetConfigParam(&EPICS_CA_MAX_ARRAY_BYTES,80,buf);
	buf[79]='\0';
	print("EPICS_CA_MAX_ARRAY_BYTES: %s\n",buf);
    }
#endif

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
  /* Same as for updateGraphicalInfoCb */
  /* Don't need to check for read access, checking ECA_NORMAL is enough */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(args.status != ECA_NORMAL) {
	medmPostMsg(0,"medmUpdateChannelCb: Bad status [%d] for %s: %s\n",
	  args.status,
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown",
	  ca_message(args.status));
	return;
    }
    if(!args.dbr) {
	medmPostMsg(0,"medmUpdateChannelCb: Invalid data for [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmUpdateChannelCb: "
	  "Invalid channel information for [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(pCh->chid != args.chid) {
	medmPostMsg(0,"medmUpdateChannelCb: chid from args [%x] "
	  "does not match chid from channel [%x]\n"
	  "  [%s]\n",
	  args.chid,
	  pCh->chid,
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    pr = pCh->pr;

  /* Allocate space for the data */
    nBytes = dbr_size_n(args.type, args.count);
    if(!pCh->data) {
        /* Allocate maximum space for the variable array data */
        if(pr->currentCount == -2) {
            allocBytes=dbr_size_n(args.type, pr->elementCount);
        } else {
            allocBytes=nBytes;
        }
      /* No previous data, allocate */
	pCh->data = (dataBuf *)malloc(allocBytes);
	pCh->size = allocBytes;
	if(!pCh->data) {
	    medmPostMsg(1,"medmUpdateChannelCb: Memory allocation error [%s]\n",
	      ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	    return;
	}
    } else if(pCh->size < nBytes) {
      /* Previous data exists but is too small
       * Free it and allocate it again */
	free((char *)pCh->data);
	pCh->data = (dataBuf *)malloc(nBytes);
	pCh->size = nBytes;
	if(pCh->data == NULL) {
	    medmPostMsg(1,"medmUpdateChannelCb: Memory reallocation error"
	      " [%s]\n",
	      ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	    return;
	}
    }
    pr->currentCount=args.count;

#ifdef __USING_TIME_STAMP__
  /* Copy the returned time stamp to the Record */
    pr->time = ((dataBuf *)args.dbr)->s.stamp;
#endif


  /* Set the array pointer in the Record to point to the value member of the
   *   appropriate struct stored in the Channel
   * (The returned data is not stored there yet) */
    switch (ca_field_type(args.chid)) {
    case DBF_STRING:
	pr->array = (XtPointer)pCh->data->s.value;
	break;
    case DBF_ENUM:
	pr->array = (XtPointer)&(pCh->data->e.value);
	break;
    case DBF_CHAR:
	pr->array = (XtPointer)&(pCh->data->c.value);
	break;
    case DBF_INT:
	pr->array = (XtPointer)&(pCh->data->i.value);
	break;
    case DBF_LONG:
	pr->array = (XtPointer)&(pCh->data->l.value);
	break;
    case DBF_FLOAT:
	pr->array = (XtPointer)&(pCh->data->f.value);
	break;
    case DBF_DOUBLE:
	pr->array = (XtPointer)&(pCh->data->d.value);
	break;
    default:
	break;
    }

  /* For strings and arrays copy the returned data to the Channel
   * (The space is allocated but the data is not stored otherwise) */
    if(ca_field_type(args.chid) == DBF_STRING ||
      ca_element_count(args.chid) > 1) {
	memcpy((void *)pCh->data, args.dbr, nBytes);
    }

  /* Copy the value from the returned data to the Record */
    switch (ca_field_type(args.chid)) {
    case DBF_STRING:
	value = 0.0;
	break;
    case DBF_ENUM:
	value = (double)((dataBuf *)(args.dbr))->e.value;
	break;
    case DBF_CHAR:
	value = (double)((dataBuf *)(args.dbr))->c.value;
	break;
    case DBF_INT:
	value = (double)((dataBuf *)(args.dbr))->i.value;
	break;
    case DBF_LONG:
	value = (double)((dataBuf *)(args.dbr))->l.value;
	break;
    case DBF_FLOAT:
	value = (double)((dataBuf *)(args.dbr))->f.value;
	break;
    case DBF_DOUBLE:
	value = ((dataBuf *)(args.dbr))->d.value;
#if DEBUG_SLIDER
	if(value > 150.0 || value < -150.0) {
	    print("medmUpdateChannelCb: %g\n",value);
	}
#endif
	break;
    default:
	value = 0.0;
	break;
    }

  /* Mark zero to nonzero transition */
    if(((value == 0.0) && (pr->value != 0.0)) ||
      ((value != 0.0) && (pr->value == 0.0)))
      zeroAndNoneZeroTransition = True;

  /* Mark status changed */
    if(pr->status != ((dataBuf *)(args.dbr))->d.status) {
	pr->status = ((dataBuf *)(args.dbr))->d.status;
	statusChanged = True;
    }

  /* Mark severity changed */
    if(pr->severity != ((dataBuf *)(args.dbr))->d.severity) {
	pr->severity = ((dataBuf *)(args.dbr))->d.severity;
	severityChanged = True;
    }

  /* Set the new value into the record */
    pr->value = value;

#if DEBUG_ERASE
    print("medmUpdateChannelCb: [%x]%s %g\n",
      pr, pr->name, pr->value);
#endif

  /* Call the update value callback if there is a monitored change */
    if(pCh->pr->updateValueCb) {
	if(pr->monitorValueChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorStatusChanged && statusChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorSeverityChanged && severityChanged) {
	    pr->updateValueCb((XtPointer)pr);
	} else if(pr->monitorZeroAndNoneZeroTransition &&
	  zeroAndNoneZeroTransition) {
	    pr->updateValueCb((XtPointer)pr);
	}
    }
}
// Channel Access callback
void ProcessVariable::connection_handler(struct connection_handler_args arg)
{
    ProcessVariable *me = (ProcessVariable *) ca_puser(arg.chid);
    LOG_ASSERT(me != 0);
    try
    {
        if (arg.op == CA_OP_CONN_DOWN)
        {   // Connection is down
            {
                Guard guard(__FILE__, __LINE__, *me);
                me->state = DISCONNECTED;
            }
            me->firePvDisconnected();
            return;
        }
        {   // else: Connection is 'up'
            Guard guard(__FILE__, __LINE__, *me);
            if (me->id == 0)
            {
                LOG_MSG("ProcessVariable(%s) received "
                        "unexpected connection_handler\n",
                        me->getName().c_str());
                return;
            }
#           ifdef DEBUG_PV
            printf("ProcessVariable(%s) getting control info\n",
                   me->getName().c_str());
#           endif
            me->state = GETTING_INFO;
            // Get control information for this channel.
            // Bug in (at least older) CA: Works only for 1 element,
            // even for array channels.
            // We are in CAC callback, and managed to lock ourself,
            // so it should be OK to issue another CAC call.
            try
            {
                int status = ca_array_get_callback(
                    ca_field_type(me->id)+DBR_CTRL_STRING,
                    1 /* ca_element_count(me->ch_id) */,
                    me->id, control_callback, me);
                if (status != ECA_NORMAL)
                {
                    LOG_MSG("ProcessVariable('%s') connection_handler error %s\n",
                            me->getName().c_str(), ca_message (status));
                    return;
                }
            }
            catch (std::exception &e)
            {
                LOG_MSG("ProcessVariable::connection_handler(%s): %s\n",
                        me->getName().c_str(), e.what());
            }
            catch (...)
            {
                LOG_MSG("ProcessVariable::connection_handler(%s): "
                        "Unknown Exception\n", me->getName().c_str());
            } 
        }
        Guard ctx_guard(__FILE__, __LINE__, me->ctx);
        me->ctx.requestFlush(ctx_guard);
    }
    catch (GenericException &e)
    {
        LOG_MSG("ProcessVariable(%s) connection_handler exception:\n%s\n",
                me->getName().c_str(), e.what());
    }    
}
Example #13
0
static void connectionCallback(struct connection_handler_args arg)
{
    caLink *pca;
    short link_action = 0;
    struct link *plink;

    pca = ca_puser(arg.chid);
    assert(pca);
    epicsMutexMustLock(pca->lock);
    plink = pca->plink;
    if (!plink) goto done;
    pca->isConnected = (ca_state(arg.chid) == cs_conn);
    if (!pca->isConnected) {
        struct pv_link *ppv_link = &plink->value.pv_link;
        dbCommon *precord = ppv_link->precord;

        pca->nDisconnect++;
        if (precord &&
            ((ppv_link->pvlMask & pvlOptCP) ||
             ((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
            scanOnce(precord);
        goto done;
    }
    pca->hasReadAccess = ca_read_access(arg.chid);
    pca->hasWriteAccess = ca_write_access(arg.chid);

    if (pca->gotFirstConnection) {
        if (pca->nelements != ca_element_count(arg.chid) ||
            pca->dbrType != ca_field_type(arg.chid)) {
            /* BUG: We have no way to clear any old subscription with the
             *      originally chosen data type/size.  That will continue
             *      to send us data and will result in an assert() fail.
             */
            /* Let next dbCaGetLink and/or dbCaPutLink determine options */
            plink->value.pv_link.pvlMask &=
                ~(pvlOptInpNative | pvlOptInpString |
                  pvlOptOutNative | pvlOptOutString);

            pca->gotInNative  = 0;
            pca->gotOutNative = 0;
            pca->gotInString  = 0;
            pca->gotOutString = 0;
            free(pca->pgetNative); pca->pgetNative = 0;
            free(pca->pgetString); pca->pgetString = 0;
            free(pca->pputNative); pca->pputNative = 0;
            free(pca->pputString); pca->pputString = 0;
        }
    }
    pca->gotFirstConnection = TRUE;
    pca->nelements = ca_element_count(arg.chid);
    pca->dbrType = ca_field_type(arg.chid);
    if ((plink->value.pv_link.pvlMask & pvlOptInpNative) && !pca->pgetNative) {
        link_action |= CA_MONITOR_NATIVE;
    }
    if ((plink->value.pv_link.pvlMask & pvlOptInpString) && !pca->pgetString) {
        link_action |= CA_MONITOR_STRING;
    }
    if ((plink->value.pv_link.pvlMask & pvlOptOutNative) && pca->gotOutNative) {
        link_action |= CA_WRITE_NATIVE;
    }
    if ((plink->value.pv_link.pvlMask & pvlOptOutString) && pca->gotOutString) {
        link_action |= CA_WRITE_STRING;
    }
    pca->gotAttributes = 0;
    if (pca->dbrType != DBR_STRING) {
        link_action |= CA_GET_ATTRIBUTES;
    }
done:
    if (link_action) addAction(pca, link_action);
    epicsMutexUnlock(pca->lock);
}
Example #14
0
void eventCallback(struct event_handler_args eha)
{
	MyNode *pNode = (MyNode *)ca_puser(eha.chid);
	SessionSummary *pSummary = (SessionSummary*)pNode->mpsummary;

	if(eha.status!=ECA_NORMAL)
	{
		printChidInfo(eha.chid,"eventCallback");
	}
	else
	{
#if 0
		int updateshot = 0;
		if(pNode->prevshotnum == 0)
		{
			updateshot = currentshot-1;
		}
		else
		{
			updateshot = (currentshot - pNode->prevshotnum)-1;
			if( updateshot <= 0 )
				updateshot = currentshot-1;
		};

		for (int i = updateshot; i > 0;i--)
		{
			int summarystatus = ReadMDSData((currentshot-1)-i);
			printf("update:%d, status:%d\n",shotnum, summarystatus);
		}
#else
		//int summarystatus = pSummary->ReadMDSData(updateshot);
		//printf("updateshot:%d, status:%d\n",updateshot, summarystatus);
		struct dbr_time_long* pdata = (struct dbr_time_long*)eha.dbr;
		if(pSummary->GetAuto() == true && pdata->value == (long)1)
		{
			QString hostname = pSummary->GetHostname();
			if(hostname.compare("opi16")==0)
			{
				int updateshot = CACommand("ShotNum");
				qDebug("Update--MDSSHOT:%d",updateshot);
				pSummary->ReadMDSData(updateshot);
				CACommand("ResetShotSummary");
			}
			else
			{
				pSummary->Update();
			}
			// check...
			//unsigned int ccsshot=0;
			//unsigned int mdsshot=0;
			//int status = pSummary->GetUpdateShotNum(ccsshot, mdsshot);
			//qDebug("CCSSHOT:%d,MDSSHOT:%d",ccsshot,mdsshot);
			//pSummary->ResetCCSPShotN();
		}
		else
		{
			qDebug("Initialze-----");
			pSummary->SetAuto(true);
		};
#endif
	};
}
Example #15
0
/*
    Connection handler callback.
    This is called with CaObject out of context, it is recovered in:
    "args" -> "parent" -> "grandParent".
*/
void CaObjectPrivate::connectionHandler( struct connection_handler_args args ) {


    // Sanity check. The CaRef extracted from args.chid will be checked later, but can we even get to extracting the CaRef safley?
    if( args.chid == 0 )
    {
        printf( "CaObjectPrivate::connectionHandler() args.chid in connection_handler_args is zero" );
        return;
    }

    CaRef::accessLock();
    CaRef* ref = (CaRef*)(ca_puser( args.chid ));

    // Sanity check. Did ca_puser() extract the CaRef extracted from args.chid?
    if( ref == NULL )
    {
        printf( "CaObjectPrivate::connectionHandler() CaRef extracted from connection_handler_args is NULL" );
        CaRef::accessUnlock();
        return;
    }

    // Extract the connection (Returns zero if checks fail)
    caconnection::CaConnection* parent = (caconnection::CaConnection*)(ref->getRef( args.chid ));
    if( !parent )
    {
        CaRef::accessUnlock();
        return;
    }

    CaObject* grandParent = (CaObject*)parent->getParent();

    if( !parent->getChannelActivated() )
    {
        printf( "Late CA callback. CaObjectPrivate::connectionHandler() called while channel (CaConnection::caChannel) is not activated.\n" );
        if( grandParent->myRef )
        {
            printf( "Variable in CaRef in CaObject: %s\n", grandParent->myRef->getVariable().c_str() );
        }
        else
        {
            printf( "CaObject has no CaRef to check.\n");
        }
        printf( "Variable in CaRef in data in this callback: %s\n", ref->getVariable().c_str() );

        CaRef::accessUnlock();
        return;
    }
    CaRef::accessUnlock();

    switch( args.op ) {
        case CA_OP_CONN_UP :
            {
                CaObjectPrivate* grandParentPri = (CaObjectPrivate*)(grandParent->caPrivate);
                grandParentPri->caRecord.setDbrType( parent->getChannelType() );
            }
            parent->setChannelElementCount();
            parent->setLinkState( caconnection::LINK_UP );
            grandParent->signalCallback( CONNECTION_UP );
        break;
        case CA_OP_CONN_DOWN :
            parent->setLinkState( caconnection::LINK_DOWN );
            grandParent->signalCallback( CONNECTION_DOWN );
        break;
        default :
            parent->setLinkState( caconnection::LINK_UNKNOWN );
            grandParent->signalCallback( CONNECTION_UNKNOWN );
        break;
    }
}
// Channel Access callback
// Each subscription monitor or 'get' callback goes here:
void ProcessVariable::value_callback(struct event_handler_args arg)
{
    ProcessVariable *me = (ProcessVariable *) ca_puser(arg.chid);
    LOG_ASSERT(me != 0);
    // Check if there is a useful value at all.
    if (arg.status != ECA_NORMAL)
    {
        LOG_MSG("ProcessVariable(%s) value_callback failed: %s\n",
                me->getName().c_str(),  ca_message(arg.status));
        return;
    }
    const RawValue::Data *value = (const RawValue::Data *)arg.dbr;
    LOG_ASSERT(value != 0);
    // Catch records that never processed and give null times.
    if (value->stamp.secPastEpoch == 0)
    {
        nulltime_throttle.LOG_MSG("ProcessVariable::value_callback(%s) "
            "with invalid null timestamp\n", me->getName().c_str());
        return;
    }
    // Check the nanoseconds of each incoming value. Problems will arise later
    // unless they are normalized to less than one second.
    if (value->stamp.nsec >= 1000000000L)
    {
        epicsTimeStamp s = value->stamp;
        s.nsec = 0;
        epicsTime t = s;
        stdString txt;
        epicsTime2string(t, txt);
        nanosecond_throttle.LOG_MSG("ProcessVariable::value_callback(%s) "
            "with invalid secs/nsecs %zu, %zu: %s\n",
            me->getName().c_str(),
            (size_t) value->stamp.secPastEpoch,
            (size_t) value->stamp.nsec,
            txt.c_str());
        return;
    }
    try
    {
        {
            // Do we expect a value because of 'get' or subscription?
            Guard guard(__FILE__, __LINE__, *me);
            if (me->outstanding_gets > 0)
                --me->outstanding_gets;
            else if (me->isSubscribed(guard) == false)
            {
                LOG_MSG("ProcessVariable::value_callback(%s): not expected\n",
                        me->getName().c_str());
                return;
            }
#           ifdef CHECK_EVID
            if (me->ev_id)
            {
                void *user = peek_evid_userptr(me->ev_id);
                LOG_ASSERT(user == me);
            }
#           endif
            if (me->state != CONNECTED)
            {
                // After a disconnect, this can happen in the GETTING_INFO state:
                // The CAC lib already sends us new monitors after the re-connect,
                // while we wait for the ctrl-info get_callback to finish.
                if (me->state == GETTING_INFO) // ignore
                    return;
                LOG_MSG("ProcessVariable(%s) received value_callback while %s\n",
                        me->getName().c_str(), me->getStateStr(guard));
                return;
            }
        }
        // Finally, notify listeners of new value.
        me->firePvValue(value);
    }
    catch (GenericException &e)
    {
        LOG_MSG("ProcessVariable(%s) value_callback exception:\n%s\n",
                me->getName().c_str(), e.what());
    }
}
static void medmUpdateGraphicalInfoCb(struct event_handler_args args) {
    int nBytes;
    int i;
    Channel *pCh = (Channel *)ca_puser(args.chid);
    Record *pr;

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
  /* Same as for updateChannelCb */
  /* Don't need to check for read access, checking ECA_NORMAL is enough */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(args.status != ECA_NORMAL) return;
    if(!args.dbr) {
	medmPostMsg(0,"medmUpdateGraphicalInfoCb: Invalid data [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmUpdateGraphicalInfoCb: Invalid channel information [%s]\n",
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    if(pCh->chid != args.chid) {
	medmPostMsg(0,"medmUpdateGraphicalInfoCb: chid from args [%x] "
	  "does not match chid from channel [%x]\n"
	  "  [%s]\n",
	  args.chid,
	  pCh->chid,
	  ca_name(args.chid)?ca_name(args.chid):"Name Unknown");
	return;
    }
    pr = pCh->pr;

  /* Copy the information to the Channel struct */
    nBytes = dbr_size_n(args.type, args.count);
    memcpy((void *)&(pCh->info),args.dbr,nBytes);

  /* Handle hopr, lopr, and precision */
    switch (ca_field_type(args.chid)) {
    case DBF_STRING:
	pr->value = 0.0;
	pr->hopr = 0.0;
	pr->lopr = 0.0;
	pr->precision = 0;
	break;
    case DBF_ENUM:
	pr->value = (double) pCh->info.e.value;
	pr->hopr = (double) pCh->info.e.no_str - 1.0;
	pr->lopr = 0.0;
	pr->precision = 0;
	for (i = 0; i < pCh->info.e.no_str; i++) {
	    pr->stateStrings[i] = pCh->info.e.strs[i];
	}
	break;
    case DBF_CHAR:
	pr->value = (double) pCh->info.c.value;
	pr->hopr = (double) pCh->info.c.upper_disp_limit;
	pr->lopr = (double) pCh->info.c.lower_disp_limit;
	pr->precision = 0;
	break;
    case DBF_INT:
	pr->value = (double) pCh->info.i.value;
	pr->hopr = (double) pCh->info.i.upper_disp_limit;
	pr->lopr = (double) pCh->info.i.lower_disp_limit;
	pr->precision = 0;
	break;
    case DBF_LONG:
	pr->value = (double) pCh->info.l.value;
	pr->hopr = (double) pCh->info.l.upper_disp_limit;
	pr->lopr = (double) pCh->info.l.lower_disp_limit;
	pr->precision = 0;
	break;
    case DBF_FLOAT:
	pr->value = (double) pCh->info.f.value;
	pr->hopr = (double) pCh->info.f.upper_disp_limit;
	pr->lopr = (double) pCh->info.f.lower_disp_limit;
	pr->precision = pCh->info.f.precision;
	break;
    case DBF_DOUBLE:
	pr->value = (double) pCh->info.d.value;
	pr->hopr = (double) pCh->info.d.upper_disp_limit;
	pr->lopr = (double) pCh->info.d.lower_disp_limit;
	pr->precision = pCh->info.f.precision;
	break;
    default:
	medmPostMsg(0,"medmUpdateGraphicalInfoCb: Unknown data type\n");
	return;
    }

  /* Adjust the precision */
    if(pr->precision < 0) {
	medmPostMsg(0,"medmUpdateGraphicalInfoCb: "
	  "pv = \"%s\" precision = %d\n",
	  ca_name(pCh->chid), pr->precision);
	pr->precision = 0;
    } else if(pr->precision > 17) {
	medmPostMsg(1,"medmUpdateGraphicalInfoCb: "
	  "pv = \"%s\" precision = %d\n",
	  ca_name(pCh->chid), pr->precision);
	pr->precision = 17;
    }

  /* Call the record's graphical info callback or its update value callback */
    if(pr->updateGraphicalInfoCb) {
	pr->updateGraphicalInfoCb((XtPointer)pr);
    } else if(pr->updateValueCb) {
	pr->updateValueCb((XtPointer)pr);
    }
}
Example #18
0
void connection_handler ( struct connection_handler_args args )
{
    pv *ppv = ( pv * ) ca_puser ( args.chid );
    if ( args.op == CA_OP_CONN_UP ) {
        int dbrType;
                                /* Set up pv structure */
                                /* ------------------- */

                                /* Get natural type and array count */
        ppv->nElems  = ca_element_count(ppv->chid);
        ppv->dbfType = ca_field_type(ppv->chid);

                                /* Set up value structures */
        dbrType = dbf_type_to_DBR_TIME(ppv->dbfType); /* Use native type */
        if (dbr_type_is_ENUM(dbrType))                  /* Enums honour -n option */
        {
            if (enumAsNr) dbrType = DBR_TIME_INT;
            else          dbrType = DBR_TIME_STRING;
        }
        
        else if (floatAsString &&
                 (dbr_type_is_FLOAT(dbrType) || dbr_type_is_DOUBLE(dbrType)))
        {
            dbrType = DBR_TIME_STRING;
        }
                                /* Adjust array count */
        if (reqElems == 0 || ppv->nElems < reqElems){
            ppv->reqElems = ppv->nElems; /* Use full number of points */
        } else {
            ppv->reqElems = reqElems; /* Limit to specified number */
        }

                                /* Remember dbrType */
        ppv->dbrType  = dbrType;

        ppv->onceConnected = 1;
        nConn++;
                                /* Issue CA request */
                                /* ---------------- */
        /* install monitor once with first connect */
        if ( ! ppv->value ) {
                                    /* Allocate value structure */
            ppv->value = calloc(1, dbr_size_n(dbrType, ppv->reqElems));           
            if ( ppv->value ) {
                ppv->status = ca_create_subscription(dbrType,
                                                ppv->reqElems,
                                                ppv->chid,
                                                eventMask,
                                                event_handler,
                                                (void*)ppv,
                                                NULL);
                if ( ppv->status != ECA_NORMAL ) {
                    free ( ppv->value );
                }
            }
        }
    }
    else if ( args.op == CA_OP_CONN_DOWN ) {
        nConn--;
        ppv->status = ECA_DISCONN;
        print_time_val_sts(ppv, ppv->reqElems);
    }
}
static void medmConnectEventCb(struct connection_handler_args args) {
    int status;
    Channel *pCh = (Channel *)ca_puser(args.chid);
    int count;

  /* Increment the event counter */
    caTask.caEventCount++;

  /* Check for valid values */
    if(globalDisplayListTraversalMode != DL_EXECUTE) return;
    if(!pCh || !pCh->chid || !pCh->pr) {
	medmPostMsg(0,"medmConnectEventCb: Invalid channel information\n");
	return;
    }

  /* Do a get every time a channel is connected or reconnected and has
   * read access.  The get will cause the graphical info callback to
   * be called */
    if(args.op == CA_OP_CONN_UP && ca_read_access(pCh->chid)) {
	status = ca_array_get_callback(
	  dbf_type_to_DBR_CTRL(ca_field_type(args.chid)),
	  1, args.chid, medmUpdateGraphicalInfoCb, NULL);
	if(status != ECA_NORMAL) {
	    medmPostMsg(0,"medmConnectEventCb: "
	      "ca_array_get_callback [%s]:\n %s\n",
	      ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
	      ca_message(status));
#if DEBUG_CONNECTION
# if 0
	    system("netstat | grep iocacis");
# endif
	    print("  pCh->chid %s args.chid\n",
	      pCh->chid == args.chid?"==":"!=");
	    print(
	      "  Channel Name: %s\n"
	      "  State: %s\n"
	      "  Native Type: %s\n"
	      "  Native Count: %hu\n"
	      "  Access: %s%s\n"
	      "  IOC: %s\n",
	      args.chid?ca_name(args.chid):"Unavailable",
	      args.chid?ca_state(args.chid) == cs_never_conn?"Never":
	      ca_state(args.chid) == cs_prev_conn?"Prev":
	      ca_state(args.chid) == cs_conn?"Conn":
	      ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
	      args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
	      args.chid?ca_element_count(args.chid):0,
	      args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
	      args.chid?(ca_write_access(args.chid)?"W":""):"",
	      args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	}
    }

  /* Handle four cases: connected or not and previously connected or not */
    if(args.op == CA_OP_CONN_UP) {
      /* Connected */
	if(pCh->previouslyConnected == False) {
	  /* Connected and not previously connected */
	  /* Set these first so they will be right for the updateValueCb */
	    pCh->pr->elementCount = ca_element_count(pCh->chid);
	    pCh->pr->dataType = ca_field_type(args.chid);
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	  /* Add the access-rights-change callback and the
	     significant-change (value, alarm or severity)
	     callback. Don't call the updateValueCb because
	     ca_replace_access_rights_event will call it. */
	    status = ca_replace_access_rights_event(
	      pCh->chid,medmReplaceAccessRightsEventCb);
	    if(status != ECA_NORMAL) {
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_replace_access_rights_event [%s]: %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
	    }
	    if(pCh->pr->currentCount == -2) {
                count=0;
            } else {
                count=ca_element_count(pCh->chid);
            }
#ifdef __USING_TIME_STAMP__
	    status = ca_add_array_event(
	      dbf_type_to_DBR_TIME(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#else
	    status = ca_add_array_event(
	      dbf_type_to_DBR_STS(ca_field_type(pCh->chid)),
	      count, pCh->chid,
	      medmUpdateChannelCb, pCh, 0.0,0.0,0.0, &(pCh->evid));
#endif
	    if(status != ECA_NORMAL) {
	      /* Set the pointer to NULL in case CA didn't.  We don't
                 want to use it or clear it later. */
#if DEBUG_CONNECTION
		if(!pCh->evid) {
		    print("medmConnectEventCb: ca_add_array_event: \n"
		      "  status[%d] != ECA_NORMAL and pCh->evid != NULL\n",
		      status);
		}
#endif
		pCh->evid = NULL;
		medmPostMsg(0,"medmConnectEventCb: "
		  "ca_add_array_event [%s]:\n %s\n",
		  ca_name(pCh->chid)?ca_name(pCh->chid):"Unknown",
		  ca_message(status));
#if DEBUG_CONNECTION
# if 0
		system("netstat | grep iocacis");
# endif
		print("  pCh->chid %s args.chid\n",
		  pCh->chid == args.chid?"==":"!=");
		print(
		  "  Channel Name: %s\n"
		  "  State: %s\n"
		  "  Native Type: %s\n"
		  "  Native Count: %hu\n"
		  "  Access: %s%s\n"
		  "  IOC: %s\n",
		  args.chid?ca_name(args.chid):"Unavailable",
		  args.chid?ca_state(args.chid) == cs_never_conn?"Never":
		  ca_state(args.chid) == cs_prev_conn?"Prev":
		  ca_state(args.chid) == cs_conn?"Conn":
		  ca_state(args.chid) == cs_closed?"Closed":"Unknown":"Unavailable",
		  args.chid?dbf_type_to_text(ca_field_type(args.chid)):"Unavailable",
		  args.chid?ca_element_count(args.chid):0,
		  args.chid?(ca_read_access(args.chid)?"R":"None"):"Unavailable",
		  args.chid?(ca_write_access(args.chid)?"W":""):"",
		  args.chid?ca_host_name(args.chid):"Unavailable");
#endif
	    }
	  /* Set this one last so ca_replace_access_rights_event can
             use the old value */
	    pCh->previouslyConnected = True;
	} else {
	  /* Connected and previously connected */
	    pCh->pr->connected = True;
	    caTask.channelConnected++;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    } else {
      /* Not connected */
	if(pCh->previouslyConnected == False) {
	  /* Not connected and not previously connected */
	  /* Probably doesn't happen -- if CA can't connect, this
	   *   routine never gets called */
	    pCh->pr->connected = False;
	} else {
	  /* Not connected but previously connected */
	    pCh->pr->connected = False;
	    caTask.channelConnected--;
	    if(pCh->pr->updateValueCb)
	      pCh->pr->updateValueCb((XtPointer)pCh->pr);
	}
    }
}