pvxs_sys/lib.rs
1// Copyright 2026 Tine Zata
2// SPDX-License-Identifier: MPL-2.0
3//! # EPICS PVXS Rust Bindings
4//!
5//! Safe Rust bindings for the EPICS PVXS (PVAccess) library.
6//!
7//! ## Overview
8//!
9//! This crate provides idiomatic Rust bindings to the EPICS PVXS C++ library,
10//! which implements the PVAccess network protocol used in EPICS (Experimental
11//! Physics and Industrial Control System).
12//!
13//! ## Features
14//!
15//! ### Client
16//! - **GET**: Read scalar and array PV values ([`Context::get`])
17//! - **PUT**: Write double, int32, string, and enum scalars or arrays
18//! ([`Context::put_double`], [`Context::put_int32`], [`Context::put_string`],
19//! [`Context::put_enum`], and their `_array` variants)
20//! - **Monitor**: Subscribe to real-time value changes via
21//! [`Context::monitor_builder`] → [`MonitorBuilder::connect_exception`] /
22//! [`MonitorBuilder::disconnect_exception`] / [`MonitorBuilder::event`] /
23//! [`MonitorBuilder::exec`] → [`Monitor::pop`]
24//!
25//! ### Server
26//! - **Start**: [`Server::start_from_env`] (network) or [`Server::start_isolated`] (local-only)
27//! - **PV creation**: `create_pv_double`, `create_pv_int32`, `create_pv_string`,
28//! `create_pv_enum`, and their `_array` variants
29//! - **POST**: Publish new values with automatic alarm computation —
30//! `post_double`, `post_int32`, `post_string`, `post_enum`, and `_array` variants
31//! - **Fetch**: Read the current server-side value with alarm info —
32//! `fetch_double`, `fetch_int32`, `fetch_string`, `fetch_enum`
33//! - **Stop**: [`Server::stop_drop`] — consumes the server and frees all resources
34//! - **Handle**: [`ServerHandle`] — clone-able, thread-safe handle for use across threads
35//!
36//! ### Metadata & Alarms
37//! - [`NTScalarMetadataBuilder`] / [`NTEnumMetadataBuilder`]: configure PV metadata at
38//! creation time (display limits, units, precision, control limits, value alarm thresholds)
39//! - [`ControlMetadata`], [`AlarmMetadata`]: structs passed to the builders
40//! - [`AlarmSeverity`], [`AlarmStatus`]: alarm state reported in fetched values and monitors
41//!
42//! ### Other
43//! - **Logging**: [`set_logger_level`] — programmatically set PVXS log levels
44//! - Thread-safe [`Context`] (implements `Send + Sync`)
45//!
46
47pub mod bridge;
48
49mod alarms;
50mod client;
51mod metadata;
52mod server;
53mod value;
54
55use std::fmt;
56
57pub use bridge::{
58 ContextWrapper, MonitorBuilderWrapper, MonitorWrapper, RpcWrapper, ServerWrapper,
59 SharedPVWrapper, StaticSourceWrapper, ValueWrapper,
60};
61
62/// Configure PVXS logging from environment variable `PVXS_LOG`
63///
64/// Reads the `PVXS_LOG` environment variable to configure logging levels.
65/// Format: "logger_name=LEVEL,another=LEVEL"
66///
67/// Examples:
68/// - `PVXS_LOG="*=DEBUG"` - all loggers at DEBUG level
69/// - `PVXS_LOG="pvxs.*=INFO"` - all internal loggers at INFO
70/// - `PVXS_LOG="pvxs.tcp.io=CRIT"` - suppress tcp.io errors below CRIT
71///
72/// Levels: CRIT < ERR < WARN < INFO < DEBUG
73///
74/// # Example
75///
76/// ```no_run
77/// use pvxs_sys::configure_logging_from_env;
78///
79/// // Read from PVXS_LOG environment variable
80/// configure_logging_from_env().ok();
81/// ```
82pub fn configure_logging_from_env() -> Result<()> {
83 bridge::pvxs_logger_config_env().map_err(|e| e.into())
84}
85
86/// Set logging level for a specific PVXS logger
87///
88/// Programmatically set the log level for a named logger.
89///
90/// # Arguments
91///
92/// * `name` - Logger name (e.g., "pvxs.tcp.io", "pvxs.*" for wildcards)
93/// * `level` - One of: "CRIT", "ERR", "WARN", "INFO", "DEBUG"
94///
95/// # Example
96///
97/// ```no_run
98/// use pvxs_sys::set_logger_level;
99///
100/// // Suppress benign TCP disconnect errors (socket error 10054)
101/// set_logger_level("pvxs.tcp.io", "CRIT").ok();
102/// ```
103pub fn set_logger_level(name: &str, level: &str) -> Result<()> {
104 bridge::pvxs_logger_level_set(name.to_string(), level.to_string()).map_err(|e| e.into())
105}
106
107pub use alarms::{compute_alarm_for_scalar, AlarmConfig, AlarmResult, AlarmSeverity, AlarmStatus};
108pub use client::{Context, Monitor, MonitorBuilder, MonitorEvent, Rpc};
109pub use metadata::{AlarmMetadata, ControlMetadata, DisplayMetadata};
110pub use server::{
111 FetchedDouble, FetchedDoubleArray, FetchedEnum, FetchedInt32, FetchedInt32Array, FetchedString,
112 FetchedStringArray, NTEnumMetadataBuilder, NTScalarMetadataBuilder, Server, ServerHandle,
113 SharedPV, StaticSource,
114};
115pub use value::Value;
116
117// Re-export for testing callbacks
118pub use std::sync::atomic::{AtomicUsize, Ordering};
119
120// Re-export for convenience
121pub type Result<T> = std::result::Result<T, PvxsError>;
122
123/// Error type for PVXS operations
124#[derive(Debug, Clone)]
125pub struct PvxsError {
126 message: String,
127}
128
129impl PvxsError {
130 pub fn new(message: impl Into<String>) -> Self {
131 Self {
132 message: message.into(),
133 }
134 }
135}
136
137impl fmt::Display for PvxsError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 write!(f, "PVXS error: {}", self.message)
140 }
141}
142
143impl std::error::Error for PvxsError {}
144
145impl From<cxx::Exception> for PvxsError {
146 fn from(e: cxx::Exception) -> Self {
147 Self::new(e.what())
148 }
149}