示例#1
0
void PvaClientPut::getDone(
    const Status& status,
    ChannelPut::shared_pointer const & channelPut,
    PVStructurePtr const & pvStructure,
    BitSetPtr const & bitSet)
{
    if(PvaClient::getDebug()) {
        cout << "PvaClientPut::getDone"
           << " channelName " << pvaClientChannel->getChannel()->getChannelName()
           << " status.isOK " << (status.isOK() ? "true" : "false")
           << endl;
    }
    {
        Lock xx(mutex);
        channelGetPutStatus = status;
        if(status.isOK()) {
            PVStructurePtr pvs = pvaClientData->getPVStructure();
            pvs->copyUnchecked(*pvStructure,*bitSet);
            BitSetPtr bs = pvaClientData->getChangedBitSet();
            bs->clear();
            *bs |= *bitSet;
            putState = putComplete;
        }
    }
    PvaClientPutRequesterPtr  req(pvaClientPutRequester.lock());
    if(req) {
          req->getDone(status,shared_from_this());
    }
    waitForGetPut.signal();
}
示例#2
0
void ChannelPutGetLocal::getGet()
{
    ChannelPutGetRequester::shared_pointer requester = channelPutGetRequester.lock();
    if(!requester) return;
    if(isDestroyed) {
         requester->getGetDone(
             channelDestroyedStatus,getPtrSelf(),nullPVStructure,nullBitSet);
         return;
    } 
    try {
         getBitSet->clear();
         {
             epicsGuard <PVRecord> guard(*pvRecord);
             pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet);
         }
         requester->getGetDone(
             Status::Ok,getPtrSelf(),pvGetStructure,getBitSet);
         if(pvRecord->getTraceLevel()>1)
         {
             cout << "ChannelPutGetLocal::getGet" << endl;
         }
    } catch(std::exception& ex) {
        Status status = Status(Status::STATUSTYPE_FATAL, ex.what());
        PVStructurePtr pvPutStructure;
        BitSetPtr putBitSet;
        requester->getGetDone(status,getPtrSelf(),pvGetStructure,getBitSet);
    }
}
示例#3
0
void PvaClientPutGet::getPutDone(
    const Status& status,
    ChannelPutGet::shared_pointer const & channelPutGet,
    PVStructurePtr const & putPVStructure,
    BitSetPtr const & putBitSet)
{
    if(isDestroyed) throw std::runtime_error("pvaClientPutGet was destroyed");
    channelPutGetStatus = status;
    if(status.isOK()) {
        PVStructurePtr pvs = pvaClientPutData->getPVStructure();
        pvs->copyUnchecked(*putPVStructure,*putBitSet);
        BitSetPtr bs = pvaClientPutData->getChangedBitSet();
        bs->clear();
        *bs |= *putBitSet;
    }
    waitForPutGet.signal();
}
示例#4
0
static bool checkBitSetPVField(
    PVFieldPtr const &pvField,BitSetPtr const &bitSet,int32 initialOffset)
{
    int32 offset = initialOffset;
    int32 nbits = static_cast<int32>(pvField->getNumberFields());
    if(nbits==1) return bitSet->get(offset);
    int32 nextSetBit = bitSet->nextSetBit(offset);
    if(nextSetBit>=(offset+nbits)) return false;
    if(nextSetBit<0) return false;
    if(bitSet->get(offset)) {
        if(nbits>1) {
            for(int32 i=offset+1; i<offset+nbits; i++) bitSet->clear(i);
        }
        return true;
    }

    bool atLeastOneBitSet = false;
    bool allBitsSet = true;
    PVStructurePtr pvStructure = static_pointer_cast<PVStructure>(pvField);
    offset = static_cast<int32>(pvStructure->getFieldOffset()) + 1;
    while(offset<initialOffset + nbits) {
        PVFieldPtr pvSubField = pvStructure->getSubField(offset);
        int32 nbitsNow = static_cast<int32>(pvSubField->getNumberFields());
        if(nbitsNow==1) {
            if(bitSet->get(offset)) {
                atLeastOneBitSet = true;
            } else {
                allBitsSet = false;
            }
            offset++;
        } else {
            bool result = checkBitSetPVField(pvSubField,bitSet,offset);
            if(result) {
                atLeastOneBitSet = true;
                if(!bitSet->get(offset)) {
                    allBitsSet = false;
                }
            } else {
                allBitsSet = false;
            }
            offset += static_cast<int32>(pvSubField->getNumberFields());
        }
    }
    if(allBitsSet) {
        if(nbits>1) {
            for(int32 i=initialOffset+1; i<initialOffset+nbits; i++) {
                bitSet->clear(i);
            }
        }
        bitSet->set(initialOffset);
    }
    return atLeastOneBitSet;
}
static void testPostPut()
{
    testDiag("== testPostPut ==");
    StructureConstPtr structure =
       fieldCreate->createFieldBuilder()->
            add("alarm",standardField->alarm()) ->
            add("timeStamp",standardField->timeStamp()) ->
            addNestedStructure("power") ->
               add("value",pvDouble) ->
               add("alarm",standardField->alarm()) ->
               endNested()->
            addNestedStructure("voltage") ->
               add("value",pvDouble) ->
               add("alarm",standardField->alarm()) ->
               endNested()->
            addNestedStructure("current") ->
               add("value",pvDouble) ->
               add("alarm",standardField->alarm()) ->
               endNested()->
            createStructure();

    PvaClientPutDataPtr pvaData = PvaClientPutData::create(structure);
    PVStructurePtr pvStructure = pvaData->getPVStructure();

    BitSetPtr change = pvaData->getChangedBitSet();
    PVDoublePtr powerValue = pvStructure->getSubField<PVDouble>("power.value");
    PVDoublePtr voltageValue = pvStructure->getSubField<PVDouble>("voltage.value");
    PVDoublePtr currentValue = pvStructure->getSubField<PVDouble>("current.value");
    size_t powerOffset = powerValue->getFieldOffset();
    size_t voltageOffset = voltageValue->getFieldOffset();
    size_t currentOffset = currentValue->getFieldOffset();

    change->clear();
    powerValue->put(1.0);
    voltageValue->put(2.0);
    currentValue->put(.5);

    testOk(change->cardinality()==3,"3 fields changed");
    testOk(change->get(powerOffset),"power changed");
    testOk(change->get(voltageOffset),"voltage changed");
    testOk(change->get(currentOffset),"current changed");
}
示例#6
0
void ChannelGetLocal::get()
{
    ChannelGetRequester::shared_pointer requester = channelGetRequester.lock();
    if(!requester) return;
    if(isDestroyed) {
         requester->getDone(
             channelDestroyedStatus,getPtrSelf(),nullPVStructure,nullBitSet);
         return;
    } 
    try {
        bitSet->clear();
        {
            epicsGuard <PVRecord> guard(*pvRecord);
            if(callProcess) {
                pvRecord->beginGroupPut();
                pvRecord->process();
                pvRecord->endGroupPut();
            }
            pvCopy->updateCopySetBitSet(pvStructure, bitSet);
        }
        if(firstTime) {
            bitSet->clear();
            bitSet->set(0);
            firstTime = false;
        } 
        requester->getDone(
            Status::Ok,
            getPtrSelf(),
            pvStructure,
            bitSet);
        if(pvRecord->getTraceLevel()>1)
        {
            cout << "ChannelGetLocal::get" << endl;
        }
    } catch(std::exception& ex) {
        Status status = Status(Status::STATUSTYPE_FATAL, ex.what());
        requester->getDone(status,getPtrSelf(),pvStructure,bitSet);
    }

}
示例#7
0
static void testPVScalar(
    string const & valueNameMaster,
    string const & valueNameCopy,
    PVStructurePtr const & pvMaster,
    PVCopyPtr const & pvCopy)
{
    PVStructurePtr pvStructureCopy;
    PVScalarPtr pvValueMaster;
    PVScalarPtr pvValueCopy;
    BitSetPtr bitSet;
    size_t offset;
    ConvertPtr convert = getConvert();

    pvValueMaster = pvMaster->getSubField<PVScalar>(valueNameMaster);
    convert->fromDouble(pvValueMaster,.04);
    StructureConstPtr structure = pvCopy->getStructure();
    if(debug) { cout << "structure from copy" << endl << *structure << endl; }
    pvStructureCopy = pvCopy->createPVStructure();
    pvValueCopy = pvStructureCopy->getSubField<PVScalar>(valueNameCopy);
    bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
    pvCopy->initCopy(pvStructureCopy, bitSet);
    if(debug) { cout << "after initCopy pvValueCopy " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << endl; }
    convert->fromDouble(pvValueMaster,.06);
    testOk1(convert->toDouble(pvValueCopy)==.04);
    pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
    testOk1(convert->toDouble(pvValueCopy)==.06);
    testOk1(bitSet->get(pvValueCopy->getFieldOffset()));
    if(debug) { cout << "after put(.06) pvValueCopy " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    offset = pvCopy->getCopyOffset(pvValueMaster);
    if(debug) { cout << "getCopyOffset() " << offset; }
    if(debug) { cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset(); }
    if(debug) { cout << " pvValueMaster->getOffset() " << pvValueMaster->getFieldOffset(); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    bitSet->clear();
    convert->fromDouble(pvValueMaster,1.0);
    if(debug) { cout << "before updateCopyFromBitSet"; }
    if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); }
    if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    bitSet->set(0);
    testOk1(convert->toDouble(pvValueCopy)==0.06);
    pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
    testOk1(convert->toDouble(pvValueCopy)==1.0);
    if(debug) { cout << "after updateCopyFromBitSet"; }
    if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); }
    if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    convert->fromDouble(pvValueCopy,2.0);
    bitSet->set(0);
    if(debug) { cout << "before updateMaster"; }
    if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); }
    if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    testOk1(convert->toDouble(pvValueMaster)==1.0);
    pvCopy->updateMaster(pvStructureCopy,bitSet);
    testOk1(convert->toDouble(pvValueMaster)==2.0);
    if(debug) { cout << "after updateMaster"; }
    if(debug) { cout << " masterValue " << convert->toDouble(pvValueMaster); }
    if(debug) { cout << " copyValue " << convert->toDouble(pvValueCopy); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
}
示例#8
0
static void testPVScalarArray(
    string const & valueNameMaster,
    string const & valueNameCopy,
    PVStructurePtr const & pvMaster,
    PVCopyPtr const & pvCopy)
{
    PVStructurePtr pvStructureCopy;
    PVScalarArrayPtr pvValueMaster;
    PVScalarArrayPtr pvValueCopy;
    BitSetPtr bitSet;
    size_t offset;
    size_t n = 5;
    shared_vector<double> values(n);
    shared_vector<const double> cvalues;

    pvValueMaster = pvMaster->getSubField<PVScalarArray>(valueNameMaster);
    for(size_t i=0; i<n; i++) values[i] = i;
    const shared_vector<const double> xxx(freeze(values));
    pvValueMaster->putFrom(xxx);
    StructureConstPtr structure = pvCopy->getStructure();
    if(debug) { cout << "structure from copy" << endl << *structure << endl;}
    pvStructureCopy = pvCopy->createPVStructure();
    pvValueCopy = pvStructureCopy->getSubField<PVScalarArray>(valueNameCopy);
    bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
    pvCopy->initCopy(pvStructureCopy, bitSet);
    if(debug) { cout << "after initCopy pvValueCopy " << *pvValueCopy << endl; }
    if(debug) { cout << endl; }
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + .06;
    const shared_vector<const double> yyy(freeze(values));
    pvValueMaster->putFrom(yyy);
    pvValueCopy->getAs(cvalues);
    testOk1(cvalues[0]==0.0);
    pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
    pvValueCopy->getAs(cvalues);
    testOk1(cvalues[0]==0.06);
    if(debug) { cout << "after put(i+ .06) pvValueCopy " << *pvValueCopy << endl; }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    offset = pvCopy->getCopyOffset(pvValueMaster);
    if(debug) { cout << "getCopyOffset() " << offset; }
    if(debug) { cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset(); }
    if(debug) { cout << " pvValueMaster->getOffset() " << pvValueMaster->getFieldOffset(); }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    bitSet->clear();
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + 1.0;
    const shared_vector<const double> zzz(freeze(values));
    pvValueMaster->putFrom(zzz);
    if(debug) { cout << "before updateCopyFromBitSet"; }
    if(debug) { cout << " masterValue " << *pvValueMaster << endl; }
    if(debug) { cout << " copyValue " << *pvValueCopy << endl; }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    bitSet->set(0);
    pvValueCopy->getAs(cvalues);
    testOk1(cvalues[0]==0.06);
    pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
    pvValueCopy->getAs(cvalues);
    testOk1(cvalues[0]==1.0);
    if(debug) { cout << "after updateCopyFromBitSet"; }
    if(debug) { cout << " masterValue " << *pvValueMaster << endl; }
    if(debug) { cout << " copyValue " << *pvValueCopy << endl; }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + 2.0;
    const shared_vector<const double> ttt(freeze(values));
    pvValueMaster->putFrom(ttt);
    bitSet->set(0);
    if(debug) { cout << "before updateMaster"; }
    if(debug) { cout << " masterValue " << *pvValueMaster << endl; }
    if(debug) { cout << " copyValue " << *pvValueCopy << endl; }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
    pvValueMaster->getAs(cvalues);
    testOk1(cvalues[0]==2.0);
    pvCopy->updateMaster(pvStructureCopy,bitSet);
    pvValueMaster->getAs(cvalues);
    testOk1(cvalues[0]==1.0);
    if(debug) { cout << "before updateMaster"; }
    if(debug) { cout << " masterValue " << *pvValueMaster << endl; }
    if(debug) { cout << " copyValue " << *pvValueCopy << endl; }
    if(debug) { cout << " bitSet " << *bitSet; }
    if(debug) { cout << endl; }
}
示例#9
0
static void test()
{
    std::ostringstream oss;
    
    testDiag("\ntestBitSetUtil\n");
    StringArray fieldNames;
    PVFieldPtrArray pvFields;
    fieldNames.reserve(5);
    pvFields.reserve(5);
    fieldNames.push_back("timeStamp");
    fieldNames.push_back("alarm");
    fieldNames.push_back("voltage");
    fieldNames.push_back("power");
    fieldNames.push_back("current");
    pvFields.push_back(
        pvDataCreate->createPVStructure(standardField->timeStamp()));
    pvFields.push_back(
        pvDataCreate->createPVStructure(standardField->alarm()));
    pvFields.push_back(
        pvDataCreate->createPVStructure(
            standardField->scalar(pvDouble,"alarm")));
    pvFields.push_back(
        pvDataCreate->createPVStructure(
            standardField->scalar(pvDouble,"alarm")));
    pvFields.push_back(
        pvDataCreate->createPVStructure(
            standardField->scalar(pvDouble,"alarm")));
    PVStructurePtr pvs =  pvDataCreate->createPVStructure(
         fieldNames,pvFields);

    int32 nfields = (int32)pvs->getNumberFields();
    BitSetPtr bitSet = BitSet::create(nfields);
    for(int32 i=0; i<nfields; i++) bitSet->set(i);

    BitSetUtil::compress(bitSet,pvs);

    bitSet->clear();
    PVFieldPtr pvField = pvs->getSubField<PVStructure>("timeStamp");
    int32 offsetTimeStamp = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVLong>("timeStamp.secondsPastEpoch");
    int32 offsetSeconds = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVInt>("timeStamp.nanoseconds");
    int32 offsetNano = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVInt>("timeStamp.userTag");
    int32 offsetUserTag = (int32)pvField->getFieldOffset();
    bitSet->set(offsetSeconds);
    BitSetUtil::compress(bitSet,pvs);
    testOk1(bitSet->get(offsetSeconds)==true);
    bitSet->set(offsetNano);
    bitSet->set(offsetUserTag);

    BitSetUtil::compress(bitSet,pvs);
    testOk1(bitSet->get(offsetSeconds)==false);
    testOk1(bitSet->get(offsetTimeStamp)==true);

    bitSet->clear();

    pvField = pvs->getSubField<PVStructure>("current");
    int32 offsetCurrent = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVDouble>("current.value");
    int32 offsetValue = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVStructure>("current.alarm");
    int32 offsetAlarm = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVInt>("current.alarm.severity");
    int32 offsetSeverity = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVInt>("current.alarm.status");
    int32 offsetStatus = (int32)pvField->getFieldOffset();
    pvField = pvs->getSubField<PVString>("current.alarm.message");
    int32 offsetMessage = (int32)pvField->getFieldOffset();
    bitSet->set(offsetValue);
    bitSet->set(offsetSeverity);
    bitSet->set(offsetStatus);
    bitSet->set(offsetMessage);

    BitSetUtil::compress(bitSet,pvs);

    testOk1(bitSet->get(offsetCurrent)==true);
    bitSet->clear();
    bitSet->set(offsetSeverity);
    bitSet->set(offsetStatus);
    bitSet->set(offsetMessage);

    BitSetUtil::compress(bitSet,pvs);

    testOk1(bitSet->get(offsetAlarm)==true);
    bitSet->clear();
    printf("testBitSetUtil PASSED\n");
}
示例#10
0
static void testPVScalar(
    string const & valueNameRecord,
    string const & valueNameCopy,
    PVRecordPtr const & pvRecord,
    PVCopyPtr const & pvCopy)
{
    PVStructurePtr pvStructureRecord;
    PVStructurePtr pvStructureCopy;
    PVFieldPtr pvField;
    PVScalarPtr pvValueRecord;
    PVScalarPtr pvValueCopy;
    BitSetPtr bitSet;
    size_t offset;
    ConvertPtr convert = getConvert();

    cout << endl;
    pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
    pvField = pvStructureRecord->getSubField(valueNameRecord);
    pvValueRecord = static_pointer_cast<PVScalar>(pvField);
    convert->fromDouble(pvValueRecord,.04);
    StructureConstPtr structure = pvCopy->getStructure();
    cout << "structure from copy" << endl << *structure << endl;
    pvStructureCopy = pvCopy->createPVStructure();
    pvField = pvStructureCopy->getSubField(valueNameCopy);
    pvValueCopy = static_pointer_cast<PVScalar>(pvField);
    bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
    pvCopy->initCopy(pvStructureCopy, bitSet);
    cout << "after initCopy pvValueCopy " << convert->toDouble(pvValueCopy);
    cout << endl;
    convert->fromDouble(pvValueRecord,.06);
    pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
    cout << "after put(.06) pvValueCopy " << convert->toDouble(pvValueCopy);
    cout << " bitSet " << *bitSet;
    cout << endl;
    offset = pvCopy->getCopyOffset(pvValueRecord);
    cout << "getCopyOffset() " << offset;
    cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset();
    cout << " pvValueRecord->getOffset() " << pvValueRecord->getFieldOffset();
    cout << " bitSet " << *bitSet;
    cout << endl;
    bitSet->clear();
    convert->fromDouble(pvValueRecord,1.0);
    cout << "before updateCopyFromBitSet";
    cout << " recordValue " << convert->toDouble(pvValueRecord);
    cout << " copyValue " << convert->toDouble(pvValueCopy);
    cout << " bitSet " << *bitSet;
    cout << endl;
    bitSet->set(0);
    pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
    cout << "after updateCopyFromBitSet";
    cout << " recordValue " << convert->toDouble(pvValueRecord);
    cout << " copyValue " << convert->toDouble(pvValueCopy);
    cout << " bitSet " << *bitSet;
    cout << endl;
    convert->fromDouble(pvValueCopy,2.0);
    bitSet->set(0);
    cout << "before updateMaster";
    cout << " recordValue " << convert->toDouble(pvValueRecord);
    cout << " copyValue " << convert->toDouble(pvValueCopy);
    cout << " bitSet " << *bitSet;
    cout << endl;
    pvCopy->updateMaster(pvStructureCopy,bitSet);
    cout << "after updateMaster";
    cout << " recordValue " << convert->toDouble(pvValueRecord);
    cout << " copyValue " << convert->toDouble(pvValueCopy);
    cout << " bitSet " << *bitSet;
    cout << endl;
}
示例#11
0
static void testPVScalarArray(
    ScalarType scalarType,
    string const & valueNameRecord,
    string const & valueNameCopy,
    PVRecordPtr const & pvRecord,
    PVCopyPtr const & pvCopy)
{
    PVStructurePtr pvStructureRecord;
    PVStructurePtr pvStructureCopy;
    PVScalarArrayPtr pvValueRecord;
    PVScalarArrayPtr pvValueCopy;
    BitSetPtr bitSet;
    size_t offset;
    size_t n = 5;
    shared_vector<double> values(n);
    cout << endl;
    pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
    pvValueRecord = pvStructureRecord->getScalarArrayField(valueNameRecord,scalarType);
    for(size_t i=0; i<n; i++) values[i] = i;
    const shared_vector<const double> xxx(freeze(values));
    pvValueRecord->putFrom(xxx);
    StructureConstPtr structure = pvCopy->getStructure();
    cout << "structure from copy" << endl << *structure << endl;
    pvStructureCopy = pvCopy->createPVStructure();
    pvValueCopy = pvStructureCopy->getScalarArrayField(valueNameCopy,scalarType);
    bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
    pvCopy->initCopy(pvStructureCopy, bitSet);
    cout << "after initCopy pvValueCopy " << *pvValueCopy << endl;
    cout << endl;
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + .06;
    const shared_vector<const double> yyy(freeze(values));
    pvValueRecord->putFrom(yyy);
    pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet);
    cout << "after put(i+ .06) pvValueCopy " << *pvValueCopy << endl;
    cout << " bitSet " << *bitSet;
    cout << endl;
    offset = pvCopy->getCopyOffset(pvValueRecord);
    cout << "getCopyOffset() " << offset;
    cout << " pvValueCopy->getOffset() " << pvValueCopy->getFieldOffset();
    cout << " pvValueRecord->getOffset() " << pvValueRecord->getFieldOffset();
    cout << " bitSet " << *bitSet;
    cout << endl;
    bitSet->clear();
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + 1.0;
    const shared_vector<const double> zzz(freeze(values));
    pvValueRecord->putFrom(zzz);
    cout << "before updateCopyFromBitSet";
    cout << " recordValue " << *pvValueRecord << endl;
    cout << " copyValue " << *pvValueCopy << endl;
    cout << " bitSet " << *bitSet;
    cout << endl;
    bitSet->set(0);
    pvCopy->updateCopyFromBitSet(pvStructureCopy,bitSet);
    cout << "after updateCopyFromBitSet";
    cout << " recordValue " << *pvValueRecord << endl;
    cout << " copyValue " << *pvValueCopy << endl;
    cout << " bitSet " << *bitSet;
    cout << endl;
    values.resize(n);
    for(size_t i=0; i<n; i++) values[i] = i + 2.0;
    const shared_vector<const double> ttt(freeze(values));
    pvValueRecord->putFrom(ttt);
    bitSet->set(0);
    cout << "before updateMaster";
    cout << " recordValue " << *pvValueRecord << endl;
    cout << " copyValue " << *pvValueCopy << endl;
    cout << " bitSet " << *bitSet;
    cout << endl;
    pvCopy->updateMaster(pvStructureCopy,bitSet);
    cout << "after updateMaster";
    cout << " recordValue " << *pvValueRecord << endl;
    cout << " copyValue " << *pvValueRecord << endl;
    cout << " bitSet " << *bitSet;
    cout << endl;
}
static void testDouble()
{
    testDiag("== testDouble ==");
    StructureConstPtr structure =
        fieldCreate->createFieldBuilder() ->
            add("alarm",standardField->alarm()) ->
            add("timeStamp",standardField->timeStamp()) ->
            add("value",pvDouble) ->
            createStructure();

    PvaClientPutDataPtr pvaData = PvaClientPutData::create(structure);
    PVDoublePtr pvDouble = pvaData->getPVStructure() ->
        getSubField<PVDouble>("value");
    pvDouble->put(5.0);

    BitSetPtr change = pvaData->getChangedBitSet();
    size_t valueOffset = pvDouble->getFieldOffset();
    testOk(change->cardinality()==1,"1 field changed");
    testOk(change->get(valueOffset),"value changed");

    testOk(pvaData->hasValue(),"hasValue");
    testOk(pvaData->isValueScalar(),"isValueScalar");
    testOk(!pvaData->isValueScalarArray(),"!isValueScalarArray");

    try {
        testOk(!!pvaData->getValue(), "getValue");
    } catch (std::runtime_error e) {
        testFail("getValue exception '%s'", e.what());
    }

    try {
        testOk(!!pvaData->getScalarValue(), "getScalarValue");
    } catch (std::runtime_error e) {
        testFail("getScalarValue exception '%s'", e.what());
    }
    try {
        testOk(!pvaData->getArrayValue(), "!getArrayValue");
    } catch (std::runtime_error e) {
        testPass("getArrayValue exception '%s'", e.what());
    }
    try {
        testOk(!pvaData->getScalarArrayValue(), "!getScalarArrayValue");
    } catch (std::runtime_error e) {
        testPass("getScalarArrayValue exception '%s'", e.what());
    }

    try {
        testOk(pvaData->getDouble() == 5.0, "getDouble value");
    } catch (std::runtime_error e) {
        testFail("getDouble exception '%s'", e.what());
    }
    try {
        testOk(pvaData->getString() == "5", "getString value");
    } catch (std::runtime_error e) {
        testFail("getString exception '%s'", e.what());
    }

    try {
        shared_vector<const double> value = pvaData->getDoubleArray();
        testFail("getDoubleArray");
    } catch (std::runtime_error e) {
        testPass("getDoubleArray exception '%s'", e.what());
    }
    try {
        shared_vector<const string> value = pvaData->getStringArray();
        testFail("getStringArray");
    } catch (std::runtime_error e) {
        testPass("getStringArray exception '%s'", e.what());
    }

    try {
        pvaData->putDouble(5.0);
        testPass("putDouble");
    } catch (std::runtime_error e) {
        testFail("putDouble exception '%s'", e.what());
    }
    try {
        pvaData->putString("1e5");
        testPass("putString");
    } catch (std::runtime_error e) {
        testFail("putString exception '%s'", e.what());
    }

    try {
        size_t len = 2;
        shared_vector<double> val(len);
        for (size_t i=0; i<len; ++i)
            val[i] = (i+1) * 10.0;
        pvaData->putDoubleArray(freeze(val));
        testFail("putDoubleArray");
    } catch (std::runtime_error e) {
        testPass("putDoubleArray exception '%s'", e.what());
    }
    try {
        size_t len = 2;
        shared_vector<string> val(len);
        val[0] = "one"; val[1] = "two";
        pvaData->putStringArray(freeze(val));
        testFail("putStringArray");
    } catch (std::runtime_error e) {
        testPass("putStringArray exception '%s'", e.what());
    }
}