pvaClientCPP 4.8.1
pvaClientData.cpp
Go to the documentation of this file.
1/* pvaClientData.cpp */
12#include <typeinfo>
13#include <sstream>
14#include <istream>
15#include <ostream>
16
17#include <pv/createRequest.h>
18#include <pv/convert.h>
19#include <pv/pvEnumerated.h>
20
21#if EPICS_VERSION_INT>=VERSION_INT(3,15,0,1)
22# include <pv/json.h>
23# define USE_JSON
24#endif
25
26#define epicsExportSharedSymbols
27
28#include <pv/pvaClient.h>
29
30using std::tr1::static_pointer_cast;
31using namespace epics::pvData;
32using namespace epics::pvAccess;
33using namespace std;
34
35namespace epics { namespace pvaClient {
36
37
38typedef std::tr1::shared_ptr<PVArray> PVArrayPtr;
39static ConvertPtr convert = getConvert();
40static string noStructure("no pvStructure ");
41static string noValue("no value field");
42static string noScalar("value is not a scalar");
43static string noArray("value is not an array");
44static string noScalarArray("value is not a scalarArray");
45static string noAlarm("no alarm");
46static string noTimeStamp("no timeStamp");
47
48PvaClientDataPtr PvaClientData::create(StructureConstPtr const & structure)
49{
50 if(PvaClient::getDebug()) cout << "PvaClientData::create\n";
51 PvaClientDataPtr epv(new PvaClientData(structure));
52 return epv;
53}
54
55PvaClientData::PvaClientData(StructureConstPtr const & structure)
56: structure(structure)
57{
58}
59
61{
62 if(PvaClient::getDebug()) cout << "PvaClientData::getSinglePVField\n";
63 PVStructurePtr pvStructure = getPVStructure();
64 while(true) {
65 const PVFieldPtrArray fieldPtrArray(pvStructure->getPVFields());
66 if(fieldPtrArray.size()==0) {
67 throw std::logic_error("PvaClientData::getSinglePVField() pvRequest for empty structure");
68 }
69 if(fieldPtrArray.size()!=1) {
70 PVFieldPtr pvValue = pvStructure->getSubField("value");
71 if(pvValue) {
72 Type type = pvValue->getField()->getType();
73 if(type!=epics::pvData::structure) return pvValue;
74 }
75 throw std::logic_error("PvaClientData::getSinglePVField() pvRequest for multiple fields");
76 }
77 PVFieldPtr pvField(fieldPtrArray[0]);
78 Type type = pvField->getField()->getType();
79 if(type!=epics::pvData::structure) return pvField;
80 pvStructure = static_pointer_cast<PVStructure>(pvField);
81 }
82}
83
85{
86 if(PvaClient::getDebug()) cout << "PvaClientData::checkValue\n";
87 if(pvValue) return;
88 throw std::runtime_error(messagePrefix + noValue);
89}
90
91void PvaClientData::setMessagePrefix(std::string const & value)
92{
93 messagePrefix = value + " ";
94}
95
96StructureConstPtr PvaClientData::getStructure()
97{
98 return structure;
99}
100
102{
103 if(pvStructure) return pvStructure;
104 throw std::runtime_error(messagePrefix + noStructure);
105}
106
108{
109 if(bitSet)return bitSet;
110 throw std::runtime_error(messagePrefix + noStructure);
111}
112
113std::ostream & PvaClientData::showChanged(std::ostream & out)
114{
115 if(!bitSet) throw std::runtime_error(messagePrefix + noStructure);
116 size_t nextSet = bitSet->nextSetBit(0);
117 PVFieldPtr pvField;
118 while(nextSet!=string::npos) {
119 if(nextSet==0) {
120 pvField = pvStructure;
121 } else {
122 pvField = pvStructure->getSubField(nextSet);
123 }
124 string name = pvField->getFullName();
125 out << name << " = " << pvField << endl;
126 nextSet = bitSet->nextSetBit(nextSet+1);
127 }
128 return out;
129}
130
132 PVStructurePtr const & pvStructureFrom,
133 BitSetPtr const & bitSetFrom)
134{
135 if(PvaClient::getDebug()) cout << "PvaClientData::setData\n";
136 pvStructure = pvStructureFrom;
137 bitSet = bitSetFrom;
138 pvValue = pvStructure->getSubField("value");
139}
140
141
143{
144 if(PvaClient::getDebug()) cout << "PvaClientData::hasValue\n";
145 if(!pvValue) return false;
146 return true;
147}
148
150{
151 if(PvaClient::getDebug()) cout << "PvaClientData::isValueScalar\n";
152 if(!pvValue) return false;
153 if(pvValue->getField()->getType()==scalar) return true;
154 return false;
155}
156
158{
159 if(PvaClient::getDebug()) cout << "PvaClientData::isValueScalarArray\n";
160 if(!pvValue) return false;
161 if(pvValue->getField()->getType()==scalarArray) return true;
162 return false;
163}
164
166{
167 if(PvaClient::getDebug()) cout << "PvaClientData::getValue\n";
168 checkValue();
169 return pvValue;
170}
171
173{
174 if(PvaClient::getDebug()) cout << "PvaClientData::getScalarValue\n";
175 checkValue();
176 if(pvValue->getField()->getType()!=scalar) {
177 throw std::runtime_error(messagePrefix + noScalar);
178 }
179 return pvStructure->getSubField<PVScalar>("value");
180}
181
183{
184 if(PvaClient::getDebug()) cout << "PvaClientData::getArrayValue\n";
185 checkValue();
186 Type type = pvValue->getField()->getType();
187 if(type!=scalarArray && type!=structureArray && type!=unionArray) {
188 throw std::runtime_error(messagePrefix + noArray);
189 }
190 return pvStructure->getSubField<PVArray>("value");
191}
192
194{
195 if(PvaClient::getDebug()) cout << "PvaClientData::getScalarArrayValue\n";
196 checkValue();
197 Type type = pvValue->getField()->getType();
198 if(type!=scalarArray) {
199 throw std::runtime_error(messagePrefix + noScalarArray);
200 }
201 return pvStructure->getSubField<PVScalarArray>("value");
202}
203
205{
206 if(PvaClient::getDebug()) cout << "PvaClientData::getDouble\n";
207 PVFieldPtr pvField = getSinglePVField();
208 Type type = pvField->getField()->getType();
209 if(type!=scalar) {
210 throw std::logic_error("PvaClientData::getDouble() did not find a scalar field");
211 }
212 PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
213 ScalarType scalarType = pvScalar->getScalar()->getScalarType();
214 if(scalarType==pvDouble) {
215 PVDoublePtr pvDouble = static_pointer_cast<PVDouble>(pvScalar);
216 return pvDouble->get();
217 }
218 if(!ScalarTypeFunc::isNumeric(scalarType)) {
219 throw std::logic_error(
220 "PvaClientData::getDouble() did not find a numeric scalar field");
221 }
222 return convert->toDouble(pvScalar);
223}
224
226{
227 if(PvaClient::getDebug()) cout << "PvaClientData::getString\n";
228 PVFieldPtr pvField = getSinglePVField();
229 Type type = pvField->getField()->getType();
230 if(type!=scalar) {
231 throw std::logic_error("PvaClientData::getString() did not find a scalar field");
232 }
233 PVScalarPtr pvScalar = static_pointer_cast<PVScalar>(pvField);
234 return convert->toString(pvScalar);
235}
236
237shared_vector<const double> PvaClientData::getDoubleArray()
238{
239 if(PvaClient::getDebug()) cout << "PvaClientData::getDoubleArray\n";
240 PVFieldPtr pvField = getSinglePVField();
241 Type type = pvField->getField()->getType();
242 if(type!=scalarArray) {
243 throw std::logic_error("PvaClientData::getDoubleArray() did not find a scalarArray field");
244 }
245 PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
246 ScalarType scalarType = pvScalarArray->getScalarArray()->getElementType();
247 if(!ScalarTypeFunc::isNumeric(scalarType)) {
248 throw std::logic_error(
249 "PvaClientData::getDoubleArray() did not find a numeric scalarArray field");
250 }
251 shared_vector<const double> retValue;
252 pvScalarArray->getAs<const double>(retValue);
253 return retValue;
254}
255
256shared_vector<const string> PvaClientData::getStringArray()
257{
258 if(PvaClient::getDebug()) cout << "PvaClientData::getStringArray\n";
259 PVFieldPtr pvField = getSinglePVField();
260 Type type = pvField->getField()->getType();
261 if(type!=scalarArray) {
262 throw std::logic_error("PvaClientData::getStringArray() did not find a scalarArray field");
263 }
264 PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
265 shared_vector<const string> retValue;
266 pvScalarArray->getAs<const string>(retValue);
267 return retValue;
268}
269
271{
272 if(PvaClient::getDebug()) cout << "PvaClientData::getAlarm\n";
273 if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
274 PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("alarm");
275 if(!pvs) throw std::runtime_error(messagePrefix + noAlarm);
276 pvAlarm.attach(pvs);
277 if(pvAlarm.isAttached()) {
278 Alarm alarm;
279 pvAlarm.get(alarm);
280 pvAlarm.detach();
281 return alarm;
282 }
283 throw std::runtime_error(messagePrefix + noAlarm);
284}
285
287{
288 if(PvaClient::getDebug()) cout << "PvaClientData::getTimeStamp\n";
289 if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
290 PVStructurePtr pvs = pvStructure->getSubField<PVStructure>("timeStamp");
291 if(!pvs) throw std::runtime_error(messagePrefix + noTimeStamp);
292 pvTimeStamp.attach(pvs);
293 if(pvTimeStamp.isAttached()) {
294 TimeStamp timeStamp;
295 pvTimeStamp.get(timeStamp);
296 pvTimeStamp.detach();
297 return timeStamp;
298 }
299 throw std::runtime_error(messagePrefix + noTimeStamp);
300}
301
303{
304 if(!pvStructure) throw new std::runtime_error(messagePrefix + noStructure);
305 zeroArrayLength(pvStructure);
306}
308 const std::string &arg,const PVFieldPtr &dest,BitSetPtr & bitSet)
309{
310#ifdef USE_JSON
311 std::istringstream strm(arg);
312 parseJSON(strm, dest,&(*bitSet));
313#else
314 throw std::runtime_error("JSON support not built");
315#endif
316}
317
319 const std::string &arg,const PVUnionPtr &pvUnion)
320{
321 if(pvUnion->getUnion()->isVariant()) {
322 throw std::runtime_error(messagePrefix + "varient union not implemented");
323 }
324 size_t iequals = arg.find_first_of('=');
325 string field;
326 string rest;
327 if(iequals==std::string::npos) {
328 string mess(arg);
329 mess += " was expected to start with field=";
330 throw std::runtime_error(messagePrefix + mess);
331 }
332 field = arg.substr(0,iequals);
333 rest = arg.substr(iequals+1);
334 PVFieldPtr pvField(pvUnion->select(field));
335 if(pvField->getField()->getType()==epics::pvData::union_) {
336 PVUnionPtr pvu = static_pointer_cast<PVUnion>(pvField);
337 parse(rest,pvu);
338 return;
339 }
340 BitSetPtr bs;
341 parse(rest,pvField,bs);
342 return;
343}
344
345void PvaClientData::parse(const std::vector<std::string> &args)
346{
347 if(!pvStructure) throw std::runtime_error(messagePrefix + noStructure);
348 if(!bitSet) throw std::runtime_error(messagePrefix + noStructure);
349 size_t num = args.size();
350 if(num<1) throw std::runtime_error(messagePrefix + " no arguments");
351 for(size_t i=0; i<num; ++i)
352 {
353 string val = args[i];
354 size_t iequals = val.find_first_of('=');
355 string field;
356 string rest(val);
357 if(iequals==std::string::npos) {
358 parse(rest,pvStructure,bitSet);
359 continue;
360 }
361 field = val.substr(0,iequals);
362 rest = val.substr(iequals+1);
363 if(field.size()==std::string::npos) {
364 parse(rest,pvStructure,bitSet);
365 continue;
366 }
367 PVFieldPtr pvField(pvStructure->getSubField(field));
368 if(!pvField) throw std::runtime_error(messagePrefix + field +" does not exist");
369 // look for enumerated structure
370 PVEnumerated pvEnumerated;
371 bool result = pvEnumerated.attach(pvField);
372 if(result) {
373 PVStringArray::const_svector choices(pvEnumerated.getChoices());
374 for(size_t i=0; i<choices.size(); ++i) {
375 if(choices[i]==rest) {
376 pvEnumerated.setIndex(i);
377 return;
378 }
379 }
380 }
381 // look for union
382 PVUnionPtr pvUnion(pvStructure->getSubField<PVUnion>(field));
383 if(pvUnion) {
384 parse(rest,pvUnion);
385 bitSet->set(pvUnion->getFieldOffset());
386 return;
387 }
388 parse(rest,pvField,bitSet);
389 }
390}
391
393 std::ostream& strm,
394 bool ignoreUnprintable,
395 bool multiLine)
396{
397#ifdef USE_JSON
398 JSONPrintOptions opts;
399 opts.ignoreUnprintable = ignoreUnprintable;
400 opts.multiLine = multiLine;
401 printJSON(strm,*pvStructure,*bitSet,opts);
402#else
403 throw std::runtime_error("JSON support not built");
404#endif
405}
406
407
408void PvaClientData::zeroArrayLength(const PVStructurePtr &pvStructure)
409{
410const PVFieldPtrArray pvFields(pvStructure->getPVFields());
411 for(size_t i=0; i<pvFields.size(); ++i) {
412 PVFieldPtr pvField = pvFields[i];
413 Type type(pvField->getField()->getType());
414 switch(type) {
415 case scalarArray:
416 {
417 PVScalarArrayPtr pvScalarArray = static_pointer_cast<PVScalarArray>(pvField);
418 pvScalarArray->setLength(0);
419 }
420 break;
421 case structureArray:
422 {
423 PVStructureArrayPtr pvStructureArray = static_pointer_cast<PVStructureArray>(pvField);
424 pvStructureArray->setLength(0);
425 }
426 break;
427 case epics::pvData::structure:
428 {
429 PVStructurePtr pvStructure = static_pointer_cast<PVStructure>(pvField);
430 zeroArrayLength(pvStructure);
431 }
432 break;
433 default:
434 break;
435 }
436 }
437}
438
439
440}}
epics::pvData::TimeStamp getTimeStamp()
Get the timeStamp. If the pvStructure has a timeStamp field, it's values are returned....
epics::pvData::PVStructurePtr getPVStructure()
Get the pvStructure.
void zeroArrayLength()
set length of all array fields to 0
epics::pvData::PVFieldPtr getValue()
Get the interface to the value field.
bool hasValue()
Is there a top level field named value.
std::tr1::shared_ptr< epics::pvData::PVScalarArray > getScalarArrayValue()
Get the interface to a scalar array value field.
std::tr1::shared_ptr< epics::pvData::PVArray > getArrayValue()
Get the interface to an array value field.
epics::pvData::StructureConstPtr getStructure()
Get the structure.
epics::pvData::Alarm getAlarm()
Get the alarm. If the pvStructure has an alarm field it's values are returned. Otherwise an exception...
epics::pvData::BitSetPtr getChangedBitSet()
Get the changed BitSet for the pvStructure.
void streamJSON(std::ostream &strm, bool ignoreUnprintable=true, bool multiLine=false)
generate JSON output from the current PVStructure and displays it on the output stream.
void parse(const std::vector< std::string > &args)
parse from args
double getDouble()
Get the value as a double.
PvaClientData(epics::pvData::StructureConstPtr const &structure)
epics::pvData::PVScalarPtr getScalarValue()
Return the interface to a scalar value field.
epics::pvData::shared_vector< const std::string > getStringArray()
Get the value as a string array.
void setData(epics::pvData::PVStructurePtr const &pvStructureFrom, epics::pvData::BitSetPtr const &bitSetFrom)
New data is present.
std::ostream & showChanged(std::ostream &out)
Show the fields that have changed value since the last get.
bool isValueScalarArray()
Is the value field a scalar array?
void setMessagePrefix(std::string const &value)
Set a prefix for throw messages.
epics::pvData::PVFieldPtr getSinglePVField()
static PvaClientDataPtr create(epics::pvData::StructureConstPtr const &structure)
bool isValueScalar()
Is the value field a scalar?
epics::pvData::shared_vector< const double > getDoubleArray()
Get the value as a double array.
static bool getDebug()
Is debug set?
Definition pvaClient.cpp:97
std::tr1::shared_ptr< PVArray > PVArrayPtr
std::tr1::shared_ptr< PvaClientData > PvaClientDataPtr
Definition pvaClient.h:49