Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply DBR_VFIELD #42

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,13 @@ environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMP: vs2019
BASE: 7.0
BASE: vfield
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMP: gcc
BASE: 7.0
BASE: vfield
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMP: vs2017
BASE: 7.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMP: vs2019
BASE: 3.15
BASE: vfield

# Platform: processor architecture
platform:
Expand Down
2 changes: 1 addition & 1 deletion .ci-local/defaults.set
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# EPICS Base
BASE_DIRNAME=base
BASE_REPONAME=epics-base
BASE_REPOOWNER=epics-base
BASE_REPOOWNER=mdavidsaver
BASE_VARNAME=EPICS_BASE
BASE_RECURSIVE=NO

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/ci-scripts-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ on:
env:
SETUP_PATH: .ci-local:.ci
EPICS_TEST_IMPRECISE_TIMING: YES
BASE: vfield

jobs:
native:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
BASE: ${{ matrix.base }}
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
Expand Down Expand Up @@ -145,7 +145,6 @@ jobs:
image: ${{ matrix.image }}
# Set environment variables from matrix parameters
env:
BASE: ${{ matrix.base }}
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
Expand Down
51 changes: 4 additions & 47 deletions documentation/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,8 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.

INPUT = . \
../pdbApp \
../common \
../p2pApp
../include \
../include/pv

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
Expand All @@ -819,50 +818,8 @@ INPUT_ENCODING = UTF-8
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.

FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf
FILE_PATTERNS = *.dox \
*.h

# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
Expand Down
3 changes: 3 additions & 0 deletions documentation/mainpage.dox
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ Documentation of @ref qsrv_config including @ref qsrv_group_def ,
@ref qsrv_aslib
and @ref qsrv_link configuration.

Beginning with UNRELEASED, several @ref qsrv_pvd_records are available
when build against Base with the DBR_VFIELD (UNMERGED) feature.

- @ref release_notes

@subsection qsrv_build Building
Expand Down
236 changes: 236 additions & 0 deletions documentation/records.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/**
@page qsrv_pvd_records QSRV PVD record types

@since UNRELEASED

Several additional process database record types are provided along with QSRV
which make use of pvData container classes.
These records include some fields which are only accessible via PV Access.
Device support for these record types must be written in C++.

- svectorin/out
- columnarin/out
- ndain
- statBin
- pvstructin
- tableAgg

All of these record types provide custom device support (dset)
struct definitions. eg. 'struct svectorindset'

@section qsrv_svector svectorin/out record types

The svectorin/out records are analogous to to aai/aao record types in EPICS Base,
with different management of array allocations. The aai/aao types manage a
C array which device support copies samples to/from.
The svectorin/out use an epics::pvData::shared_vector<> to allow immutable array data
references to be moved in/out without copying.

Configuration is similar to aai/aao, with the FTVL field being required
to specify the array element type.

Unlike aai/aao the NELM field is not required. It may be set to enable a limited
compatibility mode in which the NELM elements may be read (but not written) via Channel Access.

Device support code for svectorin needs to populate a shared_vector instance of the correct type,
and assign it to VAL.
Assigning an array of an incorrect type is an error, VAL will be cleared and an the record alarmed.

@code
/*
* record(svectorin, "myrec") {
* field(DTYP, "My Support")
* field(FTVL, "DOUBLE")
* field(NELM, "100") # only needed for CA read access
* }
*/
#include <svectorinRecord.h>
...
static
long read_my_array(svectorinRecord *prec) {
epics::pvData::shared_vector<double> arr(2);
arr[0] = 1.0;
arr[1] = 2.0;
prec->val = epics::pvData::static_shared_vector_cast<const void>(epics::pvData::freeze(arr));
return 0;
}
...
static svectorindtype devSVIMySupport = {{5,0,0,0,0}, &read_my_array};
...
@endcode

Device support code for svectorout will access the shared_vector assigned to VAL.
Since the array data is immutable, references may be safely passed to other
threads.

@section qsrv_columnar columnarin/out and statBin record types

The columnarin/out and statBin types may be understood as storing
a collection of named arrays of POD or string types.
Depending on the LAY field, this collection can either be presented
as a group of NTScalarArray sub-structures (LAY="Composite"), or as a single NTTable
with the arrays becoming columns (LAY="Table").

At this point, the only difference between columnarin and columnarout is the
presence of an INP vs. OUT field.

In either case, device support init_record() must use the multiArray::add_column()
or multiArray::add_columns() helper methods to define column name, type, and optionally
label (used with NTTable only).

@code
#include <columnarinRecord.h>
/*
* record(columnarin, "myrec") {
* field(DTYP, "My Support")
* field(LAY , "Table") # default is Composite
* }
*/
static
multiArray::Entry columns[] = {
{"a", "Column A", epics::pvData::pvString},
{"b", "Column B", epics::pvData::pvDouble},
{0}, // end
};
static
long init_record_my_table(dbCommon *pcommon) {
multiArray::add_columns(pcommon, columns);
return 0;
}
@endcode

Device support for the columnarin or statBin type will use multiArray::set_column()
to assign shared_vector instances for each "column".
In the case of LAY="Table" it is the responsibility for device support
to ensure that all arrays/columns have the same number of rows.

@code
static
long read_my_table(columnarinRecord *prec) {
epics::pvData::shared_vector<std::string> cola(2);
cola[0] = "hello";
cola[1] = "world";

epics::pvData::shared_vector<double> colb(2);
colb[0] = 1.0;
colb[1] = 2.0;

multiArray::set_column(prec, "a", epics::pvData::static_shared_vector_cast<const void>(epics::pvData::freeze(cola)));
multiArray::set_column(prec, "b", epics::pvData::static_shared_vector_cast<const void>(epics::pvData::freeze(colb)));
return 0;
}
...
static columnarindtype devCOLIMySupport = {{5,0,0,&init_record_my_table,0}, &read_my_table};
...
@endcode

Device support for the columnarout type will use multiArray::get_column() to retrieve
column arrays.

@subsection qsrv_statbin_softchannel statBin default device support

The statBin type is similar to columnarin with added fields, and a default
device support where INP can be pointed to an array field (eg. aai or svectorin)
to compute certain statistical values.

@code
record(aai, "some:array") { ... }
record(statBin, "my:stats") {
field(INP, "some:array")
field(DEC, "10") # decimate by 10. aka. 10 input samples to one output bin.
}
@endcode


@section qsrv_ndain ndain record type

The ndain record type presents an NTNDArray structure a la. areaDetector.
Some additional fields are added, notably W and H, and FTVL is omitted.
Otherwise this type is similar to svectorin.

Currently only Gray scale images are supported.

See process_img() in pdbApp/src/demo.cpp for a more realistic example.

@code
/*
* record(ndain, "myrec") {
* field(DTYP, "My Support")
* }
*/
#include <ndainRecord.h>
...
static
long read_my_image(ndainRecord *prec) {
// 3x2 8bit
prec->w = 3;
prec->h = 2;
epics::pvData::shared_vector<epics::pvData::uint8> arr(3*2);
// width is innermost/contiguous
// idx = h*prec->w + w
arr[0] = 1; // 0x0
arr[1] = 2;
arr[2] = 3; // 2x0
arr[3] = 4; // 0x1
arr[4] = 5;
arr[5] = 6;
prec->val = epics::pvData::static_shared_vector_cast<const void>(epics::pvData::freeze(arr));
return 0;
}
...
static ndaindtype devNDIMySupport = {{5,0,0,0,0}, &read_my_image};
...
@endcode

@section qsrv_pvstructin pvstructin record type

By analogy, the pvstructin record type is to these special record types what aSub is the Base record types.
A tool to be used when no other would be sufficient.

This record type allows device support to device an arbitrary pvData structure,
which is done by placing a PVStructure pointer in the VAL field during init_record().

It is then the responsibility of device support to manipulate the (arbitrary) structure,
and to set the appropriate bit(s) of the CHG bitmask when doing so.

A discussion of the proper handling of a PVStructure is outside the scope of this document.

@section qsrv_tableagg tableAgg record type

The tableAgg record builds a collection of arrays out of individual array inputs. Like
the columnarin/out and statBin records, the resulting value can be presented either as
a Table or as a Composite (structure) type, depending on the selection in the LAY field.

There are 26 inputs available to the record, A..Z:

INPA..INPZ specify where to obtain the data for each column
FNAA..FNAZ specify the field name for the corresponding column
LABA..LABZ specify the field label for each corresponding column
FTA..FTZ specify the data type of the elements of the corresponding column (default: DOUBLE)

Similar to columnarin/out and statBin, device support for tableAgg should call multiArray::add_column
or multiArray::add_columns in order to create the appropriate columns in the collection. Setting column
values should be done via multiArray::set_column.

@subsection qsrv_tableagg_softchannel tableAgg default device support

During initialization, the default device support for tableAgg creates columns based on FNAA..FNAZ,
LABA..LABZ and FTA..FTZ. It reads these inputs in order A..Z and stops creating new columns as soon
as it finds and empty FNAx field. For example, the following record will have only one column:

@code
record(tableAgg, "my:table") {
field(FNAA, "some_array")
field(INPA, "some:array")

# FNAB is empty, all following columns will be ignored

field(FNAC, "another_array")
field(INPC, "another:array")
}
@endcode

When processed, the default device support will read each INPx field and populate the corresponding
value with the obtained array.

*/
6 changes: 6 additions & 0 deletions iocBoot/iocimagedemo/ndain.db
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
record(ndain, "$(N):Array") {
field(DTYP, "QSRV Demo")
field(H, "1024")
field(W, "768")
field(PINI, "YES")
}
1 change: 1 addition & 0 deletions iocBoot/iocimagedemo/st.cmd
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!../../bin/linux-x86_64-debug/softIocPVA

dbLoadRecords("image.db","N=TST:image1")
dbLoadRecords("ndain.db","N=TST:image2")
dbLoadRecords("table.db","N=TST:table1")
dbLoadRecords("ntenum.db","P=TST:enum1")

Expand Down
Loading