This product is available via an open source license
scanServiceExample is an example service implemented via a PVRecord ( described in
developerGuide
).
There are actually two implementation.
One uses channelPutGet and the other uses channelRPC.
Terminology:
This example has two main goals:
This example is motivated by pvDatabaseRPC , which was created by David Hickin while he was working at the Diamond Light Source. It implements a scan service via channelRPC.
scanServiceExample is a simplified version of pvDatabaseRPC but also gives an example of using channelPutGet in addition to channelRPC.
scanServiceExample is available at: scanServiceExample
In order to fully understand this example you should clone and build it.
After it is build you can start the following servers:
mrk> pwd /home/epicsv4/masterCPP/scanServiceExample/iocBoot/scanServerPutGet mrk> ../../bin/linux-x86_64/scanServerPutGet st.cmd ... epics> pvdbl scanServerPutGetand
mrk> pwd /home/epicsv4/masterCPP/scanServiceExample/iocBoot/scanServerRPC mrk> ../../bin/linux-x86_64/scanServerRPC st.cmd ... epics> pvdbl scanServerRPC
After starting the two services you can monitor each service via the command:
pvget -r "" -m scanServerPutGet scanServerRPC
To run the client code you can run commands like:
mrk> pwd /home/epicsv4/masterCPP/scanServiceExample mrk> bin/linux-x86_64/scanClientPutGet configure .1 .1 0 0 mrk> bin/linux-x86_64/scanClientPutGet startor
mrk> pwd /home/epicsv4/masterCPP/scanServiceExample mrk> bin/linux-x86_64/scanClientRPC configure .1 .1 0 0 mrk> bin/linux-x86_64/scanClientRPC start
The scanService moves through a set of points, where a point is an x,y pair of doubles. It is used by both scanServerPutGet and scanServerRPC.
The public methods of ScanService are:
class Point
{
public:
...
double x;
double y;
};
class ScanService::Callback
{
public:
virtual void update(int flags);
const static int SETPOINT_CHANGED = 0x1;
const static int READBACK_CHANGED = 0x2;
const static int SCAN_COMPLETE = 0x4;
};
class ScanService : public epicsThreadRunable
{
...
public:
static ScanServicePtr create();
virtual void run()
...
void registerCallback(Callback::shared_pointer const & callback);
bool unregisterCallback(Callback::shared_pointer const & callback);
Point getPositionSetpoint();
Point getPositionReadback();
void configure(const std::vector<Point> & newPoints);
void startScan();
void stopScan();
void setRate(double stepDelay,double stepDistance);
void setDebug(bool value);
...
}
where:
There are two example servers:
mrk> pvinfo scanServerRPC
scanServerRPC
Type:
structure
Point positionSP
point_t value
double x
double y
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
Point positionRB
point_t value
double x
double y
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
The client issues scan requests via channelRPC requests.
pvinfo scanServerPutGet
scanServerPutGet
Type:
structure
Point positionSP
point_t value
double x
double y
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
Point positionRB
point_t value
double x
double y
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
time_t timeStamp
long secondsPastEpoch
int nanoseconds
int userTag
structure argument
string command
structure configArg
double[] x
double[] y
structure rateArg
double stepDelay
double stepDistance
structure debugArg
boolean value
structure result
string value
Note that the difference from scanServerRPC is argument and result
These are fields a client uses for channelPutGet request.
There are two example clients:
Both clients are accessed via the same user interface. If a user enters no arguments then help is displayed. For example:
mrk> pwd /home/epicsv4/masterCPP/scanServiceExample mrk> bin/linux-x86_64/scanClientRPC if interactive is specified then interactive mode is specified following are choices for non interactive mode: configure x0 y0 ... xn yn start stop setRate stepDelay stepDistance setDebug true|false
The following are some non interactive examples:
mrk> pwd
/home/epicsv4/masterCPP/scanServiceExample
mrk> bin/linux-x86_64/scanClientPutGet configure .1 .2 0 0
structure
structure result
string value configure success
mrk> bin/linux-x86_64/scanClientPutGet start
structure
structure result
string value startScan success
mrk> bin/linux-x86_64/scanClientPutGet stop
structure
structure result
string value stopScan success
mrk> bin/linux-x86_64/scanClientPutGet setDebug true
structure
structure result
string value configure success
mrk> bin/linux-x86_64/scanClientPutGet setRate .5 .1
structure
structure result
string value configure success
mrk> bin/linux-x86_64/scanClientPutGet start
structure
structure result
string value startScan success
The following is an interactive example:
mrk> bin/linux-x86_64/scanClientRPC i
enter one of: exit configure start stop setRate setDebug
configure
enter x y values
.1 .2 0 0
response
structure
string value configure success
enter one of: exit configure start stop setRate setDebug
start
response
structure
string value start success
enter one of: exit configure start stop setRate setDebug
setRate
enter stepDelay
.5
enter stepDistance
.1
response
structure
string value setRate success
enter one of: exit configure start stop setRate setDebug
configure
enter x y values
1 2 0 0
response
structure
string value configure success
enter one of: exit configure start stop setRate setDebug
start
response
structure
string value start success
enter one of: exit configure start stop setRate setDebug
exit
The following monitors setpoint and argument changes:
pvget -m -r "positionSP,argument,result" scanServerPutGet scanServerRPC
The following monitors position changes.
pvget -m -r "positionRB" scanServerPutGet scanServerRPCBe prepared for lots of updates while scanning is active.
Note the size of the source modules:
mrk> wc scanClientPutGet/scanClientPutGet.cpp scanClientRPC/scanClientRPC.cpp 318 829 11824 scanClientPutGet/scanClientPutGet.cpp 380 890 12671 scanClientRPC/scanClientRPC.cpp 693 1714 24265 total mrk> wc scanServerPutGet/scanServerPutGet.cpp scanServerRPC/scanServerRPC.cpp 263 506 8235 scanServerPutGet/scanServerPutGet.cpp 396 759 12054 scanServerRPC/scanServerRPC.cpp 659 1265 20289 total
For both client and server channelPutGet code is shorter.
With channelPutGet a client can see the arguments and result for client scan requests.
With channelPutGet a client can use pvput to interface to the scanner. For example:
pvput -r "argument" scanServerPutGet argument='{"command":"configure","configArg":{"x":[".1",".0"],"y":[".1","0"]}}'
pvput -r "argument" scanServerPutGet argument='{"command":"start"}'