/* * 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; }
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)); }
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; }
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); } }
/* * 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()); } }
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" : ""); } } }
/* * 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; }
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; } }
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); } } }
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; }
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); } } }
/* * 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 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); }
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; }