/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvAccessCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #include #include #include #include #include #include #include #include #include #include #include "caChannel.h" #define epicsExportSharedSymbols #include "dbdToPv.h" using namespace epics::pvData; using std::string; using std::ostringstream; namespace epics { namespace pvAccess { namespace ca { #define CA_PRIORITY 50 static void enumChoicesHandler(struct event_handler_args args) { DbdToPv *dbdToPv = static_cast(args.usr); dbdToPv->getChoicesDone(args); } static void description_connection_handler(struct connection_handler_args args) { DbdToPv *dbdToPv = static_cast(ca_puser(args.chid)); dbdToPv->descriptionConnected(args); } static void descriptionHandler(struct event_handler_args args) { DbdToPv *dbdToPv = static_cast(args.usr); dbdToPv->getDescriptionDone(args); } DbdToPvPtr DbdToPv::create( CAChannelPtr const & caChannel, PVStructurePtr const & pvRequest, IOType ioType) { DbdToPvPtr dbdToPv(new DbdToPv(ioType)); dbdToPv->activate(caChannel,pvRequest); return dbdToPv; } DbdToPv::DbdToPv(IOType ioType) : ioType(ioType), fieldRequested(false), alarmRequested(false), timeStampRequested(false), displayRequested(false), controlRequested(false), valueAlarmRequested(false), isArray(false), firstTime(true), choicesValid(false), waitForChoicesValid(false), caValueType(-1), caRequestType(-1), maxElements(0) { caTimeStamp.secPastEpoch = 0; caTimeStamp.nsec = 0; } static ScalarType dbr2ST[] = { pvString, // DBR_STRING = 0 pvShort, // DBR_SHORT. DBR_INT = 1 pvFloat, // DBR_FLOAT = 2 static_cast(-1), // DBR_ENUM = 3 pvByte, // DBR_CHAR = 4 pvInt, // DBR_LONG = 5 pvDouble // DBR_DOUBLE = 6 }; static chtype getDbrType(const ScalarType scalarType) { switch(scalarType) { case pvString : return DBR_STRING; case pvByte : return DBR_CHAR; case pvShort : return DBR_SHORT; case pvInt : return DBR_LONG; case pvFloat : return DBR_FLOAT; case pvDouble : return DBR_DOUBLE; default: break; } throw std::runtime_error("getDbr: illegal scalarType"); } void DbdToPv::activate( CAChannelPtr const & caChannel, PVStructurePtr const & pvRequest) { chid channelID = caChannel->getChannelID(); chtype channelType = ca_field_type(channelID); caValueType = (channelType==DBR_ENUM ? DBR_ENUM : getDbrType(dbr2ST[channelType])); if(!pvRequest) { string mess(caChannel->getChannelName()); mess += " DbdToPv::activate pvRequest is null"; throw std::runtime_error(mess); } PVStructurePtr fieldPVStructure; if(pvRequest->getPVFields().size()==0) { fieldPVStructure = pvRequest; } else { fieldPVStructure = pvRequest->getSubField("field"); } if(!fieldPVStructure) { ostringstream mess; mess << caChannel->getChannelName() << " DbdToPv::activate illegal pvRequest " << pvRequest; throw std::runtime_error(mess.str()); } if(fieldPVStructure->getPVFields().size()==0) { fieldRequested = true; alarmRequested = true; timeStampRequested = true; displayRequested = true; controlRequested = true; valueAlarmRequested = true; } else { if(fieldPVStructure->getSubField("value")) fieldRequested = true; if(fieldPVStructure->getSubField("alarm")) alarmRequested = true; if(fieldPVStructure->getSubField("timeStamp")) timeStampRequested = true; if(fieldPVStructure->getSubField("display")) displayRequested = true; if(fieldPVStructure->getSubField("control")) controlRequested = true; if(fieldPVStructure->getSubField("valueAlarm")) valueAlarmRequested = true; } switch(ioType) { case getIO : break; case putIO: alarmRequested = false; timeStampRequested = false; displayRequested = false; controlRequested = false; valueAlarmRequested = false; break; case monitorIO: break; } StandardFieldPtr standardField = getStandardField(); if(channelType==DBR_ENUM) { displayRequested = false; controlRequested = false; valueAlarmRequested = false; string properties; if(alarmRequested && timeStampRequested) { properties += "alarm,timeStamp"; } else if(timeStampRequested) { properties += "timeStamp"; } else if(alarmRequested) { properties += "alarm"; } caRequestType = (properties.size()==0 ? DBR_ENUM : DBR_TIME_ENUM); structure = standardField->enumerated(properties); int result = ca_array_get_callback(DBR_GR_ENUM, 1, channelID, enumChoicesHandler, this); if (result == ECA_NORMAL) result = ca_flush_io(); if (result != ECA_NORMAL) { string mess(caChannel->getChannelName()); mess += " DbdToPv::activate getting enum cnoices "; mess += ca_message(result); throw std::runtime_error(mess); } // NOTE: we do not wait here, since all subsequent request (over TCP) is serialized // and will guarantee that enumChoicesHandler is called first return; } maxElements = ca_element_count(channelID); if(maxElements!=1) isArray = true; if(isArray) { controlRequested = false; valueAlarmRequested = false; } ScalarType st = dbr2ST[channelType]; if(st==pvString) { displayRequested = false; controlRequested = false; valueAlarmRequested = false; } if(controlRequested || displayRequested || valueAlarmRequested) timeStampRequested = false; FieldCreatePtr fieldCreate(FieldCreate::getFieldCreate()); PVDataCreatePtr pvDataCreate(PVDataCreate::getPVDataCreate()); FieldBuilderPtr fieldBuilder(fieldCreate->createFieldBuilder()); if(fieldRequested) { if(isArray) { fieldBuilder->addArray("value",st); } else { fieldBuilder->add("value",st); } } if(alarmRequested) fieldBuilder->add("alarm",standardField->alarm()); if(timeStampRequested) fieldBuilder->add("timeStamp",standardField->timeStamp()); if(displayRequested) fieldBuilder->add("display",standardField->display()); if(controlRequested) fieldBuilder->add("control",standardField->control()); if(valueAlarmRequested) { switch(st) { case pvByte: fieldBuilder->add("valueAlarm",standardField->byteAlarm()); break; case pvShort: fieldBuilder->add("valueAlarm",standardField->shortAlarm()); break; case pvInt: fieldBuilder->add("valueAlarm",standardField->intAlarm()); break; case pvFloat: fieldBuilder->add("valueAlarm",standardField->floatAlarm()); break; case pvDouble: fieldBuilder->add("valueAlarm",standardField->doubleAlarm()); break; default: throw std::runtime_error("DbDToPv::activate: bad type"); } } structure = fieldBuilder->createStructure(); caRequestType = caValueType; if(displayRequested || controlRequested || valueAlarmRequested) { caRequestType = dbf_type_to_DBR_CTRL(caValueType); } else if(timeStampRequested || alarmRequested) { caRequestType = dbf_type_to_DBR_TIME(caValueType); } else { caRequestType = dbf_type_to_DBR(caValueType); } if(displayRequested) { chid channelID; string name(caChannel->getChannelName() + ".DESC"); int result = ca_create_channel(name.c_str(), description_connection_handler, this, CA_PRIORITY, // TODO mapping &channelID); if (result == ECA_NORMAL) result = ca_flush_io(); if (result != ECA_NORMAL) { string mess(caChannel->getChannelName()); mess += " DbdToPv::activate getting description "; mess += ca_message(result); throw std::runtime_error(mess); } } } void DbdToPv::descriptionConnected(struct connection_handler_args args) { if (args.op != CA_OP_CONN_UP) return; ca_array_get_callback(DBR_STRING, 0, args.chid, descriptionHandler, this); } void DbdToPv::getDescriptionDone(struct event_handler_args &args) { if(args.status!=ECA_NORMAL) return; const dbr_string_t *value = static_cast(dbr_value_ptr(args.dbr,DBR_STRING)); description = string(*value); ca_clear_channel(args.chid); } void DbdToPv::getChoicesDone(struct event_handler_args &args) { if(args.status!=ECA_NORMAL) { string message("DbdToPv::getChoicesDone ca_message "); message += ca_message(args.status); throw std::runtime_error(message); } const dbr_gr_enum* dbr_enum_p = static_cast(args.dbr); size_t num = dbr_enum_p->no_str; choices.reserve(num); for(size_t i=0; istrs[i][0])); bool signal = false; { Lock lock(choicesMutex); choicesValid = true; if(waitForChoicesValid) signal = true; } if(signal) choicesEvent.signal(); } chtype DbdToPv::getRequestType() { if(caRequestType<0) { throw std::runtime_error("DbDToPv::getRequestType: bad type"); } return caRequestType; } PVStructurePtr DbdToPv::createPVStructure() { return getPVDataCreate()->createPVStructure(structure); } template void copy_DBRScalar(const void * dbr, PVScalar::shared_pointer const & pvScalar) { std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvScalar); value->put(static_cast(dbr)[0]); } template void copy_DBRScalarArray(const void * dbr, unsigned count, PVScalarArray::shared_pointer const & pvArray) { std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvArray); typename pvT::svector temp(value->reuse()); temp.resize(count); std::copy( static_cast(dbr), static_cast(dbr) + count, temp.begin()); value->replace(freeze(temp)); } template void get_DBRControl(const void * dbr, double *upper_ctrl_limit,double *lower_ctrl_limit) { *upper_ctrl_limit = static_cast(dbr)->upper_ctrl_limit; *lower_ctrl_limit = static_cast(dbr)->lower_ctrl_limit; } template void get_DBRDisplay( const void * dbr, double *upper_disp_limit,double *lower_disp_limit,string *units) { *upper_disp_limit = static_cast(dbr)->upper_disp_limit; *lower_disp_limit = static_cast(dbr)->lower_disp_limit; *units = static_cast(dbr)->units; } template void get_DBRValueAlarm( const void * dbr, double *upper_alarm_limit,double *upper_warning_limit, double *lower_warning_limit,double *lower_alarm_limit) { *upper_alarm_limit = static_cast(dbr)->upper_alarm_limit; *upper_warning_limit = static_cast(dbr)->upper_warning_limit; *lower_warning_limit = static_cast(dbr)->lower_warning_limit; *lower_alarm_limit = static_cast(dbr)->lower_alarm_limit; } Status DbdToPv::getFromDBD( PVStructurePtr const & pvStructure, BitSet::shared_pointer const & bitSet, struct event_handler_args &args) { if(args.status!=ECA_NORMAL) { Status errorStatus(Status::STATUSTYPE_ERROR, string(ca_message(args.status))); return errorStatus; } if(fieldRequested) { void * value = dbr_value_ptr(args.dbr,caRequestType); if(isArray) { long count = args.count; PVScalarArrayPtr pvValue = pvStructure->getSubField("value"); switch(caValueType) { case DBR_STRING: { const dbr_string_t *dbrval = static_cast(value); PVStringArrayPtr pvValue = pvStructure->getSubField("value"); PVStringArray::svector arr(pvValue->reuse()); arr.resize(count); std::copy(dbrval, dbrval + count, arr.begin()); pvValue->replace(freeze(arr)); break; } case DBR_CHAR: copy_DBRScalarArray(value,count,pvValue); break; case DBR_SHORT: copy_DBRScalarArray(value,count,pvValue); break; case DBR_LONG: copy_DBRScalarArray(value,count,pvValue); break; case DBR_FLOAT: copy_DBRScalarArray(value,count,pvValue); break; case DBR_DOUBLE: copy_DBRScalarArray(value,count,pvValue); break; default: Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error")); return errorStatus; } } else { PVScalarPtr pvValue = pvStructure->getSubField("value"); switch(caValueType) { case DBR_ENUM: { const dbr_enum_t *dbrval = static_cast(value); PVIntPtr value = pvStructure->getSubField("value.index"); value->put(*dbrval); PVStringArrayPtr pvChoices = pvStructure->getSubField("value.choices"); if(pvChoices->getLength()==0) { ConvertPtr convert = getConvert(); size_t n = choices.size(); pvChoices->setLength(n); convert->fromStringArray(pvChoices,0,n,choices,0); bitSet->set(pvStructure->getSubField("value")->getFieldOffset()); } else { bitSet->set(value->getFieldOffset()); } break; } case DBR_STRING: copy_DBRScalar(value,pvValue); break; case DBR_CHAR: copy_DBRScalar(value,pvValue); break; case DBR_SHORT: copy_DBRScalar(value,pvValue); break; case DBR_LONG: copy_DBRScalar(value,pvValue); break; case DBR_FLOAT: copy_DBRScalar(value,pvValue); break; case DBR_DOUBLE: copy_DBRScalar(value,pvValue); break; default: Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error")); return errorStatus; } } if(caValueType!=DBR_ENUM) { bitSet->set(pvStructure->getSubField("value")->getFieldOffset()); } } if(alarmRequested) { // Note that status and severity are aways the first two members of DBR_ const dbr_sts_string *data = static_cast(args.dbr); dbr_short_t status = data->status; dbr_short_t severity = data->severity; bool statusChanged = false; bool severityChanged = false; PVStructurePtr pvAlarm(pvStructure->getSubField("alarm")); PVIntPtr pvSeverity(pvAlarm->getSubField("severity")); if(caAlarm.severity!=severity) { caAlarm.severity = severity; pvSeverity->put(severity); severityChanged = true; } PVStringPtr pvMessage(pvAlarm->getSubField("message")); PVIntPtr pvStatus(pvAlarm->getSubField("status")); if(caAlarm.status!=status) { caAlarm.status = status; pvStatus->put(status); string message("UNKNOWN STATUS"); if(status<=ALARM_NSTATUS) message = string(epicsAlarmConditionStrings[status]); pvMessage->put(message); statusChanged = true; } if(statusChanged&&severityChanged) { bitSet->set(pvAlarm->getFieldOffset()); } else if(severityChanged) { bitSet->set(pvSeverity->getFieldOffset()); } else if(statusChanged) { bitSet->set(pvStatus->getFieldOffset()); bitSet->set(pvMessage->getFieldOffset()); } } if(timeStampRequested) { // Note that epicsTimeStamp always follows status and severity const dbr_time_string *data = static_cast(args.dbr); epicsTimeStamp stamp = data->stamp; PVStructurePtr pvTimeStamp(pvStructure->getSubField("timeStamp")); if(caTimeStamp.secPastEpoch!=stamp.secPastEpoch) { caTimeStamp.secPastEpoch = stamp.secPastEpoch; PVLongPtr pvSeconds(pvTimeStamp->getSubField("secondsPastEpoch")); pvSeconds->put(stamp.secPastEpoch+posixEpochAtEpicsEpoch); bitSet->set(pvSeconds->getFieldOffset()); } if(caTimeStamp.nsec!=stamp.nsec) { caTimeStamp.secPastEpoch = stamp.secPastEpoch; PVIntPtr pvNano(pvTimeStamp->getSubField("nanoseconds")); pvNano->put(stamp.nsec); bitSet->set(pvNano->getFieldOffset()); } } if(controlRequested) { double upper_ctrl_limit = 0.0; double lower_ctrl_limit = 0.0; switch(caRequestType) { case DBR_CTRL_CHAR: get_DBRControl(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break; case DBR_CTRL_SHORT: get_DBRControl(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break; case DBR_CTRL_LONG: get_DBRControl(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break; case DBR_CTRL_FLOAT: get_DBRControl(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break; case DBR_CTRL_DOUBLE: get_DBRControl(args.dbr,&upper_ctrl_limit,&lower_ctrl_limit); break; default : throw std::runtime_error("DbdToPv::getFromDBD logic error"); } PVStructurePtr pvControl(pvStructure->getSubField("control")); if(caControl.upper_ctrl_limit!=upper_ctrl_limit) { caControl.upper_ctrl_limit = upper_ctrl_limit; PVDoublePtr pv = pvControl->getSubField("limitHigh"); pv->put(upper_ctrl_limit); bitSet->set(pv->getFieldOffset()); } if(caControl.lower_ctrl_limit!=lower_ctrl_limit) { caControl.lower_ctrl_limit = lower_ctrl_limit; PVDoublePtr pv = pvControl->getSubField("limitLow"); pv->put(lower_ctrl_limit); bitSet->set(pv->getFieldOffset()); } } if(displayRequested) { string units; string format; double upper_disp_limit = 0.0; double lower_disp_limit = 0.0; switch(caRequestType) { case DBR_CTRL_CHAR: get_DBRDisplay(args.dbr,&upper_disp_limit,&lower_disp_limit,&units); format = "I4"; break; case DBR_CTRL_SHORT: get_DBRDisplay(args.dbr,&upper_disp_limit,&lower_disp_limit,&units); format = "I6"; break; case DBR_CTRL_LONG: get_DBRDisplay(args.dbr,&upper_disp_limit,&lower_disp_limit,&units); format = "I12"; break; case DBR_CTRL_FLOAT: get_DBRDisplay(args.dbr,&upper_disp_limit,&lower_disp_limit,&units); { const dbr_ctrl_float *data = static_cast(args.dbr); int prec = data->precision; ostringstream s; s << "F" << prec + 6 << "." << prec; format = s.str(); } break; case DBR_CTRL_DOUBLE: get_DBRDisplay(args.dbr,&upper_disp_limit,&lower_disp_limit,&units); { const dbr_ctrl_double *data = static_cast(args.dbr); int prec = data->precision; ostringstream s; s << "F" << prec + 6 << "." << prec; format = s.str(); } break; default : throw std::runtime_error("DbdToPv::getFromDBD logic error"); } PVStructurePtr pvDisplay(pvStructure->getSubField("display")); if(caDisplay.lower_disp_limit!=lower_disp_limit) { caDisplay.lower_disp_limit = lower_disp_limit; PVDoublePtr pvDouble = pvDisplay->getSubField("limitLow"); pvDouble->put(lower_disp_limit); bitSet->set(pvDouble->getFieldOffset()); } if(caDisplay.upper_disp_limit!=upper_disp_limit) { caDisplay.upper_disp_limit = upper_disp_limit; PVDoublePtr pvDouble = pvDisplay->getSubField("limitHigh"); pvDouble->put(upper_disp_limit); bitSet->set(pvDouble->getFieldOffset()); } if(caDisplay.units!=units) { caDisplay.units = units; PVStringPtr pvString = pvDisplay->getSubField("units"); pvString->put(units); bitSet->set(pvString->getFieldOffset()); } if(caDisplay.format!=format) { caDisplay.format = format; PVStringPtr pvString = pvDisplay->getSubField("format"); pvString->put(format); bitSet->set(pvString->getFieldOffset()); } if(!description.empty()) { PVStringPtr pvString = pvDisplay->getSubField("description"); if(description.compare(pvString->get()) !=0) { pvString->put(description); bitSet->set(pvString->getFieldOffset()); } } } if(valueAlarmRequested) { double upper_alarm_limit = 0.0; double upper_warning_limit = 0.0; double lower_warning_limit = 0.0; double lower_alarm_limit = 0.0; switch(caRequestType) { case DBR_CTRL_CHAR: get_DBRValueAlarm(args.dbr, &upper_alarm_limit,&upper_warning_limit, &lower_warning_limit,&lower_alarm_limit); break; case DBR_CTRL_SHORT: get_DBRValueAlarm(args.dbr, &upper_alarm_limit,&upper_warning_limit, &lower_warning_limit,&lower_alarm_limit); break; case DBR_CTRL_LONG: get_DBRValueAlarm(args.dbr, &upper_alarm_limit,&upper_warning_limit, &lower_warning_limit,&lower_alarm_limit); break; case DBR_CTRL_FLOAT: get_DBRValueAlarm(args.dbr, &upper_alarm_limit,&upper_warning_limit, &lower_warning_limit,&lower_alarm_limit); break; case DBR_CTRL_DOUBLE: get_DBRValueAlarm(args.dbr, &upper_alarm_limit,&upper_warning_limit, &lower_warning_limit,&lower_alarm_limit); break; default : throw std::runtime_error("DbdToPv::getFromDBD logic error"); } ConvertPtr convert(getConvert()); PVStructurePtr pvValueAlarm(pvStructure->getSubField("valueAlarm")); if(caValueAlarm.upper_alarm_limit!=upper_alarm_limit) { caValueAlarm.upper_alarm_limit = upper_alarm_limit; PVScalarPtr pv = pvValueAlarm->getSubField("highAlarmLimit"); convert->fromDouble(pv,upper_alarm_limit); bitSet->set(pv->getFieldOffset()); } if(caValueAlarm.upper_warning_limit!=upper_warning_limit) { caValueAlarm.upper_warning_limit = upper_warning_limit; PVScalarPtr pv = pvValueAlarm->getSubField("highWarningLimit"); convert->fromDouble(pv,upper_warning_limit); bitSet->set(pv->getFieldOffset()); } if(caValueAlarm.lower_warning_limit!=lower_warning_limit) { caValueAlarm.lower_warning_limit = lower_warning_limit; PVScalarPtr pv = pvValueAlarm->getSubField("lowWarningLimit"); convert->fromDouble(pv,lower_warning_limit); bitSet->set(pv->getFieldOffset()); } if(caValueAlarm.lower_alarm_limit!=lower_alarm_limit) { caValueAlarm.lower_alarm_limit = lower_alarm_limit; PVScalarPtr pv = pvValueAlarm->getSubField("lowAlarmLimit"); convert->fromDouble(pv,lower_alarm_limit); bitSet->set(pv->getFieldOffset()); } } if(firstTime) { firstTime = false; bitSet->clear(); bitSet->set(0); } return Status::Ok; } template const void * put_DBRScalar(dbrT *val,PVScalar::shared_pointer const & pvScalar) { std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvScalar); *val = value->get(); return val; } template const void * put_DBRScalarArray(unsigned long*count, PVScalarArray::shared_pointer const & pvArray) { std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvArray); *count = value->getLength(); return value->view().data(); } Status DbdToPv::putToDBD( CAChannelPtr const & caChannel, PVStructurePtr const & pvStructure, bool block, caCallbackFunc putHandler, void * userarg) { chid channelID = caChannel->getChannelID(); const void *pValue = NULL; unsigned long count = 1; char *ca_stringBuffer(0); dbr_char_t bvalue(0); dbr_short_t svalue(0); dbr_long_t lvalue(0); dbr_float_t fvalue(0); dbr_double_t dvalue(0); if(isArray) { PVScalarArrayPtr pvValue = pvStructure->getSubField("value"); switch(caValueType) { case DBR_STRING: { PVStringArrayPtr pvValue = pvStructure->getSubField("value"); count = pvValue->getLength(); if(count<1) break; if(count>maxElements) count = maxElements; int nbytes = count*MAX_STRING_SIZE; ca_stringBuffer = new char[nbytes]; memset(ca_stringBuffer, 0, nbytes); pValue = ca_stringBuffer; PVStringArray::const_svector stringArray(pvValue->view()); char *pnext = ca_stringBuffer; for(size_t i=0; i= MAX_STRING_SIZE) len = MAX_STRING_SIZE - 1; memcpy(pnext, value.c_str(), len); pnext += MAX_STRING_SIZE; } break; } case DBR_CHAR: pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_SHORT: pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_LONG: pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_FLOAT: pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_DOUBLE: pValue = put_DBRScalarArray(&count,pvValue); break; default: Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error")); return errorStatus; } } else { PVScalarPtr pvValue = pvStructure->getSubField("value"); switch(caValueType) { case DBR_ENUM: { bool wait = false; { Lock lock(choicesMutex); if(!choicesValid) { wait = true; waitForChoicesValid = true; } } bool result = true; if(wait) { result = choicesEvent.wait(5.0); } if(!result) { Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD ")); return errorStatus; } dbr_enum_t indexvalue = pvStructure->getSubField("value.index")->get(); pValue = &indexvalue; break; } case DBR_STRING: pValue = pvStructure->getSubField("value")->get().c_str(); break; case DBR_CHAR: pValue = put_DBRScalar(&bvalue,pvValue); break; case DBR_SHORT: pValue = put_DBRScalar(&svalue,pvValue); break; case DBR_LONG: pValue = put_DBRScalar(&lvalue,pvValue); break; case DBR_FLOAT: pValue = put_DBRScalar(&fvalue,pvValue); break; case DBR_DOUBLE: pValue = put_DBRScalar(&dvalue,pvValue); break; default: Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::getFromDBD logic error")); return errorStatus; } } Status status = Status::Ok; int result = 0; caChannel->attachContext(); if(block) { result = ca_array_put_callback(caValueType,count,channelID,pValue,putHandler,userarg); } else { result = ca_array_put(caValueType,count,channelID,pValue); } if(result==ECA_NORMAL) { ca_flush_io(); } else { status = Status(Status::STATUSTYPE_ERROR, string(ca_message(result))); } if(ca_stringBuffer!=NULL) delete[] ca_stringBuffer; return status; } }}}