Skip to content

Commit cde9286

Browse files
committed
feat(client): add pvget_fields for field-filtered GET requests
Support the equivalent of `pvget -r "field(value,alarm)"` by encoding a pvRequest with the requested field names. When fields is empty, sends the default all-fields request. Adds PvaClient::pvget_fields() and the lower-level pvget_fields() function.
1 parent 506fa6a commit cde9286

3 files changed

Lines changed: 31 additions & 3 deletions

File tree

spvirit-client/src/client.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::auth::{resolved_authnz_host, resolved_authnz_user};
66
use crate::search::resolve_pv_server;
77
use crate::transport::{read_packet, read_until};
88
use crate::types::{PvGetError, PvGetOptions, PvGetResult};
9+
use spvirit_codec::spvd_encode::encode_pv_request;
910
use spvirit_codec::epics_decode::{
1011
PvaPacket, PvaPacketCommand, decode_op_response_status as codec_decode_op_response_status,
1112
};
@@ -134,7 +135,19 @@ pub async fn establish_channel(
134135
})
135136
}
136137

138+
/// Convenience wrapper: GET with no field filtering.
137139
pub async fn pvget(opts: &PvGetOptions) -> Result<PvGetResult, PvGetError> {
140+
pvget_fields(opts, &[]).await
141+
}
142+
143+
/// GET with optional field filtering.
144+
///
145+
/// If `fields` is empty, requests all fields (equivalent to `-r ""`).
146+
/// Otherwise, encodes a pvRequest like `field(value,alarm,timeStamp)`.
147+
pub async fn pvget_fields(
148+
opts: &PvGetOptions,
149+
fields: &[&str],
150+
) -> Result<PvGetResult, PvGetError> {
138151
let target = resolve_pv_server(opts).await?;
139152

140153
let conn = establish_channel(target, opts).await?;
@@ -147,12 +160,17 @@ pub async fn pvget(opts: &PvGetOptions) -> Result<PvGetResult, PvGetError> {
147160
} = conn;
148161

149162
let ioid = 1u32;
150-
// Match EPICS pvget GET init payload (extra pvRequest bytes observed in capture).
163+
let pv_request = if fields.is_empty() {
164+
// Empty pvRequest — request all fields
165+
vec![0xfd, 0x02, 0x00, 0x80, 0x00, 0x00]
166+
} else {
167+
encode_pv_request(fields, is_be)
168+
};
151169
let get_init_req = encode_get_request(
152170
sid,
153171
ioid,
154172
0x08,
155-
&[0xfd, 0x02, 0x00, 0x80, 0x00, 0x00],
173+
&pv_request,
156174
version,
157175
is_be,
158176
);

spvirit-client/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub use pva_client::{
5252
pub use pvlist::PvListSource;
5353

5454
// --- Re-exports: client core ---
55-
pub use client::{ChannelConn, build_client_validation, establish_channel, pvget};
55+
pub use client::{ChannelConn, build_client_validation, establish_channel, pvget, pvget_fields};
5656
pub use format::{OutputFormat, RenderOptions, format_output};
5757
pub use search::{SearchTarget, build_auto_broadcast_targets, resolve_pv_server, search_pv};
5858
pub use transport::read_packet;

spvirit-client/src/pva_client.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,16 @@ impl PvaClient {
233233
low_level_pvget(&opts).await
234234
}
235235

236+
/// Fetch a PV with field filtering (equivalent to `pvget -r "field(value,alarm)"`).
237+
pub async fn pvget_fields(
238+
&self,
239+
pv_name: &str,
240+
fields: &[&str],
241+
) -> Result<PvGetResult, PvGetError> {
242+
let opts = self.opts(pv_name);
243+
crate::client::pvget_fields(&opts, fields).await
244+
}
245+
236246
// ─── pvput ───────────────────────────────────────────────────────────
237247

238248
/// Write a value to a PV.

0 commit comments

Comments
 (0)