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 userTagThe 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 valueNote 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"}'