/** * 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 #include #define epicsExportSharedSymbols #include "caChannel.h" #include "dbdToPv.h" using namespace epics::pvData; using std::string; using std::ostringstream; using std::cout; namespace epics { namespace pvAccess { namespace ca { #define CA_PRIORITY 50 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), dbfIsUCHAR(false), dbfIsUSHORT(false), dbfIsULONG(false), dbfIsINT64(false), dbfIsUINT64(false), valueRequested(false), alarmRequested(false), timeStampRequested(false), displayRequested(false), controlRequested(false), valueAlarmRequested(false), isArray(false), charArrayIsString(false), firstTime(true), 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 pvUByte : return DBR_CHAR; case pvShort : return DBR_SHORT; case pvUShort : return DBR_SHORT; case pvInt : return DBR_LONG; case pvUInt : return DBR_LONG; case pvFloat : return DBR_FLOAT; case pvDouble : return DBR_DOUBLE; case pvLong : return DBR_DOUBLE; case pvULong : return DBR_DOUBLE; default: break; } throw std::runtime_error("getDbr: illegal scalarType"); } static dbr_short_t convertDBstatus(dbr_short_t dbStatus) { switch(dbStatus) { case NO_ALARM: return noStatus; case READ_ALARM: case WRITE_ALARM: case HIHI_ALARM: case HIGH_ALARM: case LOLO_ALARM: case LOW_ALARM: case STATE_ALARM: case COS_ALARM: case HW_LIMIT_ALARM: return deviceStatus; case COMM_ALARM: case TIMEOUT_ALARM: return driverStatus; case CALC_ALARM: case SCAN_ALARM: case LINK_ALARM: case SOFT_ALARM: case BAD_SUB_ALARM: return recordStatus; case DISABLE_ALARM: case SIMM_ALARM: case READ_ACCESS_ALARM: case WRITE_ACCESS_ALARM: return dbStatus; case UDF_ALARM: return undefinedStatus; default: return undefinedStatus; // UNDEFINED } } 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) { valueRequested = true; alarmRequested = true; timeStampRequested = true; displayRequested = true; controlRequested = true; valueAlarmRequested = true; } else { if(fieldPVStructure->getSubField("value")) valueRequested = 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); return; } ScalarType st = dbr2ST[channelType]; PVStringPtr pvValue = fieldPVStructure->getSubField("value._options.dbtype"); if(pvValue) { std::string value(pvValue->get()); if(value.find("DBF_UCHAR")!=std::string::npos) { if(st==pvByte) { dbfIsUCHAR = true; st = pvUByte; caValueType = DBR_CHAR; } } else if(value.find("DBF_USHORT")!=std::string::npos) { if(st==pvInt) { dbfIsUSHORT = true; st = pvUShort; caValueType = DBR_SHORT; } } else if(value.find("DBF_ULONG")!=std::string::npos) { if(st==pvDouble) { dbfIsULONG = true; st = pvUInt; caValueType = DBR_LONG; } } else if(value.find("DBF_INT64")!=std::string::npos) { if(st==pvDouble) { dbfIsINT64 = true; st = pvLong; } } else if(value.find("DBF_UINT64")!=std::string::npos) { if(st==pvDouble) { dbfIsUINT64 = true; st = pvULong; } } } if(st==pvString) { displayRequested = false; controlRequested = false; valueAlarmRequested = false; } maxElements = ca_element_count(channelID); if(maxElements!=1) isArray = true; if(isArray) { controlRequested = false; valueAlarmRequested = false; if(channelType==DBR_CHAR && fieldPVStructure) { PVStringPtr pvValue = fieldPVStructure->getSubField("value._options.pvtype"); if(pvValue) { std::string value(pvValue->get()); if(value.find("pvString")!=std::string::npos) { charArrayIsString = true; st = pvString; } } } } if(controlRequested || displayRequested || valueAlarmRequested) timeStampRequested = false; FieldCreatePtr fieldCreate(FieldCreate::getFieldCreate()); PVDataCreatePtr pvDataCreate(PVDataCreate::getPVDataCreate()); FieldBuilderPtr fieldBuilder(fieldCreate->createFieldBuilder()); if(valueRequested) { if(isArray && !charArrayIsString) { 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: case pvUByte: fieldBuilder->add("valueAlarm",standardField->byteAlarm()); break; case pvShort: case pvUShort: fieldBuilder->add("valueAlarm",standardField->shortAlarm()); break; case pvInt: case pvUInt: fieldBuilder->add("valueAlarm",standardField->intAlarm()); break; case pvFloat: fieldBuilder->add("valueAlarm",standardField->floatAlarm()); break; case pvDouble: case pvLong: case pvULong: 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); } } chtype DbdToPv::getRequestType() { if(caRequestType<0) { throw std::runtime_error("DbDToPv::getRequestType: bad type"); } return caRequestType; } Structure::const_shared_pointer DbdToPv::getStructure() { return structure; } static void enumChoicesHandler(struct event_handler_args args) { DbdToPv *dbdToPv = static_cast(args.usr); dbdToPv->getChoicesDone(args); } 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])); choicesEvent.trigger(); } void DbdToPv::getChoices(CAChannelPtr const & caChannel) { if(caRequestType==DBR_ENUM||caRequestType==DBR_TIME_ENUM) { chid channelID = caChannel->getChannelID(); Attach to(caChannel->caContext()); int result = ca_array_get_callback(DBR_GR_ENUM, 1, channelID, enumChoicesHandler, this); if (result == ECA_NORMAL) { result = ca_flush_io(); choicesEvent.wait(); } else { string mess(caChannel->getChannelName()); mess += " DbdToPv::activate getting enum cnoices "; mess += ca_message(result); throw std::runtime_error(mess); } } } 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(valueRequested) { 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: if(charArrayIsString) { const char * pchar = static_cast(value); std::string str(pchar); PVStringPtr pvValue(pvStructure->getSubField("value")); pvValue->put(str); break; } if(dbfIsUCHAR) { copy_DBRScalarArray(value,count,pvValue); break; } copy_DBRScalarArray(value,count,pvValue); break; case DBR_SHORT: if(dbfIsUSHORT) { copy_DBRScalarArray(value,count,pvValue); break; } copy_DBRScalarArray(value,count,pvValue); break; case DBR_LONG: if(dbfIsULONG) { copy_DBRScalarArray(value,count,pvValue); break; } copy_DBRScalarArray(value,count,pvValue); break; case DBR_FLOAT: copy_DBRScalarArray(value,count,pvValue); break; case DBR_DOUBLE: if(dbfIsINT64) { copy_DBRScalarArray(value,count,pvValue); break; } if(dbfIsUINT64) { copy_DBRScalarArray(value,count,pvValue); break; } 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: if(dbfIsUCHAR) { copy_DBRScalar(value,pvValue); break; } copy_DBRScalar(value,pvValue); break; case DBR_SHORT: if(dbfIsUSHORT) { copy_DBRScalar(value,pvValue); break; } copy_DBRScalar(value,pvValue); break; case DBR_LONG: if(dbfIsULONG) { copy_DBRScalar(value,pvValue); break; } copy_DBRScalar(value,pvValue); break; case DBR_FLOAT: copy_DBRScalar(value,pvValue); break; case DBR_DOUBLE: if(dbfIsINT64) { copy_DBRScalar(value,pvValue); break; } if(dbfIsUINT64) { copy_DBRScalar(value,pvValue); break; } 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(convertDBstatus(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.nsec = stamp.nsec; 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"); if(pvString) { pvString->put(format); 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: if(charArrayIsString) { PVStringPtr pvValue(pvStructure->getSubField("value")); const char * pchar = pvValue->get().c_str(); pValue = pchar; count = pvValue->get().length(); break; } if(dbfIsUCHAR) { pValue = put_DBRScalarArray(&count,pvValue); break; } pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_SHORT: if(dbfIsUSHORT) { pValue = put_DBRScalarArray(&count,pvValue); break; } pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_LONG: if(dbfIsULONG) { pValue = put_DBRScalarArray(&count,pvValue); break; } pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_FLOAT: pValue = put_DBRScalarArray(&count,pvValue); break; case DBR_DOUBLE: if(dbfIsINT64) { PVLongArrayPtr pvValue(pvStructure->getSubField("value")); PVLongArray::const_svector sv(pvValue->view()); pvDoubleArray = PVDoubleArrayPtr(getPVDataCreate()->createPVScalarArray()); pvDoubleArray->putFrom(sv); const double * pdouble = pvDoubleArray->view().data(); count = pvValue->getLength(); pValue = pdouble; break; } if(dbfIsUINT64) { PVULongArrayPtr pvValue(pvStructure->getSubField("value")); PVULongArray::const_svector sv(pvValue->view()); pvDoubleArray = PVDoubleArrayPtr(getPVDataCreate()->createPVScalarArray()); pvDoubleArray->putFrom(sv); const double * pdouble = pvDoubleArray->view().data(); count = pvValue->getLength(); pValue = pdouble; break; } 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: { 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: if(dbfIsUCHAR) { pValue = put_DBRScalar(&bvalue,pvValue); break; } pValue = put_DBRScalar(&bvalue,pvValue); break; case DBR_SHORT: if(dbfIsUSHORT) { pValue = put_DBRScalar(&svalue,pvValue); break; } pValue = put_DBRScalar(&svalue,pvValue); break; case DBR_LONG: if(dbfIsULONG) { pValue = put_DBRScalar(&lvalue,pvValue); break; } pValue = put_DBRScalar(&lvalue,pvValue); break; case DBR_FLOAT: pValue = put_DBRScalar(&fvalue,pvValue); break; case DBR_DOUBLE: if(dbfIsINT64) { pValue = put_DBRScalar(&dvalue,pvValue); break; } if(dbfIsUINT64) { pValue = put_DBRScalar(&dvalue,pvValue); break; } pValue = put_DBRScalar(&dvalue,pvValue); break; default: Status errorStatus( Status::STATUSTYPE_ERROR, string("DbdToPv::putToDBD logic error")); return errorStatus; } } Status status = Status::Ok; int result = 0; Attach to(caChannel->caContext()); 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; } }}}