Exemple #1
1
/*
 * 	cagft()
 *
 *	ca get field test
 *
 *	test ca get over the range of CA data types
 */
static int cagft(char *pname)
{	
	const unsigned maxTries = 1000ul;
	unsigned ntries = 0u;
	chid chan_id;
	int status;
	int i;

	/* 
	 *	convert name to chan id 
	 */
	status = ca_search(pname, &chan_id);
	SEVCHK(status,NULL);
	status = ca_pend_io(5.0);
	if(status != ECA_NORMAL){
        SEVCHK(ca_clear_channel(chan_id),NULL);
		printf("Not Found %s\n", pname);
		return -1;
	}

	printf("name:\t%s\n", 
        ca_name(chan_id));
	printf("native type:\t%s\n", 
        dbr_type_to_text(ca_field_type(chan_id)));
	printf("native count:\t%lu\n", 
        ca_element_count(chan_id));


	/* 
 	 * fetch as each type 
	 */
	for(i=0; i<=LAST_BUFFER_TYPE; i++){
		if(ca_field_type(chan_id)==DBR_STRING) {
			if( (i!=DBR_STRING)
			  && (i!=DBR_STS_STRING)
			  && (i!=DBR_TIME_STRING)
			  && (i!=DBR_GR_STRING)
              && (i!=DBR_CTRL_STRING)) {
                  continue;
            }
        }
        /* ignore write only types */
        if ( 
            i == DBR_PUT_ACKT || 
            i == DBR_PUT_ACKS ) {
                continue;
        }

		status = ca_array_get_callback(
				i, 
				ca_element_count(chan_id),
				chan_id, 
				printit, 
				NULL);
		SEVCHK(status, NULL);

		outstanding++;
	}

	/*
	 * wait for the operation to complete
	 * before returning 
	 */
	while ( ntries < maxTries ) {
		unsigned long oldOut;

		oldOut = outstanding;
		ca_pend_event ( 0.05 );

		if ( ! outstanding ) {
            SEVCHK ( ca_clear_channel ( chan_id ), NULL );
			printf ( "\n\n" );
			return 0;
		}

		if ( outstanding == oldOut ) {
			ntries++;
		}
	}

    SEVCHK ( ca_clear_channel ( chan_id ), NULL );
	return -1;
}
Exemple #2
0
PyObject *pv_getter_pvdim(pvobject * self, void *closure)
{
	if (self->chanId)
		return PyInt_FromLong(ca_element_count(self->chanId));
	else {
		PYCA_ERR("pvdim: invalid chid");
	}
}
static void printChidInfo(chid chid, char *message)
{
	printf("\n%s\n",message);
	printf("pv: %s  type(%d) nelements(%ld) host(%s)",
			ca_name(chid),ca_field_type(chid),ca_element_count(chid),
			ca_host_name(chid));
	printf(" read(%d) write(%d) state(%d)\n",
			ca_read_access(chid),ca_write_access(chid),ca_state(chid));
}
Exemple #4
0
static int stateHandlerInvoke(Tcl_Event* p, int flags) {
	/* called from Tcl event loop, when the connection status changes */
	connectionEvent *cev =(connectionEvent *) p;
	pvInfo *info = cev->info;
	Tcl_Obj *script = Tcl_DuplicateObj(info->connectprefix);
	Tcl_IncrRefCount(script);

	/* append cmd of PV and up/down */
	Tcl_Obj *cmdname = Tcl_NewObj();
    Tcl_GetCommandFullName(info->interp, info->cmd, cmdname);
	
	int code = Tcl_ListObjAppendElement(info->interp, script, cmdname);
	if (code != TCL_OK) {
		goto bgerr;
	}
	
	if (cev->op == CA_OP_CONN_UP) {
		info->connected = 1;
		/* Retrieve information about type and number of elements */
		info->nElem = ca_element_count(info->id);
		info->type  = ca_field_type(info->id);
	} else {
		info->connected = 0;
	}
	
	code = Tcl_ListObjAppendElement(info->interp, script, Tcl_NewBooleanObj(info->connected));
	if (code != TCL_OK) {
		goto bgerr;
	}


	Tcl_Preserve(info->interp);
	code = Tcl_EvalObjEx(info->interp, script, TCL_EVAL_GLOBAL);

	if (code != TCL_OK) { goto bgerr; }

	Tcl_Release(info->interp);
	Tcl_DecrRefCount(script);
	/* this event was successfully handled */
	return 1; 
bgerr:
	/* put error in background */
	Tcl_AddErrorInfo(info->interp, "\n    (epics connection callback script)");
	Tcl_BackgroundException(info->interp, code);
	
	/* this event was successfully handled */
	return 1;
}
Exemple #5
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);
    }
}
Exemple #6
0
/*
 * VERIFY_VALUE
 *
 * initiate print out the values in a database access interface structure
 */
static void verify_value(chid chan_id, chtype type)
{
	int status;

	/*
	 * issue a get which calls back `printit'
	 * upon completion
	 */
	status = ca_array_get_callback(
			type, 
			ca_element_count(chan_id),
			chan_id, 
			printit, 
			NULL);
	SEVCHK(status, NULL);

	outstanding++;
}
static void exCB(struct exception_handler_args args)
{
#define MAX_EXCEPTIONS 25    
    static int nexceptions=0;
    static int ended=0;

    if(ended) return;
    if(nexceptions++ > MAX_EXCEPTIONS) {
        ended=1;
        fprintf(stderr,"exCB Exception: Channel Access Exception:\n"
          "Too many exceptions [%d]\n"
          "No more will be handled\n"
          "Please fix the problem and restart camonitorpv",
          MAX_EXCEPTIONS);
        ca_add_exception_event(NULL, NULL);
        return;
    }
    
    fprintf(stderr,"exCB Exception: Channel Access Exception:\n"
      "  Channel Name: %s\n"
      "  Native Type: %s\n"
      "  Native Count: %lu\n"
      "  Access: %s%s\n"
      "  IOC: %s\n"
      "  Message: %s\n"
      "  Context: %s\n"
      "  Requested Type: %s\n"
      "  Requested Count: %ld\n"
      "  Source File: %s\n"
      "  Line number: %u",
      args.chid?ca_name(args.chid):"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":""):"Unavailable",
      args.chid?(ca_write_access(args.chid)?"W":""):"",
      args.chid?ca_host_name(args.chid):"Unavailable",
      ca_message(args.stat)?ca_message(args.stat):"Unavailable",
      args.ctx?args.ctx:"Unavailable",
      dbf_type_to_text(args.type),
      args.count,
      args.pFile?args.pFile:"Unavailable",
      args.pFile?args.lineNo:0);
}
// 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());
    }
}
Exemple #9
0
static void exceptionCallback(struct exception_handler_args args)
{
    const char *context = (args.ctx ? args.ctx : "unknown");

    errlogPrintf("DB CA Link Exception: \"%s\", context \"%s\"\n",
        ca_message(args.stat), context);
    if (args.chid) {
        errlogPrintf(
            "DB CA Link Exception: channel \"%s\"\n",
            ca_name(args.chid));
        if (ca_state(args.chid) == cs_conn) {
            errlogPrintf(
                "DB CA Link Exception:  native  T=%s, request T=%s,"
                " native N=%ld, request N=%ld, "
                " access rights {%s%s}\n",
                dbr_type_to_text(ca_field_type(args.chid)),
                dbr_type_to_text(args.type),
                ca_element_count(args.chid),
                args.count,
                ca_read_access(args.chid) ? "R" : "",
                ca_write_access(args.chid) ? "W" : "");
        }
    }
}
Exemple #10
0
/*
 *	capft
 *
 *	test ca_put() over a range of data types
 *	
 */
static int capft(
char		*pname,
char		*pvalue
)
{
	dbr_short_t			shortvalue;
	dbr_long_t			longvalue;
	dbr_float_t			floatvalue;
	dbr_char_t			charvalue;
	dbr_double_t		doublevalue;
	unsigned long		ntries = 10ul;
	int					status;
	chid				chan_id;

	if (((*pname < ' ') || (*pname > 'z'))
	  || ((*pvalue < ' ') || (*pvalue > 'z'))){
		printf("\nusage \"pv name\",\"value\"\n");
		return -1;
	}

	/* 
	 *	convert name to chan id 
	 */
	status = ca_search(pname, &chan_id);
	SEVCHK(status,NULL);
	status = ca_pend_io(5.0);
	if(status != ECA_NORMAL){
        SEVCHK(ca_clear_channel(chan_id),NULL);
		printf("Not Found %s\n", pname);
		return -1;
	}

	printf("name:\t%s\n", ca_name(chan_id));
	printf("native type:\t%d\n", ca_field_type(chan_id));
	printf("native count:\t%lu\n", ca_element_count(chan_id));

	/*
	 *  string value ca_put
	 */
	status = ca_put(
			DBR_STRING, 
			chan_id, 
			pvalue);
	SEVCHK(status, NULL);
	verify_value(chan_id, DBR_STRING);

	if(ca_field_type(chan_id)==0)goto skip_rest;

	if(sscanf(pvalue,"%hd",&shortvalue)==1) {
		/*
		 * short integer ca_put
		 */
		status = ca_put(
				DBR_SHORT, 
				chan_id, 
				&shortvalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_SHORT);
		status = ca_put(
				DBR_ENUM, 
				chan_id, 
				&shortvalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_ENUM);
		charvalue=(dbr_char_t)shortvalue;
		status = ca_put(
				DBR_CHAR, 
				chan_id, 
				&charvalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_CHAR);
	}
	if(sscanf(pvalue,"%d",&longvalue)==1) {
		/*
		 * long integer ca_put
		 */
		status = ca_put(
				DBR_LONG, 
				chan_id, 
				&longvalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_LONG);
	}
	if(epicsScanFloat(pvalue, &floatvalue)==1) {
		/*
		 * single precision float ca_put
		 */
		status = ca_put(
				DBR_FLOAT, 
				chan_id, 
				&floatvalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_FLOAT);
	}
	if(epicsScanDouble(pvalue, &doublevalue)==1) {
		/*
		 * double precision float ca_put
		 */
		status = ca_put(
				DBR_DOUBLE, 
				chan_id, 
				&doublevalue);
		SEVCHK(status, NULL);
		verify_value(chan_id, DBR_DOUBLE);
	}

skip_rest:

	/*
	 * wait for the operation to complete
	 * (outstabnding decrements to zero)
	 */
	while(ntries){
		ca_pend_event(1.0);

		if(!outstanding){
            SEVCHK(ca_clear_channel(chan_id),NULL);
			printf("\n\n");
			return 0;
		}

		ntries--;
	}

    SEVCHK(ca_clear_channel(chan_id),NULL);
	return -1;
}
Exemple #11
0
int cagetFuZE(char *pvName, char *pvValue) {

  RequestT request = get;
  OutputT format = plain;
  chtype dbrType = -1;
  unsigned long reqElems = 0;
  int n, result;
  pv* pvs;
  int i;
  unsigned long nElems;
  

  result = ca_context_create(ca_disable_preemptive_callback);

  pvs = calloc(1, sizeof(pv));

  pvs[0].name = pvName;
  
  connect_pvs(pvs, 1);
  
  for (n = 0; n < 1; n++) {
    
    /* Set up pvs structure */
    /* -------------------- */

    /* Get natural type and array count */
    nElems         = ca_element_count(pvs[n].chid);
    pvs[n].dbfType = ca_field_type(pvs[n].chid);
    pvs[n].dbrType = dbrType;

    /* Set up value structures */
    if (format != specifiedDbr)
      {
	pvs[n].dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */
	if (dbr_type_is_ENUM(pvs[n].dbrType))                  /* Enums honour -n option */
	  {
	    if (enumAsNr) pvs[n].dbrType = DBR_TIME_INT;
	    else          pvs[n].dbrType = DBR_TIME_STRING;
	  }
	else if (floatAsString &&
		 (dbr_type_is_FLOAT(pvs[n].dbrType) || dbr_type_is_DOUBLE(pvs[n].dbrType)))
	  {
	    pvs[n].dbrType = DBR_TIME_STRING;
	  }
      }

    /* Issue CA request */
    /* ---------------- */

    if (ca_state(pvs[n].chid) == cs_conn)
      {
  	nConn++;
  	pvs[n].onceConnected = 1;
  	if (request == callback)
  	  {
  	    /* Event handler will allocate value and set nElems */
  	    pvs[n].reqElems = reqElems > nElems ? nElems : reqElems;
  	    result = ca_array_get_callback(pvs[n].dbrType,
  					   pvs[n].reqElems,
  					   pvs[n].chid,
  					   event_handler,
  					   (void*)&pvs[n]);
  	  } else {
  	  /* We allocate value structure and set nElems */
	  pvs[n].nElems = reqElems && reqElems < nElems ? reqElems : nElems;
  	  pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].nElems));
	  if (!pvs[n].value) {
  	    fprintf(stderr,"Memory allocation failed\n");
  	    return -1;
  	  }
  	  result = ca_array_get(pvs[n].dbrType,
  				pvs[n].nElems,
  				pvs[n].chid,
  				pvs[n].value);
  	}
  	pvs[n].status = result;
      } else {
      pvs[n].status = ECA_DISCONN;
    }
  }

  if (!nConn) return -1;              /* No connection? We're done. */

  /* Wait for completion */
  /* ------------------- */

  result = ca_pend_io(caTimeout);
  if (result == ECA_TIMEOUT) {
    fprintf(stderr, "Read operation timed out: some PV data was not read.\n");
    return -1;
  }

  if (request == callback)    /* Also wait for callbacks */
    {
      if (caTimeout != 0)
        {
	  double slice = caTimeout / PEND_EVENT_SLICES;
	  for (n = 0; n < PEND_EVENT_SLICES; n++)
            {
	      ca_pend_event(slice);
	      if (nRead >= nConn) break;
            }
	  if (nRead < nConn) {
	    fprintf(stderr, "Read operation timed out: some PV data was not read.\n");
	    return -1;
	  }
	} else {
	/* For 0 timeout keep waiting until all are done */
	    while (nRead < nConn) {
	      ca_pend_event(1.0);
	    }
      }
    }


  // Does this kill the connection??
  ca_context_destroy();
  
  sprintf(pvValue, "%s\n", val2str(pvs[0].value, pvs[0].dbrType, 0));

  return 1;

}
void mcaMonitorEventHandler(struct event_handler_args arg)
{   union db_access_val *pBuf;
    struct mca_channel* PCHNL = (struct mca_channel*)arg.usr;
    double *myDblPr;
    chtype RequestType;
    int i,Cnt;
    mxArray* mymxArray;
    pBuf = (union db_access_val *)arg.dbr;
    
    //mexPrintf("MCA Monitor Event Handler Called\n");
    
    PCHNL->MonitorEventCount++;
    
    Cnt = ca_element_count(arg.chid);  
    RequestType = dbf_type_to_DBR(ca_field_type(arg.chid)); // Closest to the native 
    
    if(RequestType==DBR_STRING)
    {   if(Cnt==1)
        {   mxDestroyArray(PCHNL->CACHE); // clear mxArray that pointed to by PCHNL->CACHE
            PCHNL->CACHE = mxCreateString((char*)((pBuf)->strval)); // Create new array with current string value
            mexMakeArrayPersistent(PCHNL->CACHE);
        }
        else
        {   for(i=0;i<Cnt;i++)
            {   mymxArray = mxGetCell(PCHNL->CACHE,i);
                mxDestroyArray(mymxArray);
                mymxArray = mxCreateString(  (char*)   (&(pBuf->strval)+i)   );
                mexMakeArrayPersistent(mymxArray);
                mxSetCell(PCHNL->CACHE,i,mymxArray);
            }
        }
    }
    else
    {   myDblPr = mxGetPr(PCHNL->CACHE);
        
        switch(RequestType)
        {   case DBR_INT: // As defined in db_access.h DBR_INT = DBR_SHORT = 1
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->intval)+i));
            break;    
            
            case DBR_FLOAT:
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->fltval)+i));
            break;
                
            case DBR_ENUM:
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->enmval)+i));
            break;
                
            case DBR_CHAR:
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->charval)+i));
            break;
                    
            case DBR_LONG:
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->longval)+i));
            break;
                    
            case DBR_DOUBLE:
            for (i = 0; i<Cnt;i++)
                myDblPr[i]= (double)(*(&((pBuf)->doubleval)+i));
            break;
        }
    }
    
    if(PCHNL->MonitorCBString)
    {   
        mexEvalString(PCHNL->MonitorCBString);
    }
}
void mexFunction(	int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{   
    int i,j, k, status,buflen,Cnt, Hndl, L,M,N,  NumHandles, commandswitch;
    
    int *HndlArray;
    mxArray  *mymxArray;
    double *myDblPr;
    chtype RequestType;
    
    char PVName[PV_NAME_LENGTH_MAX+1];
    // char MCAMessageString[MCA_MESSAGE_STRING_LENGTH_MAX+1];
    
    
      

    dbr_string_t StrBuffer;
    
        
    
    const char *MCAInfoFields[]={"PVName","ElementCount","NativeType","State","MCAMessage","Host"};
    char *NativeTypeStrings[] = {"STRING","INT","FLOAT","ENUM","CHAR","LONG","DOUBLE"};
    


    
    if(!CA_INITIALIZED) // Initialize CA if not initialized (first call)
    {   mexPrintf("Initializing MATLAB Channel Access ... \n");
        status = ca_task_initialize();
        if(status!=ECA_NORMAL)
            mexErrMsgTxt("Unable to initialise Challel Access\n");
        CA_INITIALIZED = true;
        // Register a function to be called when a this mex-file is cleared from memory
        // with 'clear' or when exitting MATLAB
        mexAtExit(mca_cleanup);
        // Lock the mex-file so that it can not be cleared without explicitly
        // mexUnclock
        mexLock();
        
        //start periodic polling:
/*        PollTimerHandle = SetTimer(NULL,NULL,MCA_POLL_PERIOD,background_poll);
        if(PollTimerHandle)
            mexPrintf("Periodic CA polling started! System Timer ID: %u\n",PollTimerHandle);
        else
            mexWarnMsgTxt("Failed to start periodic CA polling\n");
 */       
        
    }

    commandswitch = (int)mxGetScalar(prhs[0]);
   
    switch(commandswitch)
    {  case 0: 
            mexUnlock();
            break;
    
        case 1: // MCAOPEN - add channel(s) by PV names, all arguments following prhs[0]
               // must be strings - names of PV's
            for(i=1;i<nrhs;i++)
            {   mxGetString(prhs[i],PVName,PV_NAME_LENGTH_MAX+1);
                status = ca_search(PVName,&(CHNLS[HandlesUsed].CHID));
                if(status == ECA_NORMAL) // if not - go on to the next PV name
                {   status = ca_pend_io(MCA_SEARCH_TIMEOUT);
                    if (status == ECA_NORMAL)
                    {   // Allocate persistent memory for the DataBuffer on this channel
                        // to hold all elements of the DBR_XXX type
                        // nearest to the native type
                        // RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[HandlesUsed].CHID));
                        // Cnt=ca_element_count(CHNLS[HandlesUsed].CHID);
                        
                        
                        CHNLS[HandlesUsed].NumElements = ca_element_count(CHNLS[HandlesUsed].CHID);
                        CHNLS[HandlesUsed].NativeType2DBR = dbf_type_to_DBR(ca_field_type(CHNLS[HandlesUsed].CHID));
                        CHNLS[HandlesUsed].MonitorEventCount = 0;
                        
                        switch(CHNLS[HandlesUsed].NativeType2DBR)
                        {   case DBR_STRING:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_string_t));
                                
                            break;
                        
                            case DBR_INT: // As defined in db_access.h DBR_INT = DBR_SHORT = 1
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_short_t)); 
                            break;
                        
                            case DBR_FLOAT:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_float_t)); 
                            break;
                
                            case DBR_ENUM:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_enum_t)); 
                            break;
                
                            case DBR_CHAR:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_char_t)); 
                            break;
                    
                            case DBR_LONG:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_short_t)); 
                            break;
                    
                            case DBR_DOUBLE:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_double_t)); 
                            break;
                        }   
                        mexMakeMemoryPersistent(CHNLS[HandlesUsed].DataBuffer);
                        
                                 
                        if(CHNLS[HandlesUsed].NativeType2DBR==DBR_STRING) // CACHE
                        {   if(CHNLS[HandlesUsed].NumElements==1) // Create MATLAB string - originally empty
                                CHNLS[HandlesUsed].CACHE = mxCreateString("");
                            else // Create MATLAB cell array of strings
                            {   CHNLS[HandlesUsed].CACHE = mxCreateCellMatrix(1,CHNLS[HandlesUsed].NumElements);
                                for(k=0;k<CHNLS[HandlesUsed].NumElements;k++)
                                {   mymxArray = mxCreateString("");
                                    mexMakeArrayPersistent(mymxArray);
                                    mxSetCell(CHNLS[HandlesUsed].CACHE, k, mymxArray);
                                }
                            }
                        }
                        else // Make CACHE a numeric mxArray 
                        {    CHNLS[HandlesUsed].CACHE = mxCreateDoubleMatrix(1,CHNLS[HandlesUsed].NumElements,mxREAL);  
                        }
                        
                        mexMakeArrayPersistent(CHNLS[HandlesUsed].CACHE);
                        
                        plhs[i-1]=mxCreateScalarDouble(++HandlesUsed);                        
                    
                    }
                    else
                        plhs[i-1]=mxCreateScalarDouble(0);

                }
                else
                    plhs[i-1]=mxCreateScalarDouble(0);
            } break;
            
        
        case 2:// MCAOPEN - add channel(s) by PV names. The arguments following prhs[0]
               // argument must be a cell array of strings - PV names
            
            L = mxGetM(prhs[1])*mxGetN(prhs[1]);
            plhs[0] = mxCreateDoubleMatrix(1,L,mxREAL);
            myDblPr = mxGetPr(plhs[0]);
            
            for(i=0;i<L;i++)
            {   mymxArray = mxGetCell(prhs[1],i);
                mxGetString(mymxArray,PVName,PV_NAME_LENGTH_MAX+1);
                status = ca_search(PVName,&(CHNLS[HandlesUsed].CHID));
                if(status == ECA_NORMAL) // if not - go on to the next PV name
                {   status = ca_pend_io(MCA_IO_TIMEOUT);
                    if (status == ECA_NORMAL)
                    {   // Allcate persistent memory for the DataBuffer on this channel
                        //RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[HandlesUsed].CHID));
                        CHNLS[HandlesUsed].NativeType2DBR = dbf_type_to_DBR(ca_field_type(CHNLS[HandlesUsed].CHID));
                        CHNLS[HandlesUsed].NumElements = ca_element_count(CHNLS[HandlesUsed].CHID);
                        CHNLS[HandlesUsed].MonitorEventCount = 0;
                        //Cnt=ca_element_count(CHNLS[HandlesUsed].CHID);
                        switch(CHNLS[HandlesUsed].NativeType2DBR)
                        {   case DBR_STRING:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_string_t)); 
                            break;
                        
                            case DBR_INT: // As defined in db_access.h DBR_INT = DBR_SHORT = 1
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_short_t)); 
                            break;
                        
                            case DBR_FLOAT:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_float_t)); 
                            break;
                
                        
                            case DBR_ENUM:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_enum_t)); 
                            break;
                
                            case DBR_CHAR:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_char_t)); 
                            break;
                    
                            case DBR_LONG:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_short_t)); 
                            break;
                    
                            case DBR_DOUBLE:
                                CHNLS[HandlesUsed].DataBuffer = mxCalloc(CHNLS[HandlesUsed].NumElements,sizeof(dbr_double_t)); 
                            break;
                        }   
                        mexMakeMemoryPersistent(CHNLS[HandlesUsed].DataBuffer);   
                        
                        if(CHNLS[HandlesUsed].NativeType2DBR == DBR_STRING) // CACHE
                        {   CHNLS[HandlesUsed].CACHE = mxCreateCellMatrix(1,CHNLS[HandlesUsed].NumElements);
                            for(k=0;k<CHNLS[HandlesUsed].NumElements;k++)
                            {   mymxArray = mxCreateString(StrBuffer);
                                mexMakeArrayPersistent(mymxArray);
                                mxSetCell(CHNLS[HandlesUsed].CACHE, k, mymxArray);
                            }
                        }
                        else
                        {    CHNLS[HandlesUsed].CACHE = mxCreateDoubleMatrix(1,CHNLS[HandlesUsed].NumElements,mxREAL);  
                        }
                        
                        mexMakeArrayPersistent(CHNLS[HandlesUsed].CACHE);
                        
                        
                        myDblPr[i] = ++HandlesUsed;
                    }
                    else
                        myDblPr[i] = 0;
                }
                else
                    myDblPr[i] = 0;
            } break;
            
       case 3: // MCAOPEN Return names of connected channels as cell array of strings
            plhs[0] = mxCreateCellArray(1, &HandlesUsed);
            for(i=0;i<HandlesUsed;i++)
            {   if(CHNLS[i].CHID!=NULL)
                    {   mymxArray = mxCreateString(ca_name(CHNLS[i].CHID));
                        mxSetCell(plhs[0], i, mymxArray);
                    }
                else
                    {   mymxArray = mxCreateString("");
                        //mexPrintf("Handle: %d PV: %s\n",i+1, "Cleared Channel");
                        mxSetCell(plhs[0], i, mymxArray);
                    }
              } break;
        
        
         
        case 5: // MCACLOSE permanently clear channel
            Hndl = (int)mxGetScalar(prhs[1]);
            if(Hndl<1 || Hndl>HandlesUsed)
                mexErrMsgTxt("Handle out of range");  

            // If a monitor is installed, set the EVID pointer to NULL 
            // ca_clear_event dos not do it by itself

            if(CHNLS[Hndl-1].EVID) 
                CHNLS[Hndl-1].EVID = NULL;
                
            // If there is Callback String - destroy it
            if(CHNLS[Hndl-1].MonitorCBString)
            {   mxFree(CHNLS[Hndl-1].MonitorCBString); 
                CHNLS[Hndl-1].MonitorCBString =NULL;
            }    
            
            if(ca_state(CHNLS[Hndl-1].CHID)==3)
                mexWarnMsgTxt("Channel previously cleared");
            else
                if(ca_clear_channel(CHNLS[Hndl-1].CHID)!=ECA_NORMAL)
                    mexErrMsgTxt("ca_clear_channel failed");

            break;
            
        case 10: // MCAINFO return channels info as MATLAB structure array
            if(HandlesUsed>0)
            {   plhs[0] = mxCreateStructMatrix(1,HandlesUsed,6,MCAInfoFields);
                
                for(i=0;i<HandlesUsed;i++)
                {   mxSetFieldByNumber(plhs[0],i,0,mxCreateString(ca_name(CHNLS[i].CHID)));
                    mxSetFieldByNumber(plhs[0],i,1,mxCreateScalarDouble(ca_element_count(CHNLS[i].CHID)));
                    mxSetFieldByNumber(plhs[0],i,5,mxCreateString(ca_host_name(CHNLS[i].CHID)));
                    
                    switch(ca_state(CHNLS[i].CHID))
                    {   case 1: // Disconnected due to Server or Network - may reconnect 
                            mxSetFieldByNumber(plhs[0],i,2,mxCreateString("unknown"));
                            mxSetFieldByNumber(plhs[0],i,3,mxCreateString("disconnected"));
                            mxSetFieldByNumber(plhs[0],i,4,mxCreateString("Disconnected due to server or network problem"));
                            break;
                        case 2: // Normal connection
                            mxSetFieldByNumber(plhs[0],i,2,mxCreateString(NativeTypeStrings[ca_field_type(CHNLS[i].CHID)]));
                            mxSetFieldByNumber(plhs[0],i,3,mxCreateString("connected"));
                            mxSetFieldByNumber(plhs[0],i,4,mxCreateString("Normal connection"));
                            break;
                        case 3: // Disconnected by user
                            mxSetFieldByNumber(plhs[0],i,2,mxCreateString("unknown"));
                            mxSetFieldByNumber(plhs[0],i,3,mxCreateString("disconnected"));
                            mxSetFieldByNumber(plhs[0],i,4,mxCreateString("Permanently disconnected (cleared) by the user"));                    
                            break;
                    }    
                }
            }
            else
            {   mexWarnMsgTxt("No connected PV's found"); 
                plhs[0] = mxCreateDoubleMatrix(0,0,mxREAL);
                
            }
            break;    
        
            
        case 11: // MCAINFO return info for 1 channel by handle number 
            Hndl = (int)mxGetScalar(prhs[1]);
            if(Hndl<1 || Hndl>HandlesUsed)
                mexErrMsgTxt("Handle out of range");  
                
            plhs[0] = mxCreateStructMatrix(1,1,6,MCAInfoFields);

            mxSetFieldByNumber(plhs[0],0,0,mxCreateString(ca_name(CHNLS[Hndl-1].CHID)));
            mxSetFieldByNumber(plhs[0],0,1,mxCreateScalarDouble(ca_element_count(CHNLS[Hndl-1].CHID)));
            mxSetFieldByNumber(plhs[0],0,5,mxCreateString(ca_host_name(CHNLS[Hndl-1].CHID)));
            
            switch(ca_state(CHNLS[Hndl-1].CHID))
            {  case 1: // Disconnected due to Server or Network - may reconnect 
                    mxSetFieldByNumber(plhs[0],0,2,mxCreateString("unknown"));
                    mxSetFieldByNumber(plhs[0],0,3,mxCreateString("disconnected"));
                    mxSetFieldByNumber(plhs[0],0,4,mxCreateString("Disconnected due to server or network problem"));
                    break;
                case 2: // Normal connection
                    mxSetFieldByNumber(plhs[0],0,2,mxCreateString(NativeTypeStrings[ca_field_type(CHNLS[Hndl-1].CHID)]));
                    mxSetFieldByNumber(plhs[0],0,3,mxCreateString("connected"));
                    mxSetFieldByNumber(plhs[0],0,4,mxCreateString("Normal connection"));
                    break;
                case 3: // Disconnected by user
                    mxSetFieldByNumber(plhs[0],0,2,mxCreateString("unknown"));
                    mxSetFieldByNumber(plhs[0],0,3,mxCreateString("disconnected"));
                    mxSetFieldByNumber(plhs[0],0,4,mxCreateString("Permanently disconnected (cleared) by the user"));                    
                    break;
            };    
            
        break;    
        
        case 12: // MCASTATE return an array of status (1 - OK, 0 - disconnected or cleared) 
            if(HandlesUsed>0)
            {   plhs[0] = mxCreateDoubleMatrix(1,HandlesUsed,mxREAL);
                myDblPr = mxGetPr(plhs[0]);
                for(i=0;i<HandlesUsed;i++)
                    myDblPr[i] = (double)(ca_state(CHNLS[i].CHID)==2);
            }
            else
            {   mexWarnMsgTxt("No connected PV's found"); 
                plhs[0] = mxCreateDoubleMatrix(0,0,mxREAL);
                
            }
            break;    
        
        
        case 30: // poll
            ca_poll();
        break;
            

        case 50: // MCAGET Get PV values by their MCA handles
            
            for(i=0;i<nrhs-1;i++) // First loop: place all ca_get requests in the buffer
            {   Hndl = (int)mxGetScalar(prhs[1+i]); //start from[1]:  [0] argument is the commnads switch
                if(Hndl<1 || Hndl>HandlesUsed)
                    mexErrMsgTxt("Invalid Handle");
                
                RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID));
                Cnt = ca_element_count(CHNLS[Hndl-1].CHID);
                status = ca_array_get(RequestType,Cnt,CHNLS[Hndl-1].CHID,CHNLS[Hndl-1].DataBuffer);
                if(status!=ECA_NORMAL)
                    mexPrintf("Error in call to ca_array_get\n");
            }   
            
            status = ca_pend_io(MCA_GET_TIMEOUT);
            if(status!=ECA_NORMAL)
                mexErrMsgTxt("... ca_pend_io call timed out \n");
            
            
            for(i=0;i<nrhs-1;i++) // Another loop to copy data from temp structures to MATLAB
            
            {   Hndl = (int)mxGetScalar(prhs[1+i]);
                RequestType = RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID));
                Cnt = ca_element_count(CHNLS[Hndl-1].CHID);
                
                if(RequestType==DBR_STRING)
                {   if(Cnt==1)
                        plhs[i] = mxCreateString((char*)(*((dbr_string_t*)(CHNLS[Hndl-1].DataBuffer))));
                    else
                    {   plhs[i] = mxCreateCellMatrix(1,Cnt);
                        for(j=0;j<Cnt;j++)
                            mxSetCell(plhs[i], j, mxCreateString((char*)(*((dbr_string_t*)(CHNLS[Hndl-1].DataBuffer)+j))));
                    }
                }
                
                else 
                {   plhs[i] = mxCreateDoubleMatrix(1,Cnt,mxREAL);
                    myDblPr = mxGetPr(plhs[i]);
                                        
                    switch(dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID)))
                    
                    {   case DBR_INT: // As defined in db_access.h DBR_INT = DBR_SHORT = 1
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_short_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;    
                 
                        case DBR_FLOAT:
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_float_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;
                
                        case DBR_ENUM:
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_enum_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;
                
                        case DBR_CHAR:
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_char_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;
                    
                        case DBR_LONG:
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_long_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;
                    
                        case DBR_DOUBLE:
                        for(j=0;j<Cnt;j++)
                            myDblPr[j]= (double)(*((dbr_double_t*)(CHNLS[Hndl-1].DataBuffer)+j));
                        break;
                    } 

                }
                
            } break;            

            case 51: // MCAGET Get scalar PV of the same type 
                     // second argument is an array of handles
                     // returns an array of values
            
            myDblPr = mxGetPr(prhs[1]);
            M = mxGetM(prhs[1]);
            N = mxGetN(prhs[1]);
            
            NumHandles = M*N;
            plhs[0] = mxCreateDoubleMatrix(M,N,mxREAL);
            
            for(i=0;i<NumHandles;i++) // First loop: place all ca_get requests in the buffer
            {   Hndl = (int)myDblPr[i];
                if(Hndl<1 || Hndl>HandlesUsed)
                    mexErrMsgTxt("Invalid Handle");
                
                RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID));
                status = ca_array_get(DBR_DOUBLE,1,CHNLS[Hndl-1].CHID,mxGetPr(plhs[0])+i);
                if(status!=ECA_NORMAL)
                    mexPrintf("Error in call to ca_array_get\n");
            }   
            
            status = ca_pend_io(MCA_GET_TIMEOUT);
            if(status!=ECA_NORMAL)
                mexErrMsgTxt("... ca_pend_io call timed out \n");
            
            break;            

        
       
        case 70: // MCAPUT
            NumHandles = (nrhs-1)/2;
            for(i=0;i<NumHandles;i++)
            {   j = 2+i*2;
                Hndl = (int)mxGetScalar(prhs[1+i*2]); 
                if(Hndl<1 || Hndl>HandlesUsed)
                    mexErrMsgTxt("Handle out of range - no values written");
                // Set the status to 0 - mcaput_callback will write 1, if successful
                CHNLS[Hndl-1].LastPutStatus = 0;    
                RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID));            
                Cnt = ca_element_count(CHNLS[Hndl-1].CHID);
                
                
                // If a value to write is passed as a string - the number of elements to write 
                //   is 1 , NOT the length of the string returned by mxGetNumberOfElements
                if(mxIsChar(prhs[j])) 
                    L=1;
                else
                    L = min(mxGetNumberOfElements(prhs[j]),Cnt);
                

                // Copy double or string data from MATLAB prhs[] to DataBuffer
                // on each channel 
                
                if(RequestType==DBR_STRING)
                {   // STRING type is is passed as a cell array of strings
                    // A a 1-row MATLAB character array (1 string) may also be passed as a value
                    
                    if(mxIsChar(prhs[j]))
                    {   mxGetString(prhs[j], StrBuffer, sizeof(dbr_string_t));
                        strcpy((char*)(*((dbr_string_t*)(CHNLS[Hndl-1].DataBuffer))),StrBuffer);
                        
                    }
                    else if(mxIsCell(prhs[j]))
                    {   for(k=0;k<L;k++)
                        {   mxGetString(mxGetCell(prhs[j],k), StrBuffer, sizeof(dbr_string_t));
                            strcpy((char*)(*((dbr_string_t*)(CHNLS[Hndl-1].DataBuffer)+k)),StrBuffer);
                        }
                    }
                }
                else
                {   myDblPr = mxGetPr(prhs[j]); 
                    switch(RequestType)
                    {   
                        case DBR_INT: // As defined in db_access.h DBR_INT = DBR_SHORT = 1
                        for(k=0;k<L;k++)
                            *((dbr_short_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_short_t)(myDblPr[k]);
                        break;    
                 
                        case DBR_FLOAT:
                        for(k=0;k<L;k++)
                            *((dbr_float_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_float_t)(myDblPr[k]);
                        break;
                
                        case DBR_ENUM:
                        for(k=0;k<L;k++)
                            *((dbr_enum_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_enum_t)(myDblPr[k]);
                        break;
                
                        case DBR_CHAR:
                        for(k=0;k<L;k++)
                            *((dbr_char_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_char_t)(myDblPr[k]);
                        break;
                   
                        case DBR_LONG:
                        for(k=0;k<L;k++)
                            *((dbr_long_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_long_t)(myDblPr[k]);
                        break;
                    
                        case DBR_DOUBLE:
                        for(k=0;k<L;k++)
                            *((dbr_double_t*)(CHNLS[Hndl-1].DataBuffer)+k) = (dbr_double_t)(myDblPr[k]);
                        break;
                    } 
                }            
 
                // place request in the que 
                status = ca_array_put_callback(RequestType,L,CHNLS[Hndl-1].CHID,CHNLS[Hndl-1].DataBuffer,
                                                   mcaput_callback,&(CHNLS[Hndl-1].LastPutStatus));

                 if(status!=ECA_NORMAL)
                    mexPrintf("ca_array_put_callback failed\n");
            }   
            
            status = ca_pend_event(MCA_PUT_TIMEOUT);
            
            plhs[0]=mxCreateDoubleMatrix(1,NumHandles,mxREAL);
            myDblPr = mxGetPr(plhs[0]);  
            
            for(i=0;i<NumHandles;i++)
            {   Hndl = (int)mxGetScalar(prhs[1+i*2]);
                myDblPr[i] = (double)CHNLS[Hndl-1].LastPutStatus;
                
            }
           
            break;
        
       case 80: // MCAPUT - fast unconfirmed put for scalar numeric PV's
        
            myDblPr = mxGetPr(prhs[1]);
            M = mxGetM(prhs[1]);
            N = mxGetN(prhs[1]);                
            NumHandles = M*N;
            
            plhs[0] = mxCreateDoubleMatrix(M,N,mxREAL);
            myDblPr = mxGetPr(plhs[0]);  
            
            for(i=0;i<NumHandles;i++)
            {   myDblPr = mxGetPr(plhs[0]);
                Hndl = (int)(*(mxGetPr(prhs[1])+i)); 
                if(Hndl<1 || Hndl>HandlesUsed)
                    mexErrMsgTxt("Handle out of range - no values written");

                status = ca_array_put(DBR_DOUBLE,1,CHNLS[Hndl-1].CHID,mxGetPr(prhs[2])+i);

                if(status!=ECA_NORMAL)
                    {   myDblPr[i] = 0;
                        //mexPrintf("ca_array_put_callback failed\n");
                    }
                    else
                    {   myDblPr[i] = 1;
                    }
                    
            }   
            
            status = ca_pend_io(MCA_PUT_TIMEOUT);
            
            break;    
                 
            
        case 100: // MCAMON install Monitor or replace MonitorCBString
            
            Hndl = (int)mxGetScalar(prhs[1]); 
            
            // Check if the handle is within range 
            if(Hndl<1 || Hndl>HandlesUsed)
            {   plhs[0]=mxCreateScalarDouble(0);
                mexErrMsgTxt("Invalid Handle");
            }
            
            if(CHNLS[Hndl-1].EVID) // if VID is not NULL - another monitor is already installed - replace MonitorCBString
            {   if(CHNLS[Hndl-1].MonitorCBString) // Free memory for occupied by the old MonitorCBString
                {   mxFree(CHNLS[Hndl-1].MonitorCBString);
                    CHNLS[Hndl-1].MonitorCBString = NULL;
                }
                if(nrhs>2) // Check if the new string is specified
                {   if(mxIsChar(prhs[2]))
                    {   buflen = mxGetM(prhs[2])*mxGetN(prhs[2])+1;
                        CHNLS[Hndl-1].MonitorCBString = (char *)mxMalloc(buflen);
                        mexMakeMemoryPersistent(CHNLS[Hndl-1].MonitorCBString);
                        mxGetString(prhs[2],CHNLS[Hndl-1].MonitorCBString,buflen); 
                    } 
                    else
                        mexErrMsgTxt("Third argument must be a string\n");
                }
                plhs[0]=mxCreateScalarDouble(1);
            }
            else // No monitor is presently installed;
            {   RequestType = dbf_type_to_DBR(ca_field_type(CHNLS[Hndl-1].CHID)); // Closest to the native 
            
            
                if(nrhs>2)
                {   if(mxIsChar(prhs[2]))
                    {   buflen = mxGetM(prhs[2])*mxGetN(prhs[2])+1;
                        CHNLS[Hndl-1].MonitorCBString = (char *)mxMalloc(buflen);
                        mexMakeMemoryPersistent(CHNLS[Hndl-1].MonitorCBString);
                        mxGetString(prhs[2],CHNLS[Hndl-1].MonitorCBString,buflen); 
                    } 
                    else
                        mexErrMsgTxt("Third argument must be a string\n");
                }
                else
                    CHNLS[Hndl-1].MonitorCBString = NULL;  // Set MonitorCBString to NULL so that mcaMonitorEventHandler only copies data to CACHE
            
                // Count argument set to 0 - native count
                status = ca_add_array_event(RequestType,0,CHNLS[Hndl-1].CHID, mcaMonitorEventHandler, &CHNLS[Hndl-1], 0.0, 0.0, 0.0, &(CHNLS[Hndl-1].EVID));
              
                if(status!=ECA_NORMAL)
                {   mexPrintf("ca_add_array_event failed\n");      
                    plhs[0]=mxCreateScalarDouble(0);
                }
                else
                {   ca_poll();
                    plhs[0]=mxCreateScalarDouble(1);
                }
            }   
            break;
            
        case 200: // Clear Monitor MCACLEARMON
            
            Hndl = (int)mxGetScalar(prhs[1]); 
            if(Hndl<1 || Hndl>HandlesUsed)
                mexErrMsgTxt("Invalid Handle");
            if(!CHNLS[Hndl-1].EVID) 
                mexErrMsgTxt("No monitor installed - can not clear");
                
            status = ca_clear_event(CHNLS[Hndl-1].EVID);
            if(status!=ECA_NORMAL)
                mexPrintf("ca_clear_event failed\n");
                
            // Set the EVID pointer to NULL (ca_clear_event dos not do it by itself)
            // to use as a FLAG that no monitors are installed 
            CHNLS[Hndl-1].EVID = NULL;
            // Reset
            CHNLS[Hndl-1].MonitorEventCount = 0;    
            // If there is Callback String - destroy it
            if(CHNLS[Hndl-1].MonitorCBString)
            {   mxFree(CHNLS[Hndl-1].MonitorCBString); 
                CHNLS[Hndl-1].MonitorCBString =NULL;
            }
                
          
        break;
          
        case 300: // MCACACHE Get Cached values of a monitored PV
            for(i=0;i<nrhs-1;i++)
            {   Hndl = (int)mxGetScalar(prhs[1+i]);
                // if(Hndl<1 || Hndl>HandlesUsed || !CHNLS[Hndl-1].CACHE)
                if(Hndl<1 || Hndl>HandlesUsed)
                    plhs[i] = mxCreateDoubleMatrix(0,0,mxREAL);
                else
                    {   plhs[i] = mxDuplicateArray(CHNLS[Hndl-1].CACHE);
                        CHNLS[Hndl-1].MonitorEventCount = 0;
                    }
            }       
          
        break;
        
        case 500: // MCAMON Info on installed monitors
            L = 0;
            HndlArray = (int*)mxCalloc(HandlesUsed,sizeof(int));
            
            for(i=0;i<HandlesUsed;i++) // Count installed monitors
            {   if(CHNLS[i].EVID)
                HndlArray[L++]=i+1;
            }       
            
            if(L>0)
            {   plhs[0] = mxCreateDoubleMatrix(1,L,mxREAL);
                myDblPr = mxGetPr(plhs[0]);
                plhs[1] = mxCreateCellMatrix(1,L);
                for(i=0;i<L;i++)
                {   myDblPr[i] = (double)HndlArray[i];
                    mxSetCell(plhs[1],i,mxCreateString(CHNLS[HndlArray[i]-1].MonitorCBString));
                }
            }
            else
            {   plhs[0] = mxCreateDoubleMatrix(0,0,mxREAL);
                plhs[1] = mxCreateCellMatrix(0,0);
            }
            
        break;
        
        case 510: // MCAMONEVENTS Event count fot monitors
                       
            plhs[0] = mxCreateDoubleMatrix(1,HandlesUsed,mxREAL);
            myDblPr = mxGetPr(plhs[0]);
            for(i=0;i<HandlesUsed;i++)
                myDblPr[i]=(double)(CHNLS[i].MonitorEventCount);
            
        break;
        
        case 1000: // print timeout settings
            plhs[0] = mxCreateDoubleMatrix(3,1,mxREAL);
            mexPrintf("MCA timeout settings\n:");
            mexPrintf("mcaopen\t%f [s]\n",  MCA_SEARCH_TIMEOUT );
            mexPrintf("mcaget\t%f [s]\n",  MCA_GET_TIMEOUT ); 
            mexPrintf("mcaput\t%f [s]\n",  MCA_PUT_TIMEOUT );

            myDblPr = mxGetPr(plhs[0]);
            myDblPr[0] = MCA_SEARCH_TIMEOUT;
            myDblPr[1] = MCA_GET_TIMEOUT;
            myDblPr[2] = MCA_PUT_TIMEOUT;

            
        break;
        
        
        case 1001: // set MCA_SEARCH_TIMEOUT
            // return delay value
            MCA_SEARCH_TIMEOUT = mxGetScalar(prhs[1]);
            plhs[0] = mxCreateScalarDouble(MCA_SEARCH_TIMEOUT);
        break;
        
        case 1002: // set MCA_GET_TIMEOUT
            // return delay value
            MCA_GET_TIMEOUT = mxGetScalar(prhs[1]);
            plhs[0] = mxCreateScalarDouble(MCA_GET_TIMEOUT);
        break;
        
        case 1003: // set MCA_PUT_TIMEOUT
            // return delay value
            MCA_PUT_TIMEOUT = mxGetScalar(prhs[1]);
            plhs[0] = mxCreateScalarDouble(MCA_PUT_TIMEOUT);
        break;

    } 
}
Exemple #14
0
int caget (pv *pvs, int nPvs, OutputT format,
           chtype dbrType, unsigned long reqElems)
{
    unsigned int i;
    int n, result;

    for (n = 0; n < nPvs; n++) {

                                /* Set up pvs structure */
                                /* -------------------- */

                                /* Get natural type and array count */
        pvs[n].nElems  = ca_element_count(pvs[n].chid);
        pvs[n].dbfType = ca_field_type(pvs[n].chid);
        pvs[n].dbrType = dbrType;

                                /* Set up value structures */
        pvs[n].dbrType = dbf_type_to_DBR_TIME(pvs[n].dbfType); /* Use native type */
        if (dbr_type_is_ENUM(pvs[n].dbrType))             /* Enums honour -n option */
        {
            if (enumAsNr) pvs[n].dbrType = DBR_TIME_INT;
            else          pvs[n].dbrType = DBR_TIME_STRING;
        }

        if (reqElems == 0 || pvs[n].nElems < reqElems)    /* Adjust array count */
            pvs[n].reqElems = pvs[n].nElems;
        else
            pvs[n].reqElems = reqElems;

                                /* Issue CA request */
                                /* ---------------- */

        if (ca_state(pvs[n].chid) == cs_conn)
        {
            nConn++;
            pvs[n].onceConnected = 1;
                                   /* Allocate value structure */
            pvs[n].value = calloc(1, dbr_size_n(pvs[n].dbrType, pvs[n].reqElems));
            if(!pvs[n].value){
                fprintf(stderr,"Allocation failed\n");
                exit(1);
            }
            result = ca_array_get(pvs[n].dbrType,
                                  pvs[n].reqElems,
                                  pvs[n].chid,
                                  pvs[n].value);
            pvs[n].status = result;
        } else {
            pvs[n].status = ECA_DISCONN;
        }
    }
    if (!nConn) return 1;              /* No connection? We're done. */

                                /* Wait for completion */
                                /* ------------------- */

    result = ca_pend_io(caTimeout);
    if (result == ECA_TIMEOUT)
        fprintf(stderr, "Read operation timed out: PV data was not read.\n");

                                /* Print the data */
                                /* -------------- */

    for (n = 0; n < nPvs; n++) {

        switch (format) {
        case plain:             /* Emulate old caput behaviour */
            if (pvs[n].reqElems <= 1 && fieldSeparator == ' ') printf("%-30s", pvs[n].name);
            else                                               printf("%s", pvs[n].name);
            printf("%c", fieldSeparator);
        case terse:
            if (pvs[n].status == ECA_DISCONN)
                printf("*** not connected\n");
            else if (pvs[n].status == ECA_NORDACCESS)
                printf("*** no read access\n");
            else if (pvs[n].status != ECA_NORMAL)
                printf("*** CA error %s\n", ca_message(pvs[n].status));
            else if (pvs[n].value == 0)
                printf("*** no data available (timeout)\n");
            else
            {
                if (charArrAsStr && dbr_type_is_CHAR(pvs[n].dbrType) && (reqElems || pvs[n].reqElems > 1)) {
                    dbr_char_t *s = (dbr_char_t*) dbr_value_ptr(pvs[n].value, pvs[n].dbrType);
                    int dlen = epicsStrnEscapedFromRawSize((char*)s, strlen((char*)s));
                    char *d = calloc(dlen+1, sizeof(char));
                    if(!d){
                        fprintf(stderr,"Allocation failed\n");
                        exit(1);
                    }
                    epicsStrnEscapedFromRaw(d, dlen+1, (char*)s, strlen((char*)s));
                    printf("%s", d);
                    free(d);
                } else {
                    if (reqElems || pvs[n].nElems > 1) printf("%lu%c", pvs[n].reqElems, fieldSeparator);
                    for (i=0; i<pvs[n].reqElems; ++i) {
                        if (i) printf ("%c", fieldSeparator);
                        printf("%s", val2str(pvs[n].value, pvs[n].dbrType, i));
                    }
                }
                printf("\n");
            }
            break;
        case all:
            print_time_val_sts(&pvs[n], reqElems);
            break;
        default :
            break;
        }
    }
    return 0;
}
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);
	}
    }
}
Exemple #16
0
PyObject *pv_getter_pvval(pvobject * self, void *closure)
{

	if (self->chanId == NULL || ca_state(self->chanId) != cs_conn
	    || self->buff == NULL) {
		PYCA_ERR("pvval: indef");
	}

	int i;
	dbr_plaintype data;
	int dim = ca_element_count(self->chanId);
	chtype type = xxx_ca_field_type(self->chanId);
	PyObject *returnvalue = NULL;

	/* build the returned tuple */
	if (dim > 1)
		returnvalue = PyTuple_New(dim);

	switch (type) {
	case DBR_STRING:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyString_FromString(data.s));
		} else
			returnvalue =
			    PyString_FromString(((struct dbr_time_string *)
						 self->buff)->value);
		break;
	case DBR_DOUBLE:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyFloat_FromDouble(data.d));
		} else
			returnvalue =
			    PyFloat_FromDouble(((struct dbr_time_double *)
						self->buff)->value);
		break;
	case DBR_LONG:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyLong_FromLong(data.l));
		} else
			returnvalue = PyLong_FromLong(((struct dbr_time_long *)
						       self->buff)->value);
		break;
	case DBR_SHORT:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyInt_FromLong(data.i));
		} else
			returnvalue = PyInt_FromLong(((struct dbr_time_short *)
						      self->buff)->value);
		break;
	case DBR_CHAR:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyInt_FromLong(data.c));
		} else
			returnvalue = PyInt_FromLong(((struct dbr_time_char *)
						      self->buff)->value);
		break;
	case DBR_ENUM:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyInt_FromLong(data.e));
		} else
			returnvalue = PyInt_FromLong(((struct dbr_time_enum *)
						      self->buff)->value);
		break;
	case DBR_FLOAT:
		if (dim > 1)
			for (i = 0; i < dim; i++) {
				ca_module_utilsextract(self->buff,
						       xxx_ca_field_type
						       (self->chanId), i,
						       &data);
				PyTuple_SetItem(returnvalue, i,
						PyFloat_FromDouble(data.f));
		} else
			returnvalue =
			    PyFloat_FromDouble(((struct dbr_time_float *)
						self->buff)->value);
		break;
	default:
		PYCA_ERR("pvval: invalid");
		break;
	}

	return returnvalue;
}
Exemple #17
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);
}
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);
	}
    }
}
Exemple #19
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;
}
Exemple #20
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);
}
Exemple #21
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 pvInfoWriteInfo(void)
{
    time_t now;
    struct tm *tblock;
    char timeStampStr[TIME_STRING_MAX];
    Record *pR;
    chid chId;
    char *descVal;
#if defined(DBR_CLASS_NAME) && DO_RTYP
    char *rtypVal;
#endif
    DlElement *pE;
    char *elementType;
    static char noType[]="Unknown";
    struct dbr_time_string timeVal;
    char string[1024];     /* Danger: Fixed length */
    XmTextPosition curpos = 0;
    int i, j;

  /* Free the timeout */
    if(pvInfoTimerOn) {
	XtRemoveTimeOut(pvInfoTimeoutId);
	pvInfoTimerOn = False;
    }

  /* Just clean up and abort if we get called with no pvInfo
   *   (Shouldn't happen) */
    if(!pvInfo) return;

  /* Get timestamp */
    time(&now);
    tblock = localtime(&now);
    strftime(timeStampStr, TIME_STRING_MAX, STRFTIME_FORMAT"\n", tblock);
    timeStampStr[TIME_STRING_MAX-1]='\0';

  /* Get element type */
    pE = pvInfoElement;
    if(pE &&
      pE->type >= MIN_DL_ELEMENT_TYPE && pE->type <= MAX_DL_ELEMENT_TYPE) {
	elementType=elementType(pE->type);
    } else {
	elementType=noType;
    }

  /* Heading */
    sprintf(string, "           PV Information\n\nObject: %s\n%s\n",
      elementType, timeStampStr);
    XmTextSetInsertionPosition(pvInfoMessageBox, 0);
    XmTextSetString(pvInfoMessageBox, string);
    curpos+=strlen(string);

  /* Loop over the records to print information */
    for(i=0; i < nPvInfoPvs; i++) {
      /* Check for a valid record */
	if(!pvInfo[i].pvOk) continue;

	chId = pvInfo[i].pvChid;
	timeVal = pvInfo[i].timeVal;
	pR = pvInfo[i].record;

      /* Name */
	sprintf(string, "%s\n"
	  "======================================\n",
	  ca_name(chId));
      /* DESC */
	descVal = pvInfo[i].descVal;
	if(pvInfo[i].descOk && descVal) {
	    sprintf(string, "%sDESC: %s\n", string, descVal);
	} else {
	    sprintf(string, "%sDESC: %s\n", string, NOT_AVAILABLE);
	}
	if(pvInfo[i].descChid) ca_clear_channel(pvInfo[i].descChid);
#if defined(DBR_CLASS_NAME) && DO_RTYP
      /* RTYP */
	rtypVal = pvInfo[i].rtypVal;
	if(pvInfo[i].rtypOk && rtypVal && *rtypVal) {
	    sprintf(string, "%sRTYP: %s\n", string, rtypVal);
	} else {
	    sprintf(string, "%sRTYP: %s\n", string, NOT_AVAILABLE);
	}
#endif
      /* Items from chid */
	sprintf(string, "%sTYPE: %s\n", string,
	  dbf_type_to_text(ca_field_type(chId)));
      /* ca_element_count is defined differently in 3.14 vs. 3.13 */
	sprintf(string, "%sCOUNT: %lu\n", string,
	  (unsigned long)ca_element_count(chId));
	sprintf(string, "%sACCESS: %s%s\n", string,
	  ca_read_access(chId)?"R":"", ca_write_access(chId)?"W":"");
	sprintf(string, "%sIOC: %s\n", string, ca_host_name(chId));
	if(timeVal.value) {
	    char fracPart[10];

	  /* Do the value */
	    if(ca_element_count(chId) == 1) {
		sprintf(string, "%sVALUE: %s\n", string,
		  timeVal.value);
	    } else {
		sprintf(string, "%sFIRST VALUE: %s\n", string,
		  timeVal.value);
	    }
	  /* Convert the seconds part of the timestamp to UNIX time */
	    now = timeVal.stamp.secPastEpoch + 631152000ul;
	    tblock = localtime(&now);
	    strftime(timeStampStr, TIME_STRING_MAX, "%a %b %d, %Y %H:%M:%S",
	      tblock);
	    timeStampStr[TIME_STRING_MAX-1]='\0';
	  /* Get the fractional part.  This assumes strftime truncates
             seconds rather than rounding them, which seems to be the
             case. */
	    sprintf(fracPart, "%09d",timeVal.stamp.nsec);
	  /* Truncate to 3 figures */
	    fracPart[3]='\0';
	    sprintf(timeStampStr,"%s.%s", timeStampStr, fracPart);
	    timeStampStr[TIME_STRING_MAX-1]='\0';
	    sprintf(string, "%sSTAMP: %s\n", string, timeStampStr);
#if DEBUG_TIMESTAMP
	  /* This prints 9 significant figures and requires 3.13 base */
	    {
		char tsTxt[32];
		sprintf(string,"%sSTAMP: %s\n",string,
		  tsStampToText(&timeVal.stamp,TS_TEXT_MONDDYYYY,tsTxt));
	    }
#endif
	} else {
	    sprintf(string, "%sVALUE: %s\n", string, NOT_AVAILABLE);
	    sprintf(string, "%sSTAMP: %s\n", string, NOT_AVAILABLE);
	}
	XmTextInsert(pvInfoMessageBox, curpos, string);
	curpos+=strlen(string);

      /* Alarms */
	switch(pR->severity) {
	case NO_ALARM:
	    sprintf(string, "ALARM: NO\n");
	    break;
	case MINOR_ALARM:
	    sprintf(string, "ALARM: MINOR\n");
	    break;
	case MAJOR_ALARM:
	    sprintf(string, "ALARM: MAJOR\n");
	    break;
	case INVALID_ALARM:
	    sprintf(string, "ALARM: INVALID\n");
	    break;
	default:
	    sprintf(string, "ALARM: Unknown\n");
	    break;
	}
	XmTextInsert(pvInfoMessageBox, curpos, string);
	curpos+=strlen(string);

      /* Items from record */
	sprintf(string, "\n");
	switch(ca_field_type(chId)) {
        case DBF_STRING:
	    break;
        case DBF_ENUM:
	    sprintf(string, "%sSTATES: %d\n",
	      string, (int)(pR->hopr+1.1));
	  /* KE: Bad way to use a double */
	    if(pR->hopr) {
		for (j=0; j <= pR->hopr; j++) {
		    sprintf(string, "%sSTATE %2d: %s\n",
		      string, j, pR->stateStrings[j]);
		}
	    }
	    break;
        case DBF_CHAR:
        case DBF_INT:
        case DBF_LONG:
	    sprintf(string, "%sHOPR: %g  LOPR: %g\n",
	      string, pR->hopr, pR->lopr);
	    break;
        case DBF_FLOAT:
        case DBF_DOUBLE:
	    if(pR->precision >= 0 && pR->precision <= 17) {
		sprintf(string, "%sPRECISION: %d\n",
		  string, pR->precision);
	    } else {
		sprintf(string, "%sPRECISION: %d [Bad Value]\n",
		  string, pR->precision);
	    }
	    sprintf(string, "%sHOPR: %g  LOPR: %g\n",
	      string, pR->hopr, pR->lopr);
	    break;
        default:
	    break;
	}
	sprintf(string, "%s\n", string);
	XmTextInsert(pvInfoMessageBox, curpos, string);
	curpos+=strlen(string);
    }

  /* Pop it up unless we have left EXECUTE mode */
    if(globalDisplayListTraversalMode == DL_EXECUTE) {
	XtSetSensitive(pvInfoS, True);
	XtPopup(pvInfoS, XtGrabNone);
    }

  /* Free space */
    if(pvInfo) free((char *)pvInfo);
    pvInfo = NULL;
    pvInfoElement = NULL;
}