static void event_handler (evargs args) { pv* ppv = args.usr; ppv->status = args.status; if (args.status == ECA_NORMAL) { ppv->dbrType = args.type; ppv->value = calloc(1, dbr_size_n(args.type, args.count)); memcpy(ppv->value, args.dbr, dbr_size_n(args.type, args.count)); ppv->nElems = args.count; nRead++; } }
void event_handler (evargs args) { pv* pv = args.usr; pv->status = args.status; if (args.status == ECA_NORMAL) { pv->dbrType = args.type; memcpy(pv->value, args.dbr, dbr_size_n(args.type, args.count)); print_time_val_sts(pv, pv->reqElems); fflush(stdout); } }
// extra effort taken here to not hold the lock when calling the callback void dbContextReadNotifyCache::callReadNotify ( epicsGuard < epicsMutex > & guard, struct dbChannel * dbch, unsigned type, unsigned long count, cacReadNotify & notify ) { guard.assertIdenticalMutex ( _mutex ); if ( type > INT_MAX ) { notify.exception ( guard, ECA_BADTYPE, "type code out of range (high side)", type, count ); return; } if ( dbChannelElements(dbch) < 0 ) { notify.exception ( guard, ECA_BADCOUNT, "database has negetive element count", type, count); return; } if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) { notify.exception ( guard, ECA_BADCOUNT, "element count out of range (high side)", type, count); return; } unsigned long size = dbr_size_n ( type, count ); privateAutoDestroyPtr ptr ( _allocator, size ); int status; { epicsGuardRelease < epicsMutex > unguard ( guard ); status = dbChannel_get ( dbch, static_cast <int> ( type ), ptr.get (), static_cast <long> ( count ), 0 ); } if ( status ) { notify.exception ( guard, ECA_GETFAIL, "db_get_field() completed unsuccessfuly", type, count ); } else { notify.completion ( guard, type, count, ptr.get () ); } }
void syncGroupReadNotify::completion ( epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count, const void * pData ) { if ( this->magic != CASG_MAGIC ) { this->sg.printFormated ( "cac: sync group io_complete(): bad sync grp op magic number?\n" ); return; } if ( this->pValue ) { size_t size = dbr_size_n ( type, count ); memcpy ( this->pValue, pData, size ); } this->sg.completionNotify ( guard, *this ); this->idIsValid = false; this->ioComplete = true; }
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); } }
void comQueSend::insertRequestWithPayLoad ( ca_uint16_t request, unsigned dataType, arrayElementCount nElem, ca_uint32_t cid, ca_uint32_t requestDependent, const void * pPayload, bool v49Ok ) { if ( INVALID_DB_REQ ( dataType ) ) { throw cacChannel::badType (); } if ( dataType >= comQueSendCopyDispatchSize ) { throw cacChannel::badType(); } ca_uint32_t size = 0u; ca_uint32_t payloadSize = 0u; if ( nElem == 1 ) { if ( dataType == DBR_STRING ) { const char * pStr = static_cast < const char * > ( pPayload ); size = strlen ( pStr ) + 1u; if ( size > MAX_STRING_SIZE ) { throw cacChannel::outOfBounds(); } payloadSize = CA_MESSAGE_ALIGN ( size ); this->insertRequestHeader ( request, payloadSize, static_cast <ca_uint16_t> ( dataType ), nElem, cid, requestDependent, v49Ok ); this->pushString ( pStr, size ); } else { size = dbr_size[dataType]; payloadSize = CA_MESSAGE_ALIGN ( size ); this->insertRequestHeader ( request, payloadSize, static_cast <ca_uint16_t> ( dataType ), nElem, cid, requestDependent, v49Ok ); ( this->*dbrCopyScalar [dataType] ) ( pPayload ); } } else { arrayElementCount maxBytes; if ( v49Ok ) { maxBytes = 0xffffffff; } else { maxBytes = MAX_TCP - sizeof ( caHdr ); } arrayElementCount maxElem = ( maxBytes - sizeof (dbr_double_t) - dbr_size[dataType] ) / dbr_value_size[dataType]; if ( nElem >= maxElem ) { throw cacChannel::outOfBounds(); } // the above checks verify that the total size // is lest that 0xffffffff size = static_cast < ca_uint32_t > ( dbr_size_n ( dataType, nElem ) ); // X aCC 392 payloadSize = CA_MESSAGE_ALIGN ( size ); this->insertRequestHeader ( request, payloadSize, static_cast <ca_uint16_t> ( dataType ), static_cast < ca_uint32_t > ( nElem ), cid, requestDependent, v49Ok ); ( this->*dbrCopyVector [dataType] ) ( pPayload, nElem ); } // set pad bytes to nill unsigned padSize = payloadSize - size; if ( padSize ) { this->pushString ( cacNillBytes, payloadSize - size ); } }
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; }
static void getChanInfo( struct event_handler_args arg) { Channel *chan; // Commented out to avoid comparison warning (David Chevrier, Aug 25 2011) //int bytecount; unsigned int bytecount; InfoBuf_t InfoBuf; chan = arg.usr; if( chan == NULL) return; /* make sure we can accept any new data, even if it's in a format * we don't know */ bytecount = dbr_size_n(arg.type, arg.count); if( bytecount > sizeof InfoBuf) return; memcpy( (void*)&InfoBuf, arg.dbr, bytecount ); switch( ca_field_type(chan->chan_id) ) { /* DBF_INT: note: this is identical to DBF_SHORT */ case DBF_SHORT: chan->cg.lopr = InfoBuf.ca_short.lower_disp_limit; chan->cg.hopr = InfoBuf.ca_short.upper_disp_limit; strncpy(chan->cg.units, InfoBuf.ca_short.units, MAX_UNITS_SIZE); break; case DBF_FLOAT: chan->cg.lopr = InfoBuf.ca_float.lower_disp_limit; chan->cg.hopr = InfoBuf.ca_float.upper_disp_limit; strncpy(chan->cg.units, InfoBuf.ca_float.units, MAX_UNITS_SIZE); chan->cg.prec = InfoBuf.ca_float.precision; break; case DBF_ENUM: { int i; chan->cg.lopr = 0; chan->cg.hopr = InfoBuf.ca_enum.no_str - 1; for(i=0; i < MAX_ENUM_STATES; i++) { if( chan->cg.states[i] == NULL) continue; free( chan->cg.states[i]); chan->cg.states[i] = NULL; } for(i=0; i <= chan->cg.hopr; i++) { chan->cg.states[i] = strdup(InfoBuf.ca_enum.strs[i] ); } } break; case DBF_CHAR: chan->cg.lopr = InfoBuf.ca_char.lower_disp_limit; chan->cg.hopr = InfoBuf.ca_char.upper_disp_limit; strncpy(chan->cg.units, InfoBuf.ca_char.units, MAX_UNITS_SIZE); break; case DBF_LONG: chan->cg.lopr = InfoBuf.ca_long.lower_disp_limit; chan->cg.hopr = InfoBuf.ca_long.upper_disp_limit; strncpy(chan->cg.units, InfoBuf.ca_long.units, MAX_UNITS_SIZE); break; case DBF_DOUBLE: chan->cg.lopr = InfoBuf.ca_double.lower_disp_limit; chan->cg.hopr = InfoBuf.ca_double.upper_disp_limit; strncpy(chan->cg.units, InfoBuf.ca_double.units, MAX_UNITS_SIZE); chan->cg.prec = InfoBuf.ca_double.precision; DEBUGP printf("read precision %d units %s\n", chan->cg.prec, chan->cg.units); break; default: 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); } } }
static void medmUpdateGraphicalInfoCb(struct event_handler_args args) { int nBytes; int i; Channel *pCh = (Channel *)ca_puser(args.chid); Record *pr; /* Increment the event counter */ caTask.caEventCount++; /* Check for valid values */ /* Same as for updateChannelCb */ /* Don't need to check for read access, checking ECA_NORMAL is enough */ if(globalDisplayListTraversalMode != DL_EXECUTE) return; if(args.status != ECA_NORMAL) return; if(!args.dbr) { medmPostMsg(0,"medmUpdateGraphicalInfoCb: Invalid data [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } if(!pCh || !pCh->chid || !pCh->pr) { medmPostMsg(0,"medmUpdateGraphicalInfoCb: Invalid channel information [%s]\n", ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } if(pCh->chid != args.chid) { medmPostMsg(0,"medmUpdateGraphicalInfoCb: chid from args [%x] " "does not match chid from channel [%x]\n" " [%s]\n", args.chid, pCh->chid, ca_name(args.chid)?ca_name(args.chid):"Name Unknown"); return; } pr = pCh->pr; /* Copy the information to the Channel struct */ nBytes = dbr_size_n(args.type, args.count); memcpy((void *)&(pCh->info),args.dbr,nBytes); /* Handle hopr, lopr, and precision */ switch (ca_field_type(args.chid)) { case DBF_STRING: pr->value = 0.0; pr->hopr = 0.0; pr->lopr = 0.0; pr->precision = 0; break; case DBF_ENUM: pr->value = (double) pCh->info.e.value; pr->hopr = (double) pCh->info.e.no_str - 1.0; pr->lopr = 0.0; pr->precision = 0; for (i = 0; i < pCh->info.e.no_str; i++) { pr->stateStrings[i] = pCh->info.e.strs[i]; } break; case DBF_CHAR: pr->value = (double) pCh->info.c.value; pr->hopr = (double) pCh->info.c.upper_disp_limit; pr->lopr = (double) pCh->info.c.lower_disp_limit; pr->precision = 0; break; case DBF_INT: pr->value = (double) pCh->info.i.value; pr->hopr = (double) pCh->info.i.upper_disp_limit; pr->lopr = (double) pCh->info.i.lower_disp_limit; pr->precision = 0; break; case DBF_LONG: pr->value = (double) pCh->info.l.value; pr->hopr = (double) pCh->info.l.upper_disp_limit; pr->lopr = (double) pCh->info.l.lower_disp_limit; pr->precision = 0; break; case DBF_FLOAT: pr->value = (double) pCh->info.f.value; pr->hopr = (double) pCh->info.f.upper_disp_limit; pr->lopr = (double) pCh->info.f.lower_disp_limit; pr->precision = pCh->info.f.precision; break; case DBF_DOUBLE: pr->value = (double) pCh->info.d.value; pr->hopr = (double) pCh->info.d.upper_disp_limit; pr->lopr = (double) pCh->info.d.lower_disp_limit; pr->precision = pCh->info.f.precision; break; default: medmPostMsg(0,"medmUpdateGraphicalInfoCb: Unknown data type\n"); return; } /* Adjust the precision */ if(pr->precision < 0) { medmPostMsg(0,"medmUpdateGraphicalInfoCb: " "pv = \"%s\" precision = %d\n", ca_name(pCh->chid), pr->precision); pr->precision = 0; } else if(pr->precision > 17) { medmPostMsg(1,"medmUpdateGraphicalInfoCb: " "pv = \"%s\" precision = %d\n", ca_name(pCh->chid), pr->precision); pr->precision = 17; } /* Call the record's graphical info callback or its update value callback */ if(pr->updateGraphicalInfoCb) { pr->updateGraphicalInfoCb((XtPointer)pr); } else if(pr->updateValueCb) { pr->updateValueCb((XtPointer)pr); } }