diff --git a/src/ca/caChannel.cpp b/src/ca/caChannel.cpp index 9ea13fa..20fbe2b 100644 --- a/src/ca/caChannel.cpp +++ b/src/ca/caChannel.cpp @@ -91,10 +91,13 @@ static void ca_get_labels_handler(struct event_handler_args args) const dbr_gr_enum* dbr_enum_p = static_cast(args.dbr); PVStringArray* labelsArray = static_cast(args.usr); - PVStringArray::svector labels(labelsArray->reuse()); - labels.resize(dbr_enum_p->no_str); - std::copy(dbr_enum_p->strs, dbr_enum_p->strs + dbr_enum_p->no_str, labels.begin()); - labelsArray->replace(freeze(labels)); + if (labelsArray) + { + PVStringArray::svector labels(labelsArray->reuse()); + labels.resize(dbr_enum_p->no_str); + std::copy(dbr_enum_p->strs, dbr_enum_p->strs + dbr_enum_p->no_str, labels.begin()); + labelsArray->replace(freeze(labels)); + } } else { @@ -103,9 +106,62 @@ static void ca_get_labels_handler(struct event_handler_args args) } } -static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, string const & properties) +// Filter out unrequested fields from a source structure according to a +// structure conforming to the format of the "field" field of a pvRequest, +// preserving type ids of unchanged structures. +static StructureConstPtr refineStructure(StructureConstPtr const & source, + StructureConstPtr const & requestedFields) { - PVStructure::shared_pointer pvStructure = getPVDataCreate()->createPVStructure(createStructure(channel, properties)); + if (requestedFields.get() == NULL || requestedFields->getNumberFields() == 0) + return source; + + FieldBuilderPtr builder = getFieldCreate()->createFieldBuilder(); + bool addId = true; + + FieldConstPtrArray fields = source->getFields(); + StringArray names = source->getFieldNames(); + size_t i = 0; + for (FieldConstPtrArray::const_iterator it = fields.begin(); it != fields.end(); ++it) + { + FieldConstPtr field = *it; + const std::string & name = names[i++]; + FieldConstPtr reqField = requestedFields->getField(name); + if (reqField.get()) + { + if (field->getType() != structure || (reqField->getType() != structure)) + builder->add(name,field); + else + { + StructureConstPtr substruct = + std::tr1::dynamic_pointer_cast(field); + + StructureConstPtr reqSubstruct = + std::tr1::dynamic_pointer_cast(reqField); + + StructureConstPtr nested = refineStructure(substruct, reqSubstruct); + builder->add(name,nested); + if (nested->getID() != substruct->getID()) + addId = false; + } + } + else + addId = false; + } + if (addId) + builder->setId(source->getID()); + return builder->createStructure(); +} + +static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, string const & properties, PVStructurePtr pvRequest) +{ + StructureConstPtr unrefinedStructure = createStructure(channel, properties); + + PVStructurePtr fieldPVStructure = pvRequest->getSubField("field"); + StructureConstPtr finalStructure = fieldPVStructure.get() ? + refineStructure(unrefinedStructure, fieldPVStructure->getStructure()) : + unrefinedStructure; + + PVStructure::shared_pointer pvStructure = getPVDataCreate()->createPVStructure(finalStructure); if (channel->getNativeType() == DBR_ENUM) { PVScalarArrayPtr pvScalarArray = pvStructure->getSubField("value.choices"); @@ -129,8 +185,9 @@ static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer c return pvStructure; } -static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, chtype dbrType) +static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer const & channel, chtype dbrType, PVStructurePtr pvRequest) { + // Match to closest DBR type // NOTE: value is always there string properties; if (dbrType >= DBR_CTRL_STRING) // 28 @@ -154,7 +211,7 @@ static PVStructure::shared_pointer createPVStructure(CAChannel::shared_pointer c else properties = "value"; - return createPVStructure(channel, properties); + return createPVStructure(channel, properties, pvRequest); } @@ -503,7 +560,7 @@ CAChannelGet::CAChannelGet(CAChannel::shared_pointer const & _channel, channel(_channel), channelGetRequester(_channelGetRequester), getType(getDBRType(pvRequest, _channel->getNativeType())), - pvStructure(createPVStructure(_channel, getType)), + pvStructure(createPVStructure(_channel, getType, pvRequest)), bitSet(new BitSet(static_cast(pvStructure->getStructure()->getNumberFields()))), lastRequestFlag(false) { @@ -536,16 +593,20 @@ void copy_DBR(const void * dbr, unsigned count, PVStructure::shared_pointer cons { if (count == 1) { - std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value")); - value->put(static_cast(dbr)[0]); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) value->put(static_cast(dbr)[0]); } else { - std::tr1::shared_ptr value = pvStructure->getSubFieldT("value"); - typename aF::svector temp(value->reuse()); - temp.resize(count); - std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin()); - value->replace(freeze(temp)); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) + { + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + typename aF::svector temp(value->reuse()); + temp.resize(count); + std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin()); + value->replace(freeze(temp)); + } } } @@ -557,16 +618,19 @@ void copy_DBR(const void * dbr, unsigned count, P { if (count == 1) { - std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value")); - value->put(static_cast(dbr)[0]); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) value->put(static_cast(dbr)[0]); } else { - std::tr1::shared_ptr value = pvStructure->getSubFieldT("value"); - PVIntArray::svector temp(value->reuse()); - temp.resize(count); - std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin()); - value->replace(freeze(temp)); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) + { + PVIntArray::svector temp(value->reuse()); + temp.resize(count); + std::copy(static_cast(dbr), static_cast(dbr) + count, temp.begin()); + value->replace(freeze(temp)); + } } } #endif @@ -577,17 +641,20 @@ void copy_DBR(const void * dbr, unsigned count, { if (count == 1) { - std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubField("value")); - value->put(std::string(static_cast(dbr))); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) value->put(std::string(static_cast(dbr))); } else { - std::tr1::shared_ptr value = pvStructure->getSubFieldT("value"); - const dbr_string_t* dbrStrings = static_cast(dbr); - PVStringArray::svector sA(value->reuse()); - sA.resize(count); - std::copy(dbrStrings, dbrStrings + count, sA.begin()); - value->replace(freeze(sA)); + std::tr1::shared_ptr value = pvStructure->getSubField("value"); + if (value.get()) + { + const dbr_string_t* dbrStrings = static_cast(dbr); + PVStringArray::svector sA(value->reuse()); + sA.resize(count); + std::copy(dbrStrings, dbrStrings + count, sA.begin()); + value->replace(freeze(sA)); + } } } @@ -597,8 +664,8 @@ void copy_DBR(const void * dbr, unsigned c { if (count == 1) { - std::tr1::shared_ptr value = std::tr1::static_pointer_cast(pvStructure->getSubFieldT("value.index")); - value->put(static_cast(dbr)[0]); + PVIntPtr value = pvStructure->getSubField("value.index"); + if (value.get()) value->put(static_cast(dbr)[0]); } else { @@ -613,10 +680,18 @@ void copy_DBR_STS(const void * dbr, unsigned count, PVStructure::shared_pointer { const T* data = static_cast(dbr); - PVStructure::shared_pointer alarm = pvStructure->getSubFieldT("alarm"); - alarm->getSubFieldT("status")->put(dbrStatus2alarmStatus[data->status]); - alarm->getSubFieldT("severity")->put(data->severity); - alarm->getSubFieldT("message")->put(dbrStatus2alarmMessage[data->status]); + PVStructure::shared_pointer alarm = pvStructure->getSubField("alarm"); + if (alarm.get()) + { + PVIntPtr status = alarm->getSubField("status"); + if (status.get()) status->put(dbrStatus2alarmStatus[data->status]); + + PVIntPtr severity = alarm->getSubField("severity"); + if (severity.get()) severity->put(data->severity); + + PVStringPtr message = alarm->getSubField("message"); + if (message.get()) message->put(dbrStatus2alarmMessage[data->status]); + } copy_DBR(&data->value, count, pvStructure); } @@ -627,11 +702,18 @@ void copy_DBR_TIME(const void * dbr, unsigned count, PVStructure::shared_pointer { const T* data = static_cast(dbr); - PVStructure::shared_pointer ts = pvStructure->getSubFieldT("timeStamp"); - epics::pvData::int64 spe = data->stamp.secPastEpoch; - spe += 7305*86400; - ts->getSubFieldT("secondsPastEpoch")->put(spe); - ts->getSubFieldT("nanoseconds")->put(data->stamp.nsec); + PVStructure::shared_pointer ts = pvStructure->getSubField("timeStamp"); + if (ts.get()) + { + epics::pvData::int64 spe = data->stamp.secPastEpoch; + spe += 7305*86400; + + PVLongPtr secondsPastEpoch = ts->getSubField("secondsPastEpoch"); + if (secondsPastEpoch.get()) secondsPastEpoch->put(spe); + + PVIntPtr nanoseconds = ts->getSubField("nanoseconds"); + if (nanoseconds.get()) nanoseconds->put(data->stamp.nsec); + } copy_DBR_STS(dbr, count, pvStructure); } @@ -640,13 +722,15 @@ void copy_DBR_TIME(const void * dbr, unsigned count, PVStructure::shared_pointer template void copy_format(const void * /*dbr*/, PVStructure::shared_pointer const & pvDisplayStructure) { - pvDisplayStructure->getSubFieldT("format")->put("%d"); + PVStringPtr format = pvDisplayStructure->getSubField("format"); + if (format.get()) format->put("%d"); } template <> void copy_format(const void * /*dbr*/, PVStructure::shared_pointer const & pvDisplayStructure) { - pvDisplayStructure->getSubFieldT("format")->put("%s"); + PVStringPtr format = pvDisplayStructure->getSubField("format"); + if (format.get()) format->put("%s"); } #define COPY_FORMAT_FOR(T) \ @@ -659,11 +743,13 @@ void copy_format(const void * dbr, PVStructure::shared_pointer const & pvDisp { \ char fmt[16]; \ sprintf(fmt, "%%.%df", data->precision); \ - pvDisplayStructure->getSubFieldT("format")->put(std::string(fmt)); \ + PVStringPtr format = pvDisplayStructure->getSubField("format");\ + if (format.get()) format->put(std::string(fmt));\ } \ else \ { \ - pvDisplayStructure->getSubFieldT("format")->put("%f"); \ + PVStringPtr format = pvDisplayStructure->getSubField("format");\ + if (format.get()) format->put("%f");\ } \ } @@ -680,24 +766,50 @@ void copy_DBR_GR(const void * dbr, unsigned count, PVStructure::shared_pointer c { const T* data = static_cast(dbr); - PVStructure::shared_pointer alarm = pvStructure->getSubFieldT("alarm"); - alarm->getSubFieldT("status")->put(0); - alarm->getSubFieldT("severity")->put(data->severity); - alarm->getSubFieldT("message")->put(dbrStatus2alarmMessage[data->status]); + PVStructurePtr alarm = pvStructure->getSubField("alarm"); + if (alarm.get()) + { + PVIntPtr status = alarm->getSubField("status"); + if (status.get()) status->put(0); - PVStructure::shared_pointer disp = pvStructure->getSubFieldT("display"); - disp->getSubFieldT("units")->put(std::string(data->units)); - disp->getSubFieldT("limitHigh")->put(data->upper_disp_limit); - disp->getSubFieldT("limitLow")->put(data->lower_disp_limit); + PVIntPtr severity = alarm->getSubField("severity"); + if (severity.get()) severity->put(data->severity); - copy_format(dbr, disp); + PVStringPtr message = alarm->getSubField("message"); + if (message.get()) message->put(dbrStatus2alarmMessage[data->status]); + } - PVStructure::shared_pointer va = pvStructure->getSubFieldT("valueAlarm"); - va->getSubFieldT("highAlarmLimit")->put(data->upper_alarm_limit); - va->getSubFieldT("highWarningLimit")->put(data->upper_warning_limit); - va->getSubFieldT("lowWarningLimit")->put(data->lower_warning_limit); - va->getSubFieldT("lowAlarmLimit")->put(data->lower_alarm_limit); + PVStructurePtr disp = pvStructure->getSubField("display"); + if (disp.get()) + { + PVStringPtr units = disp->getSubField("units"); + if (units.get()) units->put(std::string(data->units)); + PVDoublePtr limitHigh = disp->getSubField("limitHigh"); + if (limitHigh.get()) limitHigh->put(data->upper_disp_limit); + + PVDoublePtr limitLow = disp->getSubField("limitLow"); + if (limitLow.get()) limitLow->put(data->upper_disp_limit); + + copy_format(dbr, disp); + } + + PVStructurePtr va = pvStructure->getSubField("valueAlarm"); + if (va.get()) + { + std::tr1::shared_ptr highAlarmLimit = va->getSubField("highAlarmLimit"); + if (highAlarmLimit.get()) highAlarmLimit->put(data->upper_alarm_limit); + + std::tr1::shared_ptr highWarningLimit = va->getSubField("highWarningLimit"); + if (highWarningLimit.get()) highWarningLimit->put(data->upper_warning_limit); + + std::tr1::shared_ptr lowWarningLimit = va->getSubField("lowWarningLimit"); + if (lowWarningLimit.get()) lowWarningLimit->put(data->lower_warning_limit); + + std::tr1::shared_ptr lowAlarmLimit = va->getSubField("lowAlarmLimit"); + if (lowAlarmLimit.get()) lowAlarmLimit->put(data->lower_alarm_limit); + } + copy_DBR(&data->value, count, pvStructure); } @@ -718,27 +830,59 @@ void copy_DBR_CTRL(const void * dbr, unsigned count, PVStructure::shared_pointer { const T* data = static_cast(dbr); - PVStructure::shared_pointer alarm = pvStructure->getSubFieldT("alarm"); - alarm->getSubFieldT("status")->put(0); - alarm->getSubFieldT("severity")->put(data->severity); - alarm->getSubFieldT("message")->put(dbrStatus2alarmMessage[data->status]); + PVStructure::shared_pointer alarm = pvStructure->getSubField("alarm"); + if (alarm.get()) + { + PVIntPtr status = alarm->getSubField("status"); + if (status.get()) status->put(0); - PVStructure::shared_pointer disp = pvStructure->getSubFieldT("display"); - disp->getSubFieldT("units")->put(std::string(data->units)); - disp->getSubFieldT("limitHigh")->put(data->upper_disp_limit); - disp->getSubFieldT("limitLow")->put(data->lower_disp_limit); + PVIntPtr severity = alarm->getSubField("severity"); + if (severity.get()) severity->put(data->severity); - copy_format(dbr, disp); + PVStringPtr message = alarm->getSubField("message"); + if (message.get()) message->put(dbrStatus2alarmMessage[data->status]); + } - PVStructure::shared_pointer va = pvStructure->getSubFieldT("valueAlarm"); - std::tr1::static_pointer_cast(va->getSubFieldT("highAlarmLimit"))->put(data->upper_alarm_limit); - std::tr1::static_pointer_cast(va->getSubFieldT("highWarningLimit"))->put(data->upper_warning_limit); - std::tr1::static_pointer_cast(va->getSubFieldT("lowWarningLimit"))->put(data->lower_warning_limit); - std::tr1::static_pointer_cast(va->getSubFieldT("lowAlarmLimit"))->put(data->lower_alarm_limit); + PVStructurePtr disp = pvStructure->getSubField("display"); + if (disp.get()) + { + PVStringPtr units = disp->getSubField("units"); + if (units.get()) units->put(std::string(data->units)); - PVStructure::shared_pointer ctrl = pvStructure->getSubFieldT("control"); - ctrl->getSubFieldT("limitHigh")->put(data->upper_ctrl_limit); - ctrl->getSubFieldT("limitLow")->put(data->lower_ctrl_limit); + PVDoublePtr limitHigh = disp->getSubField("limitHigh"); + if (limitHigh.get()) limitHigh->put(data->upper_disp_limit); + + PVDoublePtr limitLow = disp->getSubField("limitLow"); + if (limitLow.get()) limitLow->put(data->upper_disp_limit); + + copy_format(dbr, disp); + } + + PVStructurePtr va = pvStructure->getSubField("valueAlarm"); + if (va.get()) + { + std::tr1::shared_ptr highAlarmLimit = va->getSubField("highAlarmLimit"); + if (highAlarmLimit.get()) highAlarmLimit->put(data->upper_alarm_limit); + + std::tr1::shared_ptr highWarningLimit = va->getSubField("highWarningLimit"); + if (highWarningLimit.get()) highWarningLimit->put(data->upper_warning_limit); + + std::tr1::shared_ptr lowWarningLimit = va->getSubField("lowWarningLimit"); + if (lowWarningLimit.get()) lowWarningLimit->put(data->lower_warning_limit); + + std::tr1::shared_ptr lowAlarmLimit = va->getSubField("lowAlarmLimit"); + if (lowAlarmLimit.get()) lowAlarmLimit->put(data->lower_alarm_limit); + } + + PVStructurePtr ctrl = pvStructure->getSubField("control"); + if (ctrl.get()) + { + PVDoublePtr limitHigh = ctrl->getSubField("limitHigh"); + if (limitHigh.get()) limitHigh->put(data->upper_ctrl_limit); + + PVDoublePtr limitLow = ctrl->getSubField("limitLow"); + if (limitLow.get()) limitLow->put(data->lower_ctrl_limit); + } copy_DBR(&data->value, count, pvStructure); } @@ -933,7 +1077,7 @@ CAChannelPut::CAChannelPut(CAChannel::shared_pointer const & _channel, channel(_channel), channelPutRequester(_channelPutRequester), getType(getDBRType(pvRequest, _channel->getNativeType())), - pvStructure(createPVStructure(_channel, getType)), + pvStructure(createPVStructure(_channel, getType, pvRequest)), bitSet(new BitSet(static_cast(pvStructure->getStructure()->getNumberFields()))), lastRequestFlag(false) { @@ -1278,7 +1422,7 @@ CAChannelMonitor::CAChannelMonitor(CAChannel::shared_pointer const & _channel, channel(_channel), monitorRequester(_monitorRequester), getType(getDBRType(pvRequest, _channel->getNativeType())), - pvStructure(createPVStructure(_channel, getType)), + pvStructure(createPVStructure(_channel, getType, pvRequest)), changedBitSet(new BitSet(static_cast(pvStructure->getStructure()->getNumberFields()))), overrunBitSet(new BitSet(static_cast(pvStructure->getStructure()->getNumberFields()))), count(0),