NOTES:
This product is available via an open source license
This document provides a description of the JSON support provided by pvaClientCPP. The put support is modeled on the JSON syntax for pvput. The get support is modeled on the JSON syntax for pvget
The following are some examples:
mrk> pvput PVRdouble '{"value":"10"}' Old : <undefined> 0 New : 2019-07-18 13:23:52.973 10 mrk> pvput PVRdouble value=10.5 Old : 2019-07-22 10:02:40.140 10 New : 2019-07-22 14:20:47.197 20 10.5 mrk> pvput PVRdoubleArray '{"value":["10","20"]}' Old : <undefined> [] New : 2019-07-18 13:24:01.187 [10,20] mrk> pvput -r "value,alarm" PVRdouble '{"alarm":{"severity":"1","status":"2","message":"I did this"}}' Old : 10 New : 10 MINOR DRIVER I did this mrk> pvget -M json -r "value,alarm" PVRlong PVRlong {"value": 0,"alarm": {"severity": 0,"status": 0,"message": ""}}
pvput also provides extra support for a top level field named value that is a scalar or scalarArray. For example:
mrk> pvput PVRdouble 8 Old : 2019-07-18 13:23:52.973 10 New : 2019-08-04 06:24:41.856 8 mrk> pvput PVRdoubleArray [100,200,300] Old : 2019-07-18 13:24:01.187 [10,20] New : 2019-08-04 06:25:23.686 [100,200,300]
The following is a brief description of the JSON syntax for pvData. See json for a more complete description of the JSON syntax.
A PVStructure is represented by:
{...}where ... is a comma separated set of name,value pairs; One pair for each subfield in the PVStructure.
The name,value pair for each each PVData field is:
"name":<value>where name is the PVField name. and <value> is :
"value" // field must be scalar. value is the field value. or value // field must be numeric scalar or true // field must be boolean or false // field must be boolean or [<value>,<value>...] // field must be a scalarArray or {...} // field must be a structure
The JSON support implemented by pvaClientCPP uses similar syntax. This is what is described in this document.
Starting with the 3.15 releases of epics base, a JSON parser is provided.
For this document it is not necessary to describe the parser other than to say that it is required because it is used by pvDataCPP.
pvDataCPP provides JSON support for pvData objects. The user interface is described in json.h. One of the methods is:
void parseJSON(std::istream& strm, PVField& dest, BitSet *assigned=0);
For a PVField it provides the following:
Another method is:
void printJSON(std::ostream& strm, const PVStructure& val, const BitSet& mask, const JSONPrintOptions& opts = JSONPrintOptions());
pvaClientCPP uses both of the above methods.
One of the classes implemented by pvaClientCPP is PvaClientData, which has the following new methods:
void parse(const std::vector<std::string> &args); void streamJSON( std::ostream& strm, bool ignoreUnprintable = true, bool multiLine = false); void zeroArrayLength();where
This method recursively locates all array fields in the PVStructure attached to PvaClientData and sets the array length to 0.
parseJSON shown above appends scalarArray values to the current value. This is usually not what the client wants. A common way that a client uses parse is to first get the current value of the PVStructure attached to PvaClientData and then to set new values. zeroArrayLength can be called before calling parse if the client wants to set new values to array fields.
This should NOT be called if parse is being called with the special enumerated syntax shown below, because it will set choices to an empty array.
Since PvaClientData is the base data class for channelGet, channelPut, channelPutGet, and channelMonitor, it is available for use by each. The examples shown below use it for channelPut and channelPutGet.
NOTES:
Each argument provides data for fields in the current PVStructure. The syntax for each argument is one of the following:
json or field=json or field=value // enumerated or field=type=json // restricted union
parsePut PVRdouble '{"value":"10"}'
parsePut PVRBigRecord scalar.string.value='"this is a string"'
parsePut -z false PVRenum value=one
parsePut PVRrestrictedUnion value='string="test string"' parsePut PVRrestrictedUnion value='union_t=point={"x":".1","y":".2"}'
This contains examples that use the JSON methods provided with PvaClientData.
This is a command that allows a client to perform a channelPut,
with JSON format arguments.
The command provides:
parsePut -help -h -p provider -r request -z zeroarray - d debug channelName args
The source contains the following code:
PvaClientPtr pva= PvaClient::get(provider); PvaClientChannelPtr channel = pva->channel(channelName,provider,2.0); PvaClientPutPtr put = channel->put(request); PvaClientPutDataPtr putData(put->getData()); if(zeroarray) putData->zeroArrayLength(); putData->getChangedBitSet()->clear(); putData->parse(args); put->put();
Examples are shown below.
This is similar to parsePut except that it uses channelPutGet.
This is a command that display data obtained via channelGet with JSON syntax.
The command provides:
jsonGet -help -h -p provider -r request -m multiline - d debug channelName
An example is:
jsonGet -r "value,alarm" PVRstring _____jsonGet channel PVRstring provider pva request value,alarm multiline false debug false {"value": "three","alarm": {"severity": 0,"status": 0,"message": ""}}
The source contains the following code:
PvaClientPtr pva(PvaClient::get(provider)); PvaClientGetDataPtr pvData = pva->channel(channelName,provider,2.0)->get(request)->getData(); std::ostringstream os; pvData->streamJSON(os,true,multiline); cout << os.str() << "\n";
json/client/scripts has examples that use the command line tools.
In a window start the IOC:
mrk> pwd /home/epicsv4/masterCPP/exampleCPP/database/iocBoot/exampleDatabase mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd ... epics>
For example I have added the following to my path.
export PATH=$PATH:/home/epicsv4/masterCPP/exampleCPP/json/bin/${EPICS_HOST_ARCH}
Don't forget about pvlist, pvinfo, and pvget. For example:
mrk> pvinfo PVRrestrictedUnion PVRrestrictedUnion Server: 10.0.0.48:5075 Type: epics:nt/NTUnion:1.0 union value string string string[] stringArray structure point double x double y union union_t string string string[] stringArray structure point double x double y time_t timeStamp long secondsPastEpoch int nanoseconds int userTag mrk> pvget -r "" PVRrestrictedUnion PVRrestrictedUnion epics:nt/NTUnion:1.0 union value (none) time_t timeStamp <undefined> long secondsPastEpoch 0 int nanoseconds 0 int userTag 0 mrk> parsePut PVRrestrictedUnion value='string="test string"' _____parsePut channel PVRrestrictedUnion provider pva request zeroarray true debug false mrk> pvget -r "" PVRrestrictedUnion PVRrestrictedUnion epics:nt/NTUnion:1.0 union value string test string time_t timeStamp 2019-08-03 07:00:12.608 long secondsPastEpoch 1564830012 int nanoseconds 607894337 int userTag 0 mrk> mrk> pvlist GUID 0x2569455D000000007930A800 version 2: tcp@[10.0.0.48:5075, 192.168.124.1:5075] mrk> pvlist 0x2569455D000000007930A800 DBRint00 DBRint01 DBRstring00 ... DBRdouble DBRdouble00 ... DBRao01 DBRenum01 DBRmbbo00 DBRmbbo01 DBRcounter01 DBRcalc00 DBRmbbiwierd DBRstringArray01 DBRdoubleArray DBRbyteArray01 DBRshortArray01 DBRintArray01 DBRfloatArray01 DBRdoubleArray01 DBRbo00 DBRbo01 PVRBigRecord PVRboolean PVRbooleanArray PVRbyte PVRbyteArray PVRdouble PVRdouble01 PVRdouble01Array PVRdouble02 PVRdouble02Array PVRdouble03 PVRdouble03Array PVRdouble04 PVRdouble04Array PVRdouble05 PVRdouble05Array PVRdoubleArray PVRdumbPowerSupply PVRenum PVRfloat PVRfloatArray PVRhelloPutGet PVRhelloRPC PVRint PVRintArray PVRlong PVRlongArray PVRremoveRecord PVRrestrictedUnion PVRrestrictedUnionArray PVRshort PVRshortArray PVRsoft PVRstring PVRstringArray PVRstructureArray PVRtraceRecord PVRubyte PVRubyteArray PVRuint PVRuintArray PVRulong PVRulongArray PVRushort PVRushortArray PVRvariantUnion PVRvariantUnionArray
Also monitoring changes is usefull for seeing the result of running the examples. For example in one window run:
mrk> pvget -m -r "" PVRrestrictedUnion PVRrestrictedUnion epics:nt/NTUnion:1.0 union value (none) time_t timeStamp <undefined> long secondsPastEpoch 0 int nanoseconds 0 int userTag 0
Then in another window run:
mrk> pwd /home/epicsv4/masterCPP/exampleCPP/json/client/scripts mrk> ./exampleUnion
In the monitor window you will see:
PVRrestrictedUnion epics:nt/NTUnion:1.0 union value string test string time_t timeStamp 2019-08-03 10:53:40.260 long secondsPastEpoch 1564844020 int nanoseconds 260336547 PVRrestrictedUnion epics:nt/NTUnion:1.0 union value string[] ["test string", "two"] time_t timeStamp 2019-08-03 10:53:40.804 int nanoseconds 803675341 PVRrestrictedUnion epics:nt/NTUnion:1.0 union value structure double x 0.1 double y 0.2 time_t timeStamp 2019-08-03 10:53:41.324 long secondsPastEpoch 1564844021 int nanoseconds 324152690 PVRrestrictedUnion epics:nt/NTUnion:1.0 union value union string test time_t timeStamp 2019-08-03 10:53:41.843 int nanoseconds 843287469 PVRrestrictedUnion epics:nt/NTUnion:1.0 union value union structure double x 0.1 double y 0.2 time_t timeStamp 2019-08-03 10:53:42.361 long secondsPastEpoch 1564844022 int nanoseconds 360729910
This example is for records like the following:
mrk> pvinfo PVRdouble PVRdouble Server: 10.0.0.48:5075 Type: epics:nt/NTScalar:1.0 double value alarm_t alarm int severity int status string message time_t timeStamp long secondsPastEpoch int nanoseconds int userTagFor each record value ls a scalar.
exampleScalar is
#!/bin/sh source ./setEnv ${PARSE}/parsePut -r "value" PVRdouble value=1 sleep .5 ${PARSE}/parsePut -r "value" PVRdouble '{"value":2}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRdouble value=10 sleep .5 ${PARSE}/parsePut -r "value" PVRstring value='"one"' sleep .5 ${PARSE}/parsePut -r "value" PVRstring '{"value":"two"}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRstring value='"three"' sleep .5 ${PARSE}/parsePut -r "value" PVRboolean value=true sleep .5 ${PARSE}/parsePut -r "value" PVRboolean '{"value":false}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRboolean value=true sleep .5 ${PARSE}/parsePut -r "value" DBRdouble value=1 sleep .5 ${PARSE}/parsePut -r "value" -p ca DBRdouble value=5 sleep .5 ${PARSE}/parsePut -r "value" DBRstring00 value='"one"' sleep .5 ${PARSE}/parsePut -r "value" -p ca DBRstring00 value='"two"'
Running it produces:
./exampleScalar _____parsePut channel PVRdouble provider pva request value zeroarray true debug false _____parsePut channel PVRdouble provider pva request value zeroarray true debug false _____parsePutGet channel PVRdouble provider pva request putField(value)getField(value) zeroarray true debug false structure double value 10 _____parsePut channel PVRstring provider pva request value zeroarray true debug false _____parsePut channel PVRstring provider pva request value zeroarray true debug false _____parsePutGet channel PVRstring provider pva request putField(value)getField(value) zeroarray true debug false structure string value three _____parsePut channel PVRboolean provider pva request value zeroarray true debug false _____parsePut channel PVRboolean provider pva request value zeroarray true debug false _____parsePutGet channel PVRboolean provider pva request putField(value)getField(value) zeroarray true debug false structure boolean value true _____parsePut channel DBRdouble provider pva request value zeroarray true debug false _____parsePut channel DBRdouble provider ca request value zeroarray true debug false _____parsePut channel DBRstring00 provider pva request value zeroarray true debug false _____parsePut channel DBRstring00 provider ca request value zeroarray true debug false
This example is for records like the following:
mrk> pvinfo PVRdoubleArray PVRdoubleArray Server: 10.0.0.48:5075 Type: epics:nt/NTScalarArray:1.0 double[] value alarm_t alarm int severity int status string message time_t timeStamp long secondsPastEpoch int nanoseconds int userTagFor each record value ls a scalarArray.
exampleScalarArray is:
source ./setEnv ${PARSE}/parsePut -r "" PVRdoubleArray value='[1,2,3]' sleep .5 ${PARSE}/parsePut -r "" DBRdoubleArray value='[1,2,3]' sleep .5 ${PARSE}/parsePut -r "" PVRdoubleArray '{"value":[10,20,30]}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRdoubleArray value='[100,200,300]' sleep .5 ${PARSE}/parsePut -r "" PVRstringArray value='["one","two","three"]' sleep .5 ${PARSE}/parsePut -r "" DBRstringArray01 value='["one","two","three"]' sleep .5 ${PARSE}/parsePut -r "" PVRstringArray '{"value":["one again","two again","three again"]}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRstringArray value='["once more","two again","three again"]' sleep .5 ${PARSE}/parsePut -r "" PVRbooleanArray value='[true,false,true]' sleep .5 ${PARSE}/parsePut -r "" PVRbooleanArray '{"value":[false,true,false]}' sleep .5 ${PARSE}/parsePutGet -r "putField(value)getField(value)" PVRbooleanArray value='[true,false,true]'
This example is for records like the following:
mrk> pvinfo PVRenum PVRenum Server: 10.0.0.48:5075 Type: epics:nt/NTEnum:1.0 enum_t value int index string[] choices alarm_t alarm int severity int status string message time_t timeStamp long secondsPastEpoch int nanoseconds int userTag
exampleEnum is:
#!/bin/sh source ./setEnv ${PARSE}/parsePut -z false PVRenum value=one sleep .5 ${PARSE}/parsePut -z false DBRenum01 value=one sleep .5 ${PARSE}/parsePutGet -z false -r "putField(value)getField(value)" PVRenum value=zero sleep .5 ${PARSE}/parsePut -z false -p ca DBRenum01 value=zero sleep .5 ${PARSE}/parsePut PVRenum '{"value":{"index":1}}'
This example is for the following record:
mrk> pvinfo PVRrestrictedUnion PVRrestrictedUnion Server: 10.0.0.48:5075 Type: epics:nt/NTUnion:1.0 union value string string string[] stringArray structure point double x double y union union_t string string string[] stringArray structure point double x double y time_t timeStamp long secondsPastEpoch int nanoseconds int userTag
exampleUnion is:
#!/bin/sh source ./setEnv ${PARSE}/parsePut PVRrestrictedUnion value='string="test string"' sleep .5 ${PARSE}/parsePut PVRrestrictedUnion value='stringArray=["test string","two"]' sleep .5 ${PARSE}/parsePut PVRrestrictedUnion value='point={"x":".1","y":".2"}' sleep .5 ${PARSE}/parsePut PVRrestrictedUnion value='union_t=string="test"' sleep .5 ${PARSE}/parsePut PVRrestrictedUnion value='union_t=point={"x":".1","y":".2"}'
This example is for the following record:
mrk> pvinfo PVRBigRecord PVRBigRecord Server: 10.0.0.48:5075 Type: structure time_t timeStamp long secondsPastEpoch int nanoseconds int userTag structure scalar structure boolean boolean value structure byte byte value structure long long value structure double double value structure string string value structure scalarArray structure boolean boolean[] value structure byte byte[] value structure long long[] value structure double double[] value structure string string[] value structure[] structureArray structure string name string value union restrictedUnion string string string[] stringArray any variantUnion
exampleBigRecord is:
#!/bin/sh source ./setEnv ${PARSE}/parsePut sleep .5 ${PARSE}/parsePut -r "" PVRBigRecord scalar.double.value=10 scalarArray.double.value='[100,200]' sleep .5 ${PARSE}/parsePut -r "" PVRBigRecord '{"scalar":{"double":{"value":20}}}' '{"scalarArray":{"double":{"value":[1000,2000]}}}' sleep .5 ${PARSE}/parsePut -r "" PVRBigRecord scalar.double.value=10 scalar.string.value='" this is a string"' sleep .5 ${PARSE}/parsePut -r "" PVRBigRecord '{"scalar":{"double":{"value":20},"string":{"value":"this is also a string"}}}' sleep .5 ${PARSE}/parsePutGet -r "putField(),getField(scalar.double,scalarArray.double)" PVRBigRecord scalar.double.value=10 scalarArray.double.value='[100,200]'