#include "wrapper.h"
namespace pvxs_wrapper
{
void SharedPVWrapper::open(const ValueWrapper &initial_value)
{
try
{
template_value_ = initial_value.get();
pv_.open(initial_value.get());
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV: ") + e.what());
}
}
bool SharedPVWrapper::is_open() const
{
return pv_.isOpen();
}
void SharedPVWrapper::close()
{
try
{
pv_.close();
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error closing SharedPV: ") + e.what());
}
}
void SharedPVWrapper::post_value(const ValueWrapper &value)
{
try
{
pv_.post(value.get());
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting value to SharedPV: ") + e.what());
}
}
std::unique_ptr<ValueWrapper> SharedPVWrapper::fetch_value() const
{
try
{
auto value = pv_.fetch();
return std::make_unique<ValueWrapper>(std::move(value));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error fetching value from SharedPV: ") + e.what());
}
}
std::unique_ptr<SharedPVWrapper> SharedPVWrapper::create_mailbox()
{
try
{
auto pv = pvxs::server::SharedPV::buildMailbox();
return std::make_unique<SharedPVWrapper>(std::move(pv));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error creating mailbox SharedPV: ") + e.what());
}
}
std::unique_ptr<SharedPVWrapper> SharedPVWrapper::create_readonly()
{
try
{
auto pv = pvxs::server::SharedPV::buildReadonly();
return std::make_unique<SharedPVWrapper>(std::move(pv));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error creating readonly SharedPV: ") + e.what());
}
}
void StaticSourceWrapper::add_pv(const std::string &name, SharedPVWrapper &pv)
{
try
{
source_.add(name, pv.get());
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error adding PV '") + name + "' to StaticSource: " + e.what());
}
}
void StaticSourceWrapper::remove_pv(const std::string &name)
{
try
{
source_.remove(name);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error removing PV '") + name + "' from StaticSource: " + e.what());
}
}
void StaticSourceWrapper::close_all()
{
try
{
source_.close();
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error closing all PVs in StaticSource: ") + e.what());
}
}
std::unique_ptr<StaticSourceWrapper> StaticSourceWrapper::create()
{
try
{
auto source = pvxs::server::StaticSource::build();
return std::make_unique<StaticSourceWrapper>(std::move(source));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error creating StaticSource: ") + e.what());
}
}
void ServerWrapper::start()
{
try
{
server_.start();
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error starting server: ") + e.what());
}
}
void ServerWrapper::stop()
{
try
{
server_.stop();
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error stopping server: ") + e.what());
}
}
void ServerWrapper::add_pv(const std::string &name, SharedPVWrapper &pv)
{
try
{
server_.addPV(name, pv.get());
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error adding PV '") + name + "' to server: " + e.what());
}
}
void ServerWrapper::remove_pv(const std::string &name)
{
try
{
server_.removePV(name);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error removing PV '") + name + "' from server: " + e.what());
}
}
void ServerWrapper::add_source(const std::string &name, StaticSourceWrapper &source, int order)
{
try
{
server_.addSource(name, source.get().source(), order);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error adding source '") + name + "' to server: " + e.what());
}
}
uint16_t ServerWrapper::get_tcp_port() const
{
try
{
return server_.config().tcp_port;
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error getting TCP port: ") + e.what());
}
}
uint16_t ServerWrapper::get_udp_port() const
{
try
{
return server_.config().udp_port;
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error getting UDP port: ") + e.what());
}
}
std::unique_ptr<ServerWrapper> ServerWrapper::from_env()
{
try
{
auto server = pvxs::server::Server::fromEnv();
return std::make_unique<ServerWrapper>(std::move(server));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error creating server from environment: ") + e.what());
}
}
std::unique_ptr<ServerWrapper> ServerWrapper::isolated()
{
try
{
auto config = pvxs::server::Config::isolated();
auto server = config.build();
return std::make_unique<ServerWrapper>(std::move(server));
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error creating isolated server: ") + e.what());
}
}
std::unique_ptr<ServerWrapper> server_create_from_env()
{
return ServerWrapper::from_env();
}
std::unique_ptr<ServerWrapper> server_create_isolated()
{
return ServerWrapper::isolated();
}
void server_start(ServerWrapper &server)
{
server.start();
}
void server_stop(ServerWrapper &server)
{
server.stop();
}
void server_add_pv(ServerWrapper &server, rust::String name, SharedPVWrapper &pv)
{
server.add_pv(std::string(name), pv);
}
void server_remove_pv(ServerWrapper &server, rust::String name)
{
server.remove_pv(std::string(name));
}
void server_add_source(ServerWrapper &server, rust::String name, StaticSourceWrapper &source, int32_t order)
{
server.add_source(std::string(name), source, order);
}
uint16_t server_get_tcp_port(const ServerWrapper &server)
{
return server.get_tcp_port();
}
uint16_t server_get_udp_port(const ServerWrapper &server)
{
return server.get_udp_port();
}
std::unique_ptr<SharedPVWrapper> shared_pv_create_mailbox()
{
return SharedPVWrapper::create_mailbox();
}
std::unique_ptr<SharedPVWrapper> shared_pv_create_readonly()
{
return SharedPVWrapper::create_readonly();
}
std::unique_ptr<NTScalarAlarm> create_alarm(int32_t severity, int32_t status, rust::String message)
{
auto alarm = std::make_unique<NTScalarAlarm>();
alarm->severity = severity;
alarm->status = status;
alarm->message = std::move(message);
return alarm;
}
std::unique_ptr<NTScalarTime> create_time(int64_t seconds_past_epoch, int32_t nanoseconds, int32_t user_tag)
{
auto time = std::make_unique<NTScalarTime>();
time->seconds_past_epoch = seconds_past_epoch;
time->nanoseconds = nanoseconds;
time->user_tag = user_tag;
return time;
}
std::unique_ptr<NTScalarDisplay> create_display(int64_t limit_low, int64_t limit_high,
rust::String description, rust::String units, int32_t precision)
{
auto display = std::make_unique<NTScalarDisplay>();
display->limit_low = limit_low;
display->limit_high = limit_high;
display->description = std::move(description);
display->units = std::move(units);
display->precision = precision;
return display;
}
std::unique_ptr<NTScalarControl> create_control(double limit_low, double limit_high, double min_step)
{
auto control = std::make_unique<NTScalarControl>();
control->limit_low = limit_low;
control->limit_high = limit_high;
control->min_step = min_step;
return control;
}
std::unique_ptr<NTScalarValueAlarm> create_value_alarm(bool active, double low_alarm_limit, double low_warning_limit,
double high_warning_limit, double high_alarm_limit,
int32_t low_alarm_severity, int32_t low_warning_severity,
int32_t high_warning_severity, int32_t high_alarm_severity,
uint8_t hysteresis)
{
auto value_alarm = std::make_unique<NTScalarValueAlarm>();
value_alarm->active = active;
value_alarm->low_alarm_limit = low_alarm_limit;
value_alarm->low_warning_limit = low_warning_limit;
value_alarm->high_warning_limit = high_warning_limit;
value_alarm->high_alarm_limit = high_alarm_limit;
value_alarm->low_alarm_severity = low_alarm_severity;
value_alarm->low_warning_severity = low_warning_severity;
value_alarm->high_warning_severity = high_warning_severity;
value_alarm->high_alarm_severity = high_alarm_severity;
value_alarm->hysteresis = hysteresis;
return value_alarm;
}
std::unique_ptr<NTScalarMetadata> create_metadata(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarDisplay *display, const NTScalarControl *control,
const NTScalarValueAlarm *value_alarm)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
if (display)
{
metadata->display = *display;
}
if (control)
{
metadata->control = *control;
}
if (value_alarm)
{
metadata->value_alarm = *value_alarm;
}
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_no_optional(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_display(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarDisplay &display)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->display = display;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_control(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarControl &control)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->control = control;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_value_alarm(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarValueAlarm &value_alarm)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->value_alarm = value_alarm;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_display_control(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarDisplay &display, const NTScalarControl &control)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->display = display;
metadata->control = control;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_display_value_alarm(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarDisplay &display, const NTScalarValueAlarm &value_alarm)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->display = display;
metadata->value_alarm = value_alarm;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_with_control_value_alarm(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarControl &control, const NTScalarValueAlarm &value_alarm)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->control = control;
metadata->value_alarm = value_alarm;
return metadata;
}
std::unique_ptr<NTScalarMetadata> create_metadata_full(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp,
const NTScalarDisplay &display, const NTScalarControl &control,
const NTScalarValueAlarm &value_alarm)
{
auto metadata = std::make_unique<NTScalarMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
metadata->display = display;
metadata->control = control;
metadata->value_alarm = value_alarm;
return metadata;
}
std::unique_ptr<NTEnumMetadata> create_enum_metadata(const NTScalarAlarm &alarm, const NTScalarTime &time_stamp)
{
auto metadata = std::make_unique<NTEnumMetadata>();
metadata->alarm = alarm;
metadata->time_stamp = time_stamp;
return metadata;
}
void shared_pv_open_double(SharedPVWrapper &pv, double initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::Float64,
metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value(),
metadata.display.has_value()} .create();
initial["value"] = initial_value;
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.limitLow"] = disp.limit_low;
initial["display.limitHigh"] = disp.limit_high;
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
initial["display.precision"] = disp.precision;
}
if (metadata.control.has_value())
{
const auto &ctrl = metadata.control.value();
initial["control.limitLow"] = ctrl.limit_low;
initial["control.limitHigh"] = ctrl.limit_high;
initial["control.minStep"] = ctrl.min_step;
}
if (metadata.value_alarm.has_value())
{
const auto &valarm = metadata.value_alarm.value();
initial["valueAlarm.active"] = valarm.active;
initial["valueAlarm.lowAlarmLimit"] = valarm.low_alarm_limit;
initial["valueAlarm.lowWarningLimit"] = valarm.low_warning_limit;
initial["valueAlarm.highWarningLimit"] = valarm.high_warning_limit;
initial["valueAlarm.highAlarmLimit"] = valarm.high_alarm_limit;
initial["valueAlarm.lowAlarmSeverity"] = valarm.low_alarm_severity;
initial["valueAlarm.lowWarningSeverity"] = valarm.low_warning_severity;
initial["valueAlarm.highWarningSeverity"] = valarm.high_warning_severity;
initial["valueAlarm.highAlarmSeverity"] = valarm.high_alarm_severity;
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with NTScalar metadata: ") + e.what());
}
}
void shared_pv_open_double_array(SharedPVWrapper &pv, rust::Vec<double> initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::Float64A, metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value(),
metadata.display.has_value()} .create();
pvxs::shared_array<double> arr(initial_value.size());
for (size_t i = 0; i < initial_value.size(); ++i)
{
arr[i] = initial_value[i];
}
initial["value"] = arr.freeze();
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.limitLow"] = disp.limit_low;
initial["display.limitHigh"] = disp.limit_high;
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
initial["display.precision"] = disp.precision;
}
if (metadata.control.has_value())
{
const auto &ctrl = metadata.control.value();
initial["control.limitLow"] = ctrl.limit_low;
initial["control.limitHigh"] = ctrl.limit_high;
initial["control.minStep"] = ctrl.min_step;
}
if (metadata.value_alarm.has_value())
{
const auto &valarm = metadata.value_alarm.value();
initial["valueAlarm.active"] = valarm.active;
initial["valueAlarm.lowAlarmLimit"] = valarm.low_alarm_limit;
initial["valueAlarm.lowWarningLimit"] = valarm.low_warning_limit;
initial["valueAlarm.highWarningLimit"] = valarm.high_warning_limit;
initial["valueAlarm.highAlarmLimit"] = valarm.high_alarm_limit;
initial["valueAlarm.lowAlarmSeverity"] = valarm.low_alarm_severity;
;
initial["valueAlarm.lowWarningSeverity"] = valarm.low_warning_severity;
initial["valueAlarm.highWarningSeverity"] = valarm.high_warning_severity;
initial["valueAlarm.highAlarmSeverity"] = valarm.high_alarm_severity;
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with double array metadata: ") + e.what());
}
}
void shared_pv_open_int32(SharedPVWrapper &pv, int32_t initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::Int32,
metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value(),
metadata.display.has_value()} .create();
initial["value"] = initial_value;
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.limitLow"] = disp.limit_low;
initial["display.limitHigh"] = disp.limit_high;
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
initial["display.precision"] = disp.precision;
}
if (metadata.control.has_value())
{
const auto &ctrl = metadata.control.value();
initial["control.limitLow"] = ctrl.limit_low;
initial["control.limitHigh"] = ctrl.limit_high;
initial["control.minStep"] = ctrl.min_step;
}
if (metadata.value_alarm.has_value())
{
const auto &valarm = metadata.value_alarm.value();
initial["valueAlarm.active"] = valarm.active;
initial["valueAlarm.lowAlarmLimit"] = valarm.low_alarm_limit;
initial["valueAlarm.lowWarningLimit"] = valarm.low_warning_limit;
initial["valueAlarm.highWarningLimit"] = valarm.high_warning_limit;
initial["valueAlarm.highAlarmLimit"] = valarm.high_alarm_limit;
initial["valueAlarm.lowAlarmSeverity"] = valarm.low_alarm_severity;
initial["valueAlarm.lowWarningSeverity"] = valarm.low_warning_severity;
initial["valueAlarm.highWarningSeverity"] = valarm.high_warning_severity;
initial["valueAlarm.highAlarmSeverity"] = valarm.high_alarm_severity;
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with int32 value: ") + e.what());
}
}
void shared_pv_open_int32_array(SharedPVWrapper &pv, rust::Vec<int32_t> initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::Int32A, metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value(),
metadata.display.has_value()} .create();
pvxs::shared_array<int32_t> arr(initial_value.size());
for (size_t i = 0; i < initial_value.size(); ++i)
{
arr[i] = initial_value[i];
}
initial["value"] = arr.freeze();
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.limitLow"] = disp.limit_low;
initial["display.limitHigh"] = disp.limit_high;
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
initial["display.precision"] = disp.precision;
}
if (metadata.control.has_value())
{
const auto &ctrl = metadata.control.value();
initial["control.limitLow"] = ctrl.limit_low;
initial["control.limitHigh"] = ctrl.limit_high;
initial["control.minStep"] = ctrl.min_step;
}
if (metadata.value_alarm.has_value())
{
const auto &valarm = metadata.value_alarm.value();
initial["valueAlarm.active"] = valarm.active;
initial["valueAlarm.lowAlarmLimit"] = valarm.low_alarm_limit;
initial["valueAlarm.lowWarningLimit"] = valarm.low_warning_limit;
initial["valueAlarm.highWarningLimit"] = valarm.high_warning_limit;
initial["valueAlarm.highAlarmLimit"] = valarm.high_alarm_limit;
initial["valueAlarm.lowAlarmSeverity"] = valarm.low_alarm_severity;
;
initial["valueAlarm.lowWarningSeverity"] = valarm.low_warning_severity;
initial["valueAlarm.highWarningSeverity"] = valarm.high_warning_severity;
initial["valueAlarm.highAlarmSeverity"] = valarm.high_alarm_severity;
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with int32 array metadata: ") + e.what());
}
}
void shared_pv_open_string(SharedPVWrapper &pv, rust::String initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::String,
metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value()}
.create();
initial["value"] = std::string(initial_value);
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with string value and metadata: ") + e.what());
}
}
void shared_pv_open_string_array(SharedPVWrapper &pv, rust::Vec<rust::String> initial_value, const NTScalarMetadata &metadata)
{
try
{
auto initial = pvxs::nt::NTScalar{
pvxs::TypeCode::StringA, metadata.display.has_value(),
metadata.control.has_value(),
metadata.value_alarm.has_value()}
.create();
pvxs::shared_array<std::string> arr(initial_value.size());
for (size_t i = 0; i < initial_value.size(); ++i)
{
arr[i] = std::string(initial_value[i]);
}
initial["value"] = arr.freeze();
initial["alarm.severity"] = metadata.alarm.severity;
initial["alarm.status"] = metadata.alarm.status;
initial["alarm.message"] = std::string(metadata.alarm.message);
initial["timeStamp.secondsPastEpoch"] = metadata.time_stamp.seconds_past_epoch;
initial["timeStamp.nanoseconds"] = metadata.time_stamp.nanoseconds;
initial["timeStamp.userTag"] = metadata.time_stamp.user_tag;
if (metadata.display.has_value())
{
const auto &disp = metadata.display.value();
initial["display.description"] = std::string(disp.description);
initial["display.units"] = std::string(disp.units);
}
ValueWrapper wrapper(std::move(initial));
pv.open(wrapper);
auto onPut = [](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error applying PUT: ") + e.what());
}
};
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with string array metadata: ") + e.what());
}
}
void shared_pv_open_enum(SharedPVWrapper &pv, rust::Vec<rust::String> enum_choices, int16_t selected_choice, const NTEnumMetadata &metadata)
{
try
{
auto enums = pvxs::nt::NTEnum{}.create();
enums["value.index"] = selected_choice;
pvxs::shared_array<const std::string> choices_array;
{
std::vector<std::string> temp_vec;
temp_vec.reserve(enum_choices.size());
for (const auto &choice : enum_choices)
{
temp_vec.emplace_back(std::string(choice));
}
choices_array = pvxs::shared_array<const std::string>(temp_vec.begin(), temp_vec.end());
}
enums["value.choices"].from(choices_array);
auto onPut = [choices_array](pvxs::server::SharedPV &spv, std::unique_ptr<pvxs::server::ExecOp> &&op, pvxs::Value &&value)
{
try
{
auto new_index = value["value.index"].as<int16_t>();
if (new_index < 0)
{
op->error("Enum index cannot be negative");
return;
}
if (static_cast<size_t>(new_index) >= choices_array.size())
{
op->error("Enum index " + std::to_string(new_index) + " is out of range (max: " + std::to_string(choices_array.size() - 1) + ")");
return;
}
spv.post(std::move(value));
op->reply();
}
catch (const std::exception &e)
{
op->error(std::string("Error validating enum PUT: ") + e.what());
}
};
ValueWrapper wrapper(std::move(enums));
pv.open(wrapper);
pv.get().onPut(onPut);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error opening SharedPV with enum value: ") + e.what());
}
}
bool shared_pv_is_open(const SharedPVWrapper &pv)
{
return pv.is_open();
}
void shared_pv_close(SharedPVWrapper &pv)
{
pv.close();
}
void shared_pv_post_double(SharedPVWrapper &pv, double value)
{
try
{
auto update = pv.get_template().cloneEmpty();
update["value"] = value;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting double value to SharedPV: ") + e.what());
}
}
void shared_pv_post_double_with_alarm(SharedPVWrapper &pv, double value, int32_t severity, int32_t status, rust::String message)
{
try
{
auto update = pv.get_template().cloneEmpty();
update["value"] = value;
update["alarm.severity"] = severity;
update["alarm.status"] = status;
update["alarm.message"] = std::string(message);
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting double value with alarm to SharedPV: ") + e.what());
}
}
void shared_pv_post_int32(SharedPVWrapper &pv, int32_t value)
{
try
{
auto update = pv.get_template().cloneEmpty();
update["value"] = value;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting int32 value to SharedPV: ") + e.what());
}
}
void shared_pv_post_int32_with_alarm(SharedPVWrapper &pv, int32_t value, int32_t severity, int32_t status, rust::String message)
{
try
{
auto update = pv.get_template().cloneEmpty();
update["value"] = value;
update["alarm.severity"] = severity;
update["alarm.status"] = status;
update["alarm.message"] = std::string(message);
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting int32 value with alarm to SharedPV: ") + e.what());
}
}
void shared_pv_post_string(SharedPVWrapper &pv, rust::String value)
{
try
{
auto update = pv.get_template().cloneEmpty();
update["value"] = std::string(value);
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting string value to SharedPV: ") + e.what());
}
}
void shared_pv_post_enum(SharedPVWrapper &pv, int16_t value)
{
try
{
auto current = pv.get_template();
if (value < 0)
{
throw PvxsError("Enum index cannot be negative");
}
auto choices = current["value.choices"].as<pvxs::shared_array<const std::string>>();
if (static_cast<size_t>(value) >= choices.size())
{
throw PvxsError("Enum index " + std::to_string(value) + " is out of range (max: " + std::to_string(choices.size() - 1) + ")");
}
auto update = current.cloneEmpty();
update["value.index"] = value;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting enum value to SharedPV: ") + e.what());
}
}
void shared_pv_post_enum_with_alarm(SharedPVWrapper &pv, int16_t value, int32_t severity, int32_t status, rust::String message)
{
try
{
auto current = pv.get_template();
if (value < 0)
{
throw PvxsError("Enum index cannot be negative");
}
auto choices = current["value.choices"].as<pvxs::shared_array<const std::string>>();
if (static_cast<size_t>(value) >= choices.size())
{
throw PvxsError("Enum index " + std::to_string(value) + " is out of range (max: " + std::to_string(choices.size() - 1) + ")");
}
auto update = current.cloneEmpty();
update["value.index"] = value;
update["alarm.severity"] = severity;
update["alarm.status"] = status;
update["alarm.message"] = std::string(message);
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting enum value with alarm to SharedPV: ") + e.what());
}
}
void shared_pv_post_double_array(SharedPVWrapper &pv, rust::Vec<double> value)
{
try
{
auto update = pv.get_template().cloneEmpty();
pvxs::shared_array<const double> arr(value.begin(), value.end());
update["value"] = arr;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting double array to SharedPV: ") + e.what());
}
}
void shared_pv_post_int32_array(SharedPVWrapper &pv, rust::Vec<int32_t> value)
{
try
{
auto update = pv.get_template().cloneEmpty();
pvxs::shared_array<const int32_t> arr(value.begin(), value.end());
update["value"] = arr;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting int32 array to SharedPV: ") + e.what());
}
}
void shared_pv_post_string_array(SharedPVWrapper &pv, rust::Vec<rust::String> value)
{
try
{
auto update = pv.get_template().cloneEmpty();
std::vector<std::string> cpp_vec;
cpp_vec.reserve(value.size());
for (const auto &s : value)
{
cpp_vec.emplace_back(std::string(s));
}
pvxs::shared_array<const std::string> arr(cpp_vec.begin(), cpp_vec.end());
update["value"] = arr;
ValueWrapper wrapper(std::move(update));
pv.post_value(wrapper);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error posting string array to SharedPV: ") + e.what());
}
}
std::unique_ptr<ValueWrapper> shared_pv_fetch(const SharedPVWrapper &pv)
{
return pv.fetch_value();
}
std::unique_ptr<StaticSourceWrapper> static_source_create()
{
return StaticSourceWrapper::create();
}
void static_source_add_pv(StaticSourceWrapper &source, rust::String name, SharedPVWrapper &pv)
{
source.add_pv(std::string(name), pv);
}
void static_source_remove_pv(StaticSourceWrapper &source, rust::String name)
{
source.remove_pv(std::string(name));
}
void static_source_close_all(StaticSourceWrapper &source)
{
source.close_all();
}
void pvxs_logger_config_env()
{
try
{
pvxs::logger_config_env();
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error configuring logger from env: ") + e.what());
}
}
void pvxs_logger_level_set(rust::String name, rust::String level)
{
try
{
std::string name_str(name);
std::string level_str(level);
pvxs::Level lvl;
if (level_str == "CRIT" || level_str == "Crit")
{
lvl = pvxs::Level::Crit;
}
else if (level_str == "ERR" || level_str == "Err")
{
lvl = pvxs::Level::Err;
}
else if (level_str == "WARN" || level_str == "Warn")
{
lvl = pvxs::Level::Warn;
}
else if (level_str == "INFO" || level_str == "Info")
{
lvl = pvxs::Level::Info;
}
else if (level_str == "DEBUG" || level_str == "Debug")
{
lvl = pvxs::Level::Debug;
}
else
{
throw PvxsError("Invalid log level: " + level_str + ". Must be one of: CRIT, ERR, WARN, INFO, DEBUG");
}
pvxs::logger_level_set(name_str.c_str(), lvl);
}
catch (const std::exception &e)
{
throw PvxsError(std::string("Error setting logger level: ") + e.what());
}
}
}