After looking at the source code and doing some tests using PvaClient::setDebug(), I’ve learned that PvaClientNTMultiMonitor->poll() doesn’t bring the data structure for the channels that had no change since
the last poll. For these channels the data at the vectors looks like is only garbage.
The only way that I’ve managed to check if the channel was changed is by looking if “values[i]” is none. PvaClientNTMultiMonitor doesn’t provide a sort of hasChanged bool vector. If checking for “none” is
what is expected I would suggest it to be written on the documentation.
I’ve placed an issue on the PvaClientCPP module on GitHub suggesting this feature.
Thank you,
Márcio Paduan Donadio
Control Systems Engineer - SLAC
From:
Tech-talk <tech-talk-bounces at aps.anl.gov>
Date: Thursday, January 7, 2021 at 8:58 PM
To: EPICS tech-talk <tech-talk at aps.anl.gov>
Subject: PvaClientMultiChannel CPP: multiGet get() looks like to interfere with multiMonitor waitEvent()
I’m playing with PvaClientNTMulti and can’t understand some of the behaviors. I’m using EPICS 7.0.3.
Please, check part of the source code in the end of this email. I’ve created a PvaClientMultiChannel with 4 existent PVs. In a loop I’ve issued a multiMonitor waitEvent(1), got some data, print it, then issued
a multiGet get(), got the same data, and printed it. In the first pass of the loop the data from the monitor agree with the get(). But in the second pass, the message from the monitor says “Not connected” and the message from get() still shows “UDF” for the
last channel. Even though, isConnected[3] is still true. Also, the value for the last channel come as (none) and the timestamp as zero in the second pass of the monitor, different from get().
Return from multiMonitor, item 0
any[] value
any
double value 5.27338e-13
any
double value 5.73043e-13
any
double value 1.10038e-12
any
double value 0
Severity: [0,0,0,3]
["NO_ALARM", "NO_ALARM", "NO_ALARM", "UDF"]
isConnected: [true,true,true,true]
secondsPastEpoch: [1610078476,1610078476,1610078476,631152000]
Return from multiGet, item 0
any[] value
any
double value 5.27338e-13
any
double value 5.73043e-13
any
double value 1.10038e-12
any
double value 0
Severity: [0,0,0,3]
["NO_ALARM", "NO_ALARM", "NO_ALARM", "UDF"]
isConnected: [true,true,true,true]
secondsPastEpoch: [1610078476,1610078476,1610078476,631152000]
Return from multiMonitor, item 1
any[] value
any
double value 5.12687e-13
any
double value 5.38479e-13
any
double value 1.05117e-12
(none)
Severity: [0,0,0,3]
["NO_ALARM", "NO_ALARM", "NO_ALARM", "not connected"]
isConnected: [true,true,true,true]
secondsPastEpoch: [1610078477,1610078477,1610078477,0]
Return from multiGet, item 1
any[] value
any
double value 5.12687e-13
any
double value 5.38479e-13
any
double value 1.05117e-12
any
double value 0
Severity: [0,0,0,3]
["NO_ALARM", "NO_ALARM", "NO_ALARM", "UDF"]
isConnected: [true,true,true,true]
secondsPastEpoch: [1610078477,1610078477,1610078477,631152000]
In another experiment, I commented out the get() part of the loop, having only the waitEvent one. Now I get almost nothing in the prints:
Return from multiMonitor, item 0
any[] value
(none)
(none)
(none)
any
double value 0
Severity: [3,3,3,3]
["not connected", "not connected", "not connected", "UDF"]
isConnected: [true,true,true,true]
secondsPastEpoch: [0,0,0,631152000]
Return from multiMonitor, item 1
any[] value
(none)
(none)
(none)
(none)
Severity: [3,3,3,3]
["not connected", "not connected", "not connected", "not connected"]
isConnected: [true,true,true,true]
secondsPastEpoch: [0,0,0,0]
So, something happens when I call multiGet->get() before multiMonitor->waitEvent(). I’m probably missing something here. What is the right way to use waitEvent()? What about waitEvent() vs poll()?
Another thing is that I’d like to have waitEvent() bringing the full contents of the channels, but I see that internally it calls poll() using the default “value only” option. Don’t you think it would be useful
to have waitEvent with 2 parameters: timeout and valueOnly?
/*
Code to create the multi channel with the PV names are not shown
PvaClientMultiChannelPtr multichannel (…)
*/
PvaClientNTMultiGetPtr multiGet(multiChannel->createNTGet());
PvaClientNTMultiMonitorPtr multiMonitor(multiChannel->createNTMonitor());
PVUnionArrayPtr values;
PVIntArrayPtr severity;
PVStringArrayPtr message;
PVBooleanArrayPtr isConnected;
PVLongArrayPtr secondsPastEpoch;
bool result;
int channelSize;
NTMultiChannelPtr multiPtr;
for (int iii=0; iii<2; ++iii) {
result = multiMonitor->waitEvent(1);
if(result) {
multiPtr = multiMonitor->getData()->getNTMultiChannel();
values = multiPtr->getValue();
severity = multiPtr->getSeverity();
message = multiPtr->getMessage();
isConnected = multiPtr->getIsConnected();
secondsPastEpoch = multiPtr->getSecondsPastEpoch();
cout << endl << "Return from multiMonitor, item " << iii << endl;
cout << values << endl;
cout << "Severity: " << severity << endl;
cout << message << endl;
cout << "isConnected: " << isConnected << endl;
cout << "secondsPastEpoch: " << secondsPastEpoch << endl;
}
multiGet->get(true);
multiPtr = multiGet->getData()->getNTMultiChannel();
values = multiPtr->getValue();
severity = multiPtr->getSeverity();
message = multiPtr->getMessage();
isConnected = multiPtr->getIsConnected();
secondsPastEpoch = multiPtr->getSecondsPastEpoch();
cout << endl << "Return from multiGet, item " << iii << endl;
cout << values << endl;
cout << "Severity: " << severity << endl;
cout << message << endl;
cout << "isConnected: " << isConnected << endl;
cout << "secondsPastEpoch: " << secondsPastEpoch << endl;
}
Thank you,
Márcio Paduan Donadio
Control Systems Engineer - SLAC