Examples¶
Example are built, but not installed. They can be found under example/O.*
Latest versions https://github.com/epics-base/pvxs/blob/master/example/
Shortest Client Get¶
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/** The short example of a client GET operation.
*/
#include <iostream>
#include <pvxs/client.h>
#include <pvxs/log.h>
int main(int argc, char* argv[]) {
using namespace pvxs;
// (Optional) configuring logging using $PVXS_LOG
logger_config_env();
// Configure client using $EPICS_PVA_*
auto ctxt(client::Context::fromEnv());
// fetch PV "some:pv:name" and wait up to 5 seconds for a reply.
// (throws an exception on error, including timeout)
Value reply = ctxt.get("some:pv:name").exec()->wait(5.0);
// Reply is printed to stdout.
std::cout<<reply;
return 0;
}
Shortest Server¶
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/** The short example of a server.
*/
#include <iostream>
#include <pvxs/server.h>
#include <pvxs/sharedpv.h>
#include <pvxs/nt.h>
#include <pvxs/log.h>
int main(int argc, char* argv[]) {
using namespace pvxs;
// (Optional) configuring logging using $PVXS_LOG
logger_config_env();
// Use pre-defined NTScalar structure w/ double for primary value field.
Value initial = nt::NTScalar{TypeCode::Float64}.create();
initial["value"] = 42.0;
// Storage and access for network visible Process Variable
server::SharedPV pv(server::SharedPV::buildMailbox());
pv.open(initial);
server::Server::fromEnv() // Configure a server using $EPICS_PVAS_* or $EPICS_PVA_*
.addPV("my:pv:name", pv) // add (and name) one local PV
.run(); // run until SIGINT
return 0;
}
Client Demo¶
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/** Meant to be run against the mailbox example.
* eg. in one terminal run:
*
* ./mailbox some:pv:name
*
* And in another terminal run:
*
* ./client some:pv:name
*/
#include <iostream>
#include <pvxs/client.h>
#include <pvxs/log.h>
using namespace pvxs;
int main(int argc, char* argv[])
{
if(argc<2) {
std::cerr<<"Usage: "<<argv[0]<<" <pvname>\n";
return 1;
}
// Read $PVXS_LOG from process environment and update
// logging configuration. eg.
// export PVXS_LOG=*=DEBUG
// makes a lot of noise.
logger_config_env();
// Create a client context
auto ctxt(client::Context::fromEnv());
// Fetch current value
int32_t current;
{
std::cout<<"Getting current value of '"<<argv[1]<<"'"<<std::endl;
// Build and start network operation
auto op = ctxt.get(argv[1])
.exec();
// wait for it to complete, for up to 5 seconds.
Value result = op->wait(5.0);
std::cout<<"Result is:\n"<<result<<std::endl;
if(auto value = result["value"]) {
// there is a .value field
// as may still throw pvxs::NoConvert if its value can't
// be converted to int32_t
current = value.as<int32_t>();
} else {
// an example. won't happen with mailbox server
std::cerr<<"Server type doesn't have .value field!\n";
return 1;
}
}
{
// attempt to change.
// uses simple builder form to assign .value
ctxt.put(argv[1])
.set("value", current+1)
.exec()
->wait(5.0);
std::cout<<"First increment successful"<<std::endl;
}
{
// change again.
// use build() callback
auto op = ctxt.put(argv[1])
// provide present value to build() callback.
.fetchPresent(true)
.build([](Value&& current) -> Value {
// allocate an empty container
auto toput(current.cloneEmpty());
// fill in .value.
// Assignment implicitly marks .value as changed
toput["value"] = current["value"].as<int32_t>() + 1;
// return the container to be sent
return toput;
})
.exec();
op->wait(5.0);
std::cout<<"Second increment successful"<<std::endl;
}
// fetch final value
{
std::cout<<"Getting current value of '"<<argv[1]<<"'"<<std::endl;
// Build and start network operation
auto result = ctxt.get(argv[1])
.exec()
->wait(5.0);
std::cout<<"Result is:\n"<<result<<std::endl;
}
return 0;
}
Mailbox Server¶
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvxs is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
/**
* Serves a single PV name.
* Any updates written (PUT) to this PV will be stored verbatim
* and sent to any subscribers.
*/
#include <iostream>
#include <epicsTime.h>
#include <pvxs/sharedpv.h>
#include <pvxs/server.h>
#include <pvxs/nt.h>
#include <pvxs/log.h>
using namespace pvxs;
int main(int argc, char* argv[])
{
if(argc<=1) {
std::cerr<<"Usage: "<<argv[0]<<" <pvname> [pvname1 [...]]\n";
return 1;
}
// Read $PVXS_LOG from process environment and update
// logging configuration. eg.
// export PVXS_LOG=*=DEBUG
// makes a lot of noise.
logger_config_env();
// Must provide a data type for the mailbox.
// Use pre-canned definition of scalar with meta-data
Value initial = nt::NTScalar{TypeCode::Float64}.create();
// (optional) Provide an initial value
initial["value"] = 42.0;
initial["alarm.severity"] = 0;
initial["alarm.status"] = 0;
initial["alarm.message"] = "";
std::vector<server::SharedPV> pvs(argc-1u);
for(size_t i=0ul; i<pvs.size(); i++) {
// Actually creating a mailbox PV.
// buildMailbox() installs a default onPut() handler which
// stores whatever a client sends (subject to our data type).
server::SharedPV pv(server::SharedPV::buildMailbox());
// (optional) Replace the default PUT handler to do a range check
pv.onPut([](server::SharedPV& pv,
std::unique_ptr<server::ExecOp>&& op,
Value&& top)
{
// (optional) arbitrarily clip value to [-100.0, 100.0]
double val(top["value"].as<double>());
if(val<-100.0)
top["value"] = -100.0;
else if(val>100.0)
top["value"] = 100.0;
// (optional) Provide a timestamp if the client has not (common)
Value ts(top["timeStamp"]);
if(!ts.isMarked(true, true)) {
// use current time
epicsTimeStamp now;
if(!epicsTimeGetCurrent(&now)) {
ts["secondsPastEpoch"] = now.secPastEpoch + POSIX_TIME_AT_EPICS_EPOCH;
ts["nanoseconds"] = now.nsec;
}
}
// (optional) update the SharedPV cache and send
// a update to any subscribers
pv.post(top);
// Required. Inform client that PUT operation is complete.
op->reply();
});
// Associate a data type (and maybe initial value) with this PV
pv.open(initial);
pvs[i] = std::move(pv);
}
// Build server which will serve this PV
// Configure using process environment.
auto serv(server::Server::fromEnv());
for(size_t i=0ul; i<pvs.size(); i++) {
serv.addPV(argv[i+1], pvs[i]);
}
// (optional) Print the configuration this server is using
// with any auto-address list expanded.
std::cout<<"Effective config\n"<<serv.config();
std::cout<<"Running\n";
// Start server and run forever, or until Ctrl+c is pressed.
// Returns on SIGINT or SIGTERM
serv.run();
std::cout<<"Done\n";
return 0;
}