382 lines
12 KiB
Plaintext
382 lines
12 KiB
Plaintext
/**
|
|
@page qsrv_page QSRV
|
|
|
|
@section qsrv_config QSRV Configuration
|
|
|
|
By default QSRV exposes all Process Variables (fields of process database records).
|
|
In addition to these "single" PVs are special "group" PVs.
|
|
|
|
@subsection qsrv_single Single PVs
|
|
|
|
"single" PVs are the same set of names server by the Channel Access server (RSRV).
|
|
This is all accessible record fields.
|
|
So all data which is accessible via Channel Access is also accessible via PVAccess.
|
|
|
|
QSRV presents all "single" PVs as Structures conforming to the
|
|
Normative Types NTScalar, NTScalarArray, or NTEnum depending on the native DBF field type.
|
|
|
|
@subsection qsrv_group_def Group PV definitions
|
|
|
|
A group is defined using a JSON syntax.
|
|
Groups are defined with respect to a Group Name,
|
|
which is also the PV name.
|
|
So unlike records, the "field" of a group have a different meaning.
|
|
Group field names are _not_ part of the PV name.
|
|
|
|
A group definition may be split among several records,
|
|
or included in separate JSON file(s).
|
|
|
|
For example of a group including two records is:
|
|
|
|
@code
|
|
record(ai, "rec:X") {
|
|
info(Q:group, {
|
|
"grp:name": {
|
|
"X": {+channel:"VAL"}
|
|
}
|
|
})
|
|
}
|
|
record(ai, "rec:Y") {
|
|
info(Q:group, {
|
|
"grp:name": {
|
|
"Y": {+channel:"VAL"}
|
|
}
|
|
})
|
|
}
|
|
@endcode
|
|
|
|
Or equivalently with separate .db file and .json files.
|
|
|
|
@code
|
|
# some .db
|
|
record(ai, "rec:X") {}
|
|
record(ai, "rec:Y") {}
|
|
@endcode
|
|
|
|
@code
|
|
{
|
|
"grp:name": {
|
|
"X": {+channel:"VAL"},
|
|
"Y": {+channel:"VAL"}
|
|
}
|
|
}
|
|
@endcode
|
|
|
|
This group, named "grp:name", has two fields "X" and "Y".
|
|
|
|
@code
|
|
$ pvget grp:name
|
|
grp:name
|
|
structure
|
|
epics:nt/NTScalar:1.0 X
|
|
double value 0
|
|
alarm_t alarm INVALID DRIVER UDF
|
|
time_t timeStamp <undefined> 0
|
|
...
|
|
epics:nt/NTScalar:1.0 Y
|
|
double value 0
|
|
alarm_t alarm INVALID DRIVER UDF
|
|
time_t timeStamp <undefined> 0
|
|
...
|
|
@endcode
|
|
|
|
@subsection qsrv_group_ref Group PV reference
|
|
|
|
@code
|
|
record(...) {
|
|
info(Q:group, {
|
|
"<group_name>":{
|
|
+id:"some/NT:1.0", # top level ID
|
|
+atomic:true, # whether monitors default to multi-locking atomicity
|
|
"<field.name>":{
|
|
+type:"scalar", # controls how map VAL mapped onto <field.name>
|
|
+channel:"VAL",
|
|
+id:"some/NT:1.0",
|
|
+trigger:"*", # "*" or comma seperated list of <field.name>s
|
|
+putorder:0, # set for fields where put is allowed, processing done in increasing order
|
|
},
|
|
"": {+type:"meta", +channel:"VAL"} # special case adds meta-data fields at top level
|
|
}
|
|
})
|
|
}
|
|
@endcode
|
|
|
|
@subsubsection qsrv_group_map_types Field mapping types
|
|
|
|
@li "scalar" or ""
|
|
@li "plain"
|
|
@li "any"
|
|
@li "meta"
|
|
@li "proc"
|
|
@li "structure"
|
|
|
|
The "scalar" mapping places an NTScalar or NTScalarArray as a sub-structure.
|
|
|
|
The "plain" mapping ignores all meta-data and places only the "value" as a field.
|
|
The "value" is equivalent to '.value' of the equivalent NTScalar/NTScalarArray as a field.
|
|
|
|
The "any" mapping places a variant union into which the "value" is placed.
|
|
|
|
The "meta" mapping ignores the "value" and places only the alarm and time
|
|
meta-data as sub-fields.
|
|
Placing an entry in a blank field name '"": {+type:"meta"}' allows these meta-data fields to be
|
|
placed in the top-level structure.
|
|
|
|
The "proc" mapping uses neither "value" nor meta-data.
|
|
Instead the target record is processed during a put.
|
|
|
|
The "structure" mapping allows an "+id" to be attached without a "+channel".
|
|
So none of "+channel", "+trigger", nor "+putorder" are meaningful for a "structure" mapping.
|
|
|
|
@subsubsection qsrv_group_map_trig Field Update Triggers
|
|
|
|
The field triggers define how changes to the consitutent field
|
|
are translated into a subscription update to the group.
|
|
|
|
The most use of these are "" which means that changes to the field
|
|
are ignored, and do not result group update.
|
|
And "*" which results in a group update containing the most recent
|
|
values/meta-data of all fields.
|
|
|
|
It may be useful to specify a comma seperated list of field names
|
|
so that changes may partially update the group.
|
|
|
|
@subsection qsrv_stamp QSRV Timestamp Options
|
|
|
|
QSRV has the ability to perform certain transformations on the timestamp before transporting it.
|
|
The mechanism for configuring this is the "Q:time:tag" info() tag.
|
|
|
|
@subsubsection qsrv_stamp_nslsb Nano-seconds least significant bits
|
|
|
|
Setting "Q:time:tag" to a value of "nsec:lsb:#", where # is a number between 0 and 32,
|
|
will split the nanoseconds value stored in the associated record.
|
|
The least significant # bits are stored in the 'timeStamp.userTag' field.
|
|
While the remaining 32-# bits are stored in 'timeStamp.nanoseconds' (without shifting).
|
|
|
|
For example, in the following situation 20 bits are split off into userTag.
|
|
If the nanoseconds part of the record timestamp is 0x12345678,
|
|
then the PVD structure would include "timeStamp.nanoseconds=0x12300000"
|
|
and "timeStamp.userTag=0x45678".
|
|
|
|
@code
|
|
record(ai, "...") {
|
|
info(Q:time:tag, "nsec:lsb:20")
|
|
}
|
|
@endcode
|
|
|
|
@subsection qsrv_form QSRV Display Form Option
|
|
|
|
The value of the OPI display form hint ('display.form') can be set set with the "Q:form" info() tag.
|
|
This hint, along with 'display.precision', is used by some OPI clients to control how values are rendered.
|
|
|
|
The text value of the tag must be one of the following choices.
|
|
|
|
@li Default
|
|
@li String
|
|
@li Binary
|
|
@li Decimal
|
|
@li Hex
|
|
@li Exponential
|
|
@li Engineering
|
|
|
|
@code
|
|
record(ai, "...") {
|
|
info(Q:form, "Default") # implied default
|
|
}
|
|
@endcode
|
|
|
|
@subsection qsrv_aslib Access Security
|
|
|
|
QSRV will enforce an optional access control policy file (.acf) loaded by the usual means (cf. asSetFilename() ).
|
|
This policy is applied to both Single and Group PVs. With Group PVs, restrictions are not defined for the group,
|
|
but rather for the individual member records. The same policy will be applied regardess of how a record
|
|
is accessed (individually, or through a group).
|
|
|
|
Policy application differs from CA (RSRV) in several ways:
|
|
|
|
* Client hostname is always the numeric IP address. HAG() entries must either contained numeric IP addresses,
|
|
or that asCheckClientIP=1 flag must be set to translate hostnames into IPs on ACF file load (effects CA server as well).
|
|
This prevents clients from trivially forging "hostname".
|
|
* In additional to client usernames. UAG definitions may contained items beginning with "role/" which are matched
|
|
against the list of groups of which the client username is a member. Username to group lookup is done internally
|
|
to QSRV, and depends on IOC host authentication configuration. Note that this is still based on the client provided
|
|
username string.
|
|
|
|
@code
|
|
UAG(special) {
|
|
someone, "role/op"
|
|
}
|
|
@endcode
|
|
|
|
The "special" UAG will match CA or PVA clients with the username "someone".
|
|
It will also match a PVA client if the client provided username is a member
|
|
of the "op" group (supported on POSIX targets and Windows).
|
|
|
|
@subsection qsrv_link PVAccess Links
|
|
|
|
When built against Base >= 3.16.1, support is enabled for PVAccess links,
|
|
which are analogous to Channel Access (CA) links. However, the syntax
|
|
for PVA links is quite different.
|
|
|
|
@note The "dbjlr" and "dbpvar" IOC shell command provide information about PVA links in a running IOC.
|
|
|
|
A simple configuration using defaults is
|
|
|
|
@code
|
|
record(longin, "tgt") {}
|
|
record(longin, "src") {
|
|
field(INP, {pva:"tgt"})
|
|
}
|
|
@endcode
|
|
|
|
This is a shorthand for
|
|
|
|
@code
|
|
record(longin, "tgt") {}
|
|
record(longin, "src") {
|
|
field(INP, {pva:{pv:"tgt"}})
|
|
}
|
|
@endcode
|
|
|
|
Some additional keys (beyond "pv") may be used.
|
|
Defaults are shown below:
|
|
|
|
@code
|
|
record(longin, "tgt") {}
|
|
record(longin, "src") {
|
|
field(INP, {pva:{
|
|
pv:"tgt",
|
|
field:"", # may be a sub-field
|
|
local:false,# Require local PV
|
|
Q:4, # monitor queue depth
|
|
pipeline:false, # require that server uses monitor flow control protocol
|
|
proc:none, # Request record processing (side-effects).
|
|
sevr:false, # Maximize severity.
|
|
time:false, # set record time during getValue
|
|
monorder:0, # Order of record processing as a result of CP and CPP
|
|
retry:false,# allow Put while disconnected.
|
|
always:false,# CP/CPP input link process even when .value field hasn't changed
|
|
defer:false # Defer put
|
|
}})
|
|
}
|
|
@endcode
|
|
|
|
@subsubsection qsrv_link_pv pv: Target PV name
|
|
|
|
The PV name to search for.
|
|
This is the same name which could be used with 'pvget' or other client tools.
|
|
|
|
@subsubsection qsrv_link_field field: Structure field name
|
|
|
|
The name of a sub-field of the remotely provided Structure.
|
|
By default, an empty string "" uses the top-level Structure.
|
|
|
|
If the top level structure, or a sub-structure is selected, then
|
|
it is expeccted to conform to NTScalar, NTScalarArray, or NTEnum
|
|
to extract value and meta-data.
|
|
|
|
If the sub-field is an PVScalar or PVScalarArray, then a value
|
|
will be taken from it, but not meta-data will be available.
|
|
|
|
@todo Ability to traverse through unions and into structure arrays (as with group mappings).
|
|
|
|
@subsubsection qsrv_link_local local: Require local PV
|
|
|
|
When true, link will not connect unless the named PV is provided by the local (QSRV) data provider.
|
|
|
|
@subsubsection qsrv_link_Q Q: Monitor queue depth
|
|
|
|
Requests a certain monitor queue depth.
|
|
The server may, or may not, take this into consideration when selecting
|
|
a queue depth.
|
|
|
|
@subsubsection qsrv_link_pipeline pipeline: Monitor flow control
|
|
|
|
Expect that the server supports PVA monitor flow control.
|
|
If not, then the subscription will stall (ick.)
|
|
|
|
@subsubsection qsrv_link_proc proc: Request record processing (side-effects)
|
|
|
|
The meaning of this option depends on the direction of the link.
|
|
|
|
For output links, this option allows a request for remote processing (side-effects).
|
|
|
|
@li none (default) - Make no special request. Uses a server specific default.
|
|
@li false, "NPP" - Request to skip processing.
|
|
@li true, "PP" - Request to force processing.
|
|
@li "CP", "CPP" - For output links, an alias for "PP".
|
|
|
|
For input links, this option controls whether the record containing
|
|
the PVA link will be processed when subscription events are received.
|
|
|
|
@li none (default), false, "NPP" - Do not process on subscription updates.
|
|
@li true, "CP" - Always process on subscription updates.
|
|
@li "PP", "CPP" - Process on subscription updates if SCAN=Passive
|
|
|
|
@subsubsection qsrv_link_sevr sevr: Alarm propagation
|
|
|
|
This option controls whether reading a value from an input PVA link
|
|
has the addition effect of propagating any alarm via the Maximize
|
|
Severity process.
|
|
|
|
@li false - Do not maximize severity.
|
|
@li true - Maximize alarm severity
|
|
@li "MSI" - Maximize only if the remote severity is INVALID.
|
|
|
|
@subsubsection qsrv_link_time time: Time propagation
|
|
|
|
Somewhat analogous to sevr: applied to timestamp.
|
|
When true, the record TIME field is updated when the link value is read.
|
|
|
|
@warning TSEL must be set to -2 for time:true to have an effect.
|
|
|
|
@subsubsection qsrv_link_monorder monorder: Monitor processing order
|
|
|
|
When multiple record target the same target PV, and request processing
|
|
on subscription updates. This option allows the order of processing
|
|
to be specified.
|
|
|
|
Record are processed in increasing order.
|
|
monorder=-1 is processed before monorder=0.
|
|
Both are processed before monorder=1.
|
|
|
|
@subsubsection qsrv_link_defer defer: Defer put
|
|
|
|
By default (defer=false) an output link will immediately
|
|
start a PVA Put operation. defer=true will store the
|
|
new value in an internal cache, but not start a PVA Put.
|
|
|
|
This option, in combination with field: allows a single
|
|
Put to contain updates to multiple sub-fields.
|
|
|
|
|
|
@subsubsection qsrv_link_retry retry: Put while disconnected
|
|
|
|
Allow a Put operation to be queued while the link is disconnected.
|
|
The Put will be executed when the link becomes connected.
|
|
|
|
@subsubsection qsrv_link_always always: CP/CPP always process
|
|
|
|
By default (always:false) a subscription update will only cause a CP input link
|
|
to scan if the structure field (cf. field: option) is marked as changed.
|
|
Set to true to override this, and always process the link.
|
|
|
|
@subsubsection qsrv_link_sem Link semantics/behavior
|
|
|
|
This section attempts to answer some questions about how links behave in certain situations.
|
|
|
|
Links are evaluated in three basic contexts.
|
|
|
|
@li dbPutLink()/dbScanFwdLink()
|
|
@li dbGetLink() of non-CP link
|
|
@li dbGetLink() during a scan resulting from a CP link.
|
|
|
|
An input link can bring in a Value as well as meta-data, alarm, time, and display/control info.
|
|
For input links, the PVA link engine attempts to always maintain consistency between Value, alarm, and time.
|
|
However, consistency between these, and the display/control info is only ensured during a CP scan.
|
|
|
|
|
|
|
|
|
|
*/
|