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 userTag
For 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 userTag
For 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]'