Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e67486c319 | ||
|
|
4f1da262d2 | ||
|
|
65c31491d9 | ||
|
|
5450f564dc | ||
|
|
453c267c9b | ||
| 7a2d264f2c | |||
| 03f9c1ab07 | |||
|
|
6d41566b40 | ||
|
|
1250a3c236 | ||
|
|
28e5defc9b | ||
|
|
fbe1a1135f | ||
|
|
b75f942d5a | ||
|
|
e83ce61bf6 | ||
|
|
86d8b5deec | ||
|
|
abbcf486b8 | ||
|
|
e286d32716 | ||
|
|
ba33c7443c | ||
|
|
c6168a7477 | ||
|
|
dd2aa1863d | ||
|
|
66737740ef | ||
|
|
54bddc9942 | ||
|
|
02151964a9 | ||
|
|
d366cc9682 | ||
|
|
1cac2ccd7e | ||
|
|
9702b68d72 | ||
|
|
6a163d7fd4 | ||
|
|
1832c417e6 | ||
|
|
148cfef572 | ||
|
|
31050952b6 | ||
|
|
e0d422ffd9 | ||
|
|
452f2379a1 | ||
|
|
e2d95128a3 | ||
|
|
3a178ea5c4 | ||
|
|
24489f6535 | ||
|
|
28ca7ac1ab | ||
|
|
5a0b42fec7 | ||
|
|
35bf9dcb13 | ||
|
|
f22b5d5b7b | ||
|
|
9923459c4b | ||
|
|
50a7208174 | ||
|
|
7e7949b1fa | ||
|
|
76c00b78c9 | ||
|
|
1676192dd1 | ||
|
|
b76c91a885 | ||
|
|
2d186d40d5 | ||
|
|
e803240fbf | ||
|
|
54c07f705f | ||
|
|
fa23ddd370 | ||
|
|
41d56fdf89 | ||
|
|
a65fc3ef30 | ||
|
|
b69bc44974 | ||
|
|
a90f0173a7 | ||
|
|
83342beb7e | ||
|
|
f6e6cf037f | ||
|
|
80920ae0b0 | ||
|
|
1f7667b22d | ||
|
|
e15e84fb14 | ||
|
|
ba2e1c8a1d | ||
|
|
fb6873e9a3 | ||
|
|
2f4c0eea9d | ||
|
|
a2b635c2fe | ||
|
|
abd029aa71 | ||
|
|
57c6d07a93 | ||
|
|
91c5136883 | ||
|
|
5e151c3b7a | ||
|
|
fc4b51cb49 | ||
|
|
fc703958b3 | ||
|
|
1b156c92cd | ||
|
|
2c75f1d1e9 | ||
|
|
e03096c35e | ||
|
|
4b0970ffcb | ||
|
|
048d6ef737 | ||
|
|
4768444b8a | ||
|
|
0ce3613acc |
10
.ci/travis-build.sh
Executable file
10
.ci/travis-build.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make -j2 tapfiles
|
||||
make -j2 -s test-results
|
||||
fi
|
||||
107
.ci/travis-prepare.sh
Executable file
107
.ci/travis-prepare.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
CURDIR="$PWD"
|
||||
|
||||
cat << EOF > $CURDIR/configure/RELEASE.local
|
||||
EPICS_BASE=$HOME/.source/epics-base
|
||||
EOF
|
||||
|
||||
install -d "$HOME/.source"
|
||||
cd "$HOME/.source"
|
||||
|
||||
add_gh_flat() {
|
||||
MODULE=$1
|
||||
REPOOWNER=$2
|
||||
REPONAME=$3
|
||||
BRANCH=$4
|
||||
MODULE_UC=$(echo $MODULE | tr 'a-z' 'A-Z')
|
||||
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
|
||||
cd $MODULE && git log -n1 )
|
||||
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
|
||||
cat << EOF >> $CURDIR/configure/RELEASE.local
|
||||
${MODULE_UC}=$HOME/.source/$MODULE
|
||||
EOF
|
||||
}
|
||||
|
||||
# not recursive
|
||||
git clone --quiet --depth 5 --branch "$BRBASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
|
||||
(cd epics-base && git log -n1 )
|
||||
add_gh_flat pvData ${REPOPVD:-epics-base} pvDataCPP ${BRPVD:-master}
|
||||
|
||||
if [ -e $CURDIR/configure/RELEASE.local ]
|
||||
then
|
||||
cat $CURDIR/configure/RELEASE.local
|
||||
fi
|
||||
|
||||
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
|
||||
|
||||
# requires wine and g++-mingw-w64-i686
|
||||
if [ "$WINE" = "32" ]
|
||||
then
|
||||
echo "Cross mingw32"
|
||||
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
|
||||
CMPLR_PREFIX=i686-w64-mingw32-
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ "$STATIC" = "YES" ]
|
||||
then
|
||||
echo "Build static libraries/executables"
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
SHARED_LIBRARIES=NO
|
||||
STATIC_BUILD=YES
|
||||
EOF
|
||||
fi
|
||||
|
||||
case "$CMPLR" in
|
||||
clang)
|
||||
echo "Host compiler is clang"
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
|
||||
GNU = NO
|
||||
CMPLR_CLASS = clang
|
||||
CC = clang
|
||||
CCC = clang++
|
||||
EOF
|
||||
|
||||
# hack
|
||||
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
|
||||
|
||||
clang --version
|
||||
;;
|
||||
*)
|
||||
echo "Host compiler is default"
|
||||
gcc --version
|
||||
;;
|
||||
esac
|
||||
|
||||
cat <<EOF >> epics-base/configure/CONFIG_SITE
|
||||
USR_CPPFLAGS += $USR_CPPFLAGS
|
||||
USR_CFLAGS += $USR_CFLAGS
|
||||
USR_CXXFLAGS += $USR_CXXFLAGS
|
||||
EOF
|
||||
|
||||
# set RTEMS to eg. "4.9" or "4.10"
|
||||
# requires qemu, bison, flex, texinfo, install-info
|
||||
if [ -n "$RTEMS" ]
|
||||
then
|
||||
echo "Cross RTEMS${RTEMS} for pc386"
|
||||
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
|
||||
| tar -C / -xmj
|
||||
|
||||
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
|
||||
RTEMS_VERSION=$RTEMS
|
||||
RTEMS_BASE=$HOME/.rtems
|
||||
EOF
|
||||
cat << EOF >> epics-base/configure/CONFIG_SITE
|
||||
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
|
||||
EOF
|
||||
fi
|
||||
|
||||
make -j2 -C epics-base $EXTRA
|
||||
make -j2 -C pvData $EXTRA
|
||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,10 +1,14 @@
|
||||
bin/
|
||||
include/
|
||||
lib/
|
||||
db/
|
||||
dbd/
|
||||
configure/*.local
|
||||
html/
|
||||
**/O.*
|
||||
**/**/O.*
|
||||
QtC-*
|
||||
/cfg/
|
||||
/bin/
|
||||
/lib/
|
||||
/db/
|
||||
/dbd/
|
||||
/html/
|
||||
/include/
|
||||
/templates/
|
||||
/configure/*.local
|
||||
O.*/
|
||||
/QtC-*
|
||||
*.orig
|
||||
*.log
|
||||
.*.swp
|
||||
|
||||
17
.readthedocs.yml
Normal file
17
.readthedocs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
# .readthedocs.yml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the documentation/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: documentation/conf.py
|
||||
|
||||
# Build documentation with MkDocs
|
||||
#mkdocs:
|
||||
# configuration: mkdocs.yml
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
formats: all
|
||||
31
.travis.yml
Normal file
31
.travis.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
sudo: false
|
||||
dist: trusty
|
||||
language: c++
|
||||
compiler:
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libreadline6-dev
|
||||
- libncurses5-dev
|
||||
- perl
|
||||
- clang
|
||||
- g++-mingw-w64-i686
|
||||
- qemu-system-x86
|
||||
install:
|
||||
- ./.ci/travis-prepare.sh
|
||||
script:
|
||||
- ./.ci/travis-build.sh
|
||||
env:
|
||||
- BRBASE=7.0
|
||||
- BRBASE=7.0 CMPLR=clang
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++98"
|
||||
- BRBASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 CMPLR=clang EXTRA="CMD_CXXFLAGS=-std=c++11"
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=YES
|
||||
- BRBASE=7.0 WINE=32 TEST=NO STATIC=NO
|
||||
- BRBASE=7.0 RTEMS=4.10 TEST=NO
|
||||
- BRBASE=7.0 RTEMS=4.9 TEST=NO
|
||||
- BRBASE=3.16
|
||||
- BRBASE=3.15
|
||||
- BRBASE=3.14
|
||||
6
Doxyfile
6
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = normativeTypesCPP
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = 6.0.2
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -743,7 +743,7 @@ WARN_LOGFILE =
|
||||
# spaces.
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = include
|
||||
INPUT = src
|
||||
|
||||
# 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
|
||||
@@ -1008,7 +1008,7 @@ GENERATE_HTML = YES
|
||||
# The default directory is: html.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_OUTPUT = documentation/html
|
||||
HTML_OUTPUT = html/doxygen
|
||||
|
||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
|
||||
# generated HTML page (for example: .htm, .php, .asp).
|
||||
|
||||
83
README.md
83
README.md
@@ -1,78 +1,17 @@
|
||||
normativeTypesCPP
|
||||
=================
|
||||
# normativeTypesCPP
|
||||
|
||||
normativeTypesCPP is a C++ module containing helper classes which implement
|
||||
and provide support for the EPICS V4 Normative Types.
|
||||
The EPICS **Normative Types** are a set of standard high-level data types, designed to aid interoperability between EPICS PVA applications.
|
||||
|
||||
The latter are a set of standard high-level data types to aid interoperability
|
||||
of EPICS V4 applications and are specified in the
|
||||
[NormativeTypes Specification](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes.html).
|
||||
This normativeTypesCPP module is a part of the EPICS software toolkit that provides C++ helper classes which implement the EPICS Normative Types.
|
||||
|
||||
## Links
|
||||
|
||||
Status
|
||||
------
|
||||
- General information about EPICS can be found at the
|
||||
[EPICS Controls website](https://epics-controls.org).
|
||||
- API documentation for this module can be found in its
|
||||
documentation directory, in particular the file
|
||||
normativeTypesCPP.html
|
||||
|
||||
The current release (5.0) implements fully the
|
||||
[16 Mar 2015 version](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html)
|
||||
of the Normative Types Specification.
|
||||
|
||||
The module status is alpha and the API and behaviour may change in future
|
||||
versions.
|
||||
|
||||
The previous release (4.0) supported only 6 types.
|
||||
There is no documentation yet for the new types added in 5.0.
|
||||
|
||||
|
||||
Further Info
|
||||
------------
|
||||
|
||||
Consult the documents in the documentation directory, in particular
|
||||
|
||||
* normativeTypesCPP.html
|
||||
* RELEASE_NOTES.md
|
||||
|
||||
Also see the [EPICS Version 4 website](http://epics-pvdata.sourceforge.net)
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
normativeTypesCPP requires recent versions of the following software:
|
||||
|
||||
1. EPICS Base (v3.14.12.3 or later)
|
||||
2. EPICS4 pvCommonCPP (4.1.0 or later)
|
||||
2. pvDataCPP (5.0.0 or later)
|
||||
|
||||
(pvCommonCPP may not be needed depending on host/compiler.)
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Building uses the make utility and the EPICS base build system.
|
||||
|
||||
The build system needs the location of the prerequisites, e.g. by placing the
|
||||
lines of the form
|
||||
|
||||
PVDATA = /home/install/epicsV4/pvDataCPP
|
||||
PVCOMMON = /home/install/epicsV4/pvCommonCPP
|
||||
EPICS_BASE = /home/install/epics/base
|
||||
|
||||
pointing to the locations in a file called RELEASE.local
|
||||
in the configure directory or the parent directory of normativeTypesCPP.
|
||||
|
||||
With this in place, to build type make
|
||||
|
||||
make
|
||||
|
||||
To perform a clean build type
|
||||
|
||||
make clean uninstall
|
||||
|
||||
To run the unit tests type
|
||||
|
||||
make runtests
|
||||
|
||||
For more information on the EPICS build system consult the
|
||||
[Application Development guide](http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide.pdf).
|
||||
## Building
|
||||
|
||||
This module is included as a submodule of a full EPICS 7 release and will be compiled during builds of that software.
|
||||
|
||||
12
configure/CONFIG_NTYPES_VERSION
Normal file
12
configure/CONFIG_NTYPES_VERSION
Normal file
@@ -0,0 +1,12 @@
|
||||
# Version number for the Normative Types API and shared library
|
||||
|
||||
EPICS_NTYPES_MAJOR_VERSION = 6
|
||||
EPICS_NTYPES_MINOR_VERSION = 0
|
||||
EPICS_NTYPES_MAINTENANCE_VERSION = 2
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_NTYPES_DEVELOPMENT_FLAG = 0
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
@@ -32,3 +32,5 @@ endif
|
||||
-include $(TOP)/../CONFIG_SITE.local
|
||||
-include $(TOP)/configure/CONFIG_SITE.local
|
||||
|
||||
# MSVC - skip defining min()/max() macros
|
||||
USR_CPPFLAGS_WIN32 += -DNOMINMAX
|
||||
|
||||
@@ -10,6 +10,8 @@ include $(TOP)/configure/CONFIG
|
||||
# but continue the build even if conflicts are found.
|
||||
CHECK_RELEASE = YES
|
||||
|
||||
CFG += CONFIG_NTYPES_VERSION
|
||||
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
#RELEASE Location of external products
|
||||
# RELEASE - Location of external support modules
|
||||
#
|
||||
# IF YOU MAKE ANY CHANGES to this file you MUST at least run
|
||||
# "gnumake" in this directory afterwards; you usually need
|
||||
# to run "gnumake rebuild" in the application's top level
|
||||
# directory each time this file is changed.
|
||||
# IF YOU CHANGE ANY PATHS in this file or make API changes to
|
||||
# any modules it refers to, you should do a "make rebuild" in
|
||||
# this application's top level directory.
|
||||
#
|
||||
# NOTE: The build does not check dependencies against files
|
||||
# that are outside this application, thus you should run
|
||||
# "gnumake distclean install" in the top directory each time
|
||||
# EPICS_BASE, SNCSEQ, or any other external module defined
|
||||
# in the RELEASE file is rebuilt.
|
||||
# The EPICS build process does not check dependencies against
|
||||
# any files from outside the application, so it is safest to
|
||||
# rebuild it completely if any modules it depends on change.
|
||||
#
|
||||
# Host/target specific settings can be specified in files named
|
||||
# Host- or target-specific settings can be given in files named
|
||||
# RELEASE.$(EPICS_HOST_ARCH).Common
|
||||
# RELEASE.Common.$(T_A)
|
||||
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
#
|
||||
# This file is parsed by both GNUmake and an EPICS Perl script,
|
||||
# so it may ONLY contain definititions of paths to other support
|
||||
# modules, variable definitions that are used in module paths,
|
||||
# and include statements that pull in other RELEASE files.
|
||||
# Variables may be used before their values have been set.
|
||||
# Build variables that are NOT used in paths should be set in
|
||||
# the CONFIG_SITE file.
|
||||
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
# Variables and paths to dependent modules:
|
||||
#MODULES = /path/to/modules
|
||||
#MYMODULE = $(MODULES)/my-module
|
||||
|
||||
#If using the sequencer, point SNCSEQ at its top directory:
|
||||
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
|
||||
# If building the EPICS modules individually, set these:
|
||||
#EPICS_PVDATA = $(MODULES)/pvData-7.0.0
|
||||
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
|
||||
#EPICS_BASE = $(MODULES)/core-7.0.1
|
||||
|
||||
# EPICS_BASE usually appears last so other apps can override stuff:
|
||||
#EPICS_BASE=/opt/epics/base
|
||||
|
||||
#Capfast users may need the following definitions
|
||||
#CAPFAST_TEMPLATES=
|
||||
#SCH2EDIF_PATH=
|
||||
# Set RULES here if you want to use build rules from elsewhere:
|
||||
#RULES = $(MODULES)/build-rules
|
||||
|
||||
# These allow developers to override the RELEASE variable settings
|
||||
# without having to modify the configure/RELEASE file itself.
|
||||
-include $(TOP)/../RELEASE.local
|
||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
||||
-include $(TOP)/configure/RELEASE.local
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;" />
|
||||
<meta name="keywords" content="EPICS, EPICSv4" />
|
||||
<title>EPICS V4 Normative Types Release Notes</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../base.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../epicsv4.css" />
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<h1>Release 5.1.2</h1>
|
||||
|
||||
<p>The main changes since release 5.1.1 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>NTUnionBuilder: Add missing value() function</li>
|
||||
<li>Updated document: Now document all Normative Types</li>
|
||||
</ul>
|
||||
|
||||
<h1>Release 5.1.1</h1>
|
||||
|
||||
<p>The main changes since release 5.0 are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Linux shared library version added</li>
|
||||
<li>Headers and source locations have changed</li>
|
||||
<li>Missing is_a implementations added</li>
|
||||
<li>NTAttribute::addTags() is now non-virtual</li>
|
||||
<li>New license file replaces LICENSE and COPYRIGHT</li>
|
||||
</ul>
|
||||
|
||||
<h2>Shared library version added</h2>
|
||||
|
||||
<p>Linux shared library version numbers have been added by setting SHRLIB_VERSION
|
||||
(to 5.1 in this case). So shared object will be libnt.so.5.1 instead of
|
||||
libpvData.so.</p>
|
||||
|
||||
<h2>Headers and source locations have changed</h2>
|
||||
|
||||
<p>Source has moved out of nt directory directly into src.</p>
|
||||
|
||||
<p>Headers have been moved into a pv directory. This facilitates using some IDEs
|
||||
such as Qt Creator.</p>
|
||||
|
||||
<p>src/nt/ntscalar.cpp -> src/ntscalar.cpp
|
||||
src/nt/ntscalar.h -> src/pv/ntscalar.h</p>
|
||||
|
||||
<h2>Missing is_a implementations added</h2>
|
||||
|
||||
<p>is_a(PVStructurePtr const &) implementation has been added for each type.</p>
|
||||
|
||||
<h1>Release 5.0</h1>
|
||||
|
||||
<p>This release adds support through wrapper classes and builders for the
|
||||
remaining Normative Types:</p>
|
||||
|
||||
<ul>
|
||||
<li>NTEnum</li>
|
||||
<li>NTMatrix</li>
|
||||
<li>NTURI</li>
|
||||
<li>NTAttribute</li>
|
||||
<li>NTContinuum</li>
|
||||
<li>NTHistogram</li>
|
||||
<li>NTAggregate</li>
|
||||
<li>NTUnion</li>
|
||||
<li>NTScalarMultiChannel</li>
|
||||
</ul>
|
||||
|
||||
<p>Release 5.0 therefore implements fully the
|
||||
<a href="http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html">16 Mar 2015 version</a>
|
||||
of the normativeTypes specification.</p>
|
||||
|
||||
<p>Each wrapper class has an extended API:</p>
|
||||
|
||||
<ul>
|
||||
<li>is_a now has a convenience overload taking a PVStructure.</li>
|
||||
<li>isCompatible, reporting introspection type compatibility, now has an overload
|
||||
taking a Structure. The PVStructure version is retained as a convenience
|
||||
method and for backwards compatibility.</li>
|
||||
<li>An isValid function now reports validity of a compatible PVStructure's data
|
||||
with respect to the specification.</li>
|
||||
</ul>
|
||||
|
||||
<p>Other changes are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Support for NTAttributes extended as required by NTNDArray
|
||||
(NTNDArrayAttributes).</li>
|
||||
<li>A new class for parsing NT IDs (NTID).</li>
|
||||
<li>Resolution of the confusion between column names and labels in NTTable and
|
||||
improved API. Function for adding columns is now addColumn rather than add.
|
||||
New getColumnNames function provided.</li>
|
||||
<li>isConnected is treated as an optional rather than a required field in
|
||||
NTMultiChannelArray. isConnected() and addIsConnected() functions added to
|
||||
wrapper and builder respectively.</li>
|
||||
<li>Unit tests for all new classes.</li>
|
||||
</ul>
|
||||
|
||||
<h1>Release 4.0</h1>
|
||||
|
||||
<p>This is the first release of normativeTypesCPP that is part of an official
|
||||
EPICS V4 release.
|
||||
It is a major rewrite of the previous versions of normativeTypesCPP.</p>
|
||||
|
||||
<p>This release provides support through wrapper classes and builders for the
|
||||
following Normative Types:</p>
|
||||
|
||||
<ul>
|
||||
<li>NTScalar</li>
|
||||
<li>NTScalarArray</li>
|
||||
<li>NTNameValue</li>
|
||||
<li>NTTable</li>
|
||||
<li>NTMultiChannel</li>
|
||||
<li>NTNDArray</li>
|
||||
</ul>
|
||||
|
||||
<p>Each type has a wrapper class of the same name which has functions for checking
|
||||
compatibility of existing PVStructures (isCompatible) and the reported types of
|
||||
Structures (is_a), wraps existing PVStructures (wrap, wrapUnsafe) and provides
|
||||
a convenient interface to all required and optional fields.</p>
|
||||
|
||||
<p>Each type has a builder which can create a Structure, a PVStructure or a
|
||||
wrapper around a new PVStructure. In each case optional or extra fields can be
|
||||
added and options such as choice of scalar type can be made.</p>
|
||||
|
||||
<p>Additional features are:</p>
|
||||
|
||||
<ul>
|
||||
<li>Utility classes NTField and NTPVField for standard structure fields and
|
||||
NTUtils for type IDs.</li>
|
||||
<li>Unit tests for the implemented classes.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,91 +1,135 @@
|
||||
Release 5.1.2
|
||||
=============
|
||||
# normativeTypes Module
|
||||
|
||||
This document summarizes the changes to the module between releases.
|
||||
|
||||
## Release 6.0.2 (EPICS 7.0.10, December 2025)
|
||||
|
||||
- Fix potential NULL pointer dereference in `NTNDArray::getValueSize()`
|
||||
|
||||
## Release 6.0.1 (EPICS 7.0.3.1, October 2019)
|
||||
|
||||
- Doxygen updates and read-the-docs integration.
|
||||
|
||||
## Release 6.0.0 (EPICS 7.0.3, July 2019)
|
||||
|
||||
- Reimplement `isCompatible()` methods to use a new internal validation API in
|
||||
order to make the implementation uniform, less repetitive and less strict.
|
||||
|
||||
The new implementation is less strict in the sense that it considers types that
|
||||
can be converted into one another compatible with each other.
|
||||
For example, any `Scalar` is considered compatible with any other `Scalar`,
|
||||
regardless of the underlying type.
|
||||
Normative Types users are advised to use `getAs()` and `putFrom()` when
|
||||
getting/putting data from/into `PVScalar`s and `PVScalarArray`s.
|
||||
|
||||
Also, `isCompatible()` methods now disregard field order and extra fields that
|
||||
are not part of the specification.
|
||||
|
||||
This change is not expected to break any current server or client, but it will
|
||||
break existing clients that rely on the previous `isCompatible()` strictness
|
||||
once servers start to take advantage of `isCompatible()` now being less strict.
|
||||
|
||||
## Release 5.2.2
|
||||
|
||||
- Fix `NTTable::getColumnNames()`.
|
||||
|
||||
## Release 5.2.1 (EPICS 7.0.2, Dec 2018)
|
||||
|
||||
- No functional changes.
|
||||
- Removal of declaration for unimplemented `PVNTField::createAlarmLimit()` and
|
||||
elimination of unused variables.
|
||||
|
||||
|
||||
## Release 5.2.0 (EPICS 7.0.1, Dec 2017)
|
||||
|
||||
This release contains bug fixes and minor source updates needed to
|
||||
build against the latest version of pvData.
|
||||
|
||||
|
||||
## Release 5.1.2 (EPICS V4.6, Aug 2016)
|
||||
|
||||
The main changes since release 5.1.1 are:
|
||||
|
||||
* NTUnionBuilder: Add missing value() function
|
||||
* Updated document: Now document all Normative Types
|
||||
- NTUnionBuilder: Add missing `value()` function
|
||||
- Updated document: Now document all Normative Types
|
||||
|
||||
|
||||
Release 5.1.1
|
||||
=============
|
||||
## Release 5.1.1
|
||||
|
||||
The main changes since release 5.0 are:
|
||||
|
||||
* Linux shared library version added
|
||||
* Headers and source locations have changed
|
||||
* Missing is_a implementations added
|
||||
* NTAttribute::addTags() is now non-virtual
|
||||
* New license file replaces LICENSE and COPYRIGHT
|
||||
- Linux shared library version added
|
||||
- Headers and source locations have changed
|
||||
- Missing `is_a()` implementations added
|
||||
- `NTAttribute::addTags()` is now non-virtual
|
||||
- New license file replaces LICENSE and COPYRIGHT
|
||||
|
||||
Shared library version added
|
||||
----------------------------
|
||||
### Shared library version added
|
||||
|
||||
Linux shared library version numbers have been added by setting SHRLIB_VERSION
|
||||
(to 5.1 in this case). So shared object will be libnt.so.5.1 instead of
|
||||
libpvData.so.
|
||||
Linux shared library version numbers have been added by setting `SHRLIB_VERSION`
|
||||
(to 5.1 in this case).
|
||||
The shared object will be `libnt.so.5.1` instead of `libnt.so`.
|
||||
|
||||
Headers and source locations have changed
|
||||
-----------------------------------------
|
||||
### Headers and source locations have changed
|
||||
|
||||
Source has moved out of nt directory directly into src.
|
||||
|
||||
Headers have been moved into a pv directory. This facilitates using some IDEs
|
||||
such as Qt Creator.
|
||||
Headers have been moved into a pv directory.
|
||||
This facilitates using some IDEs such as Qt Creator.
|
||||
|
||||
src/nt/ntscalar.cpp -> src/ntscalar.cpp
|
||||
src/nt/ntscalar.h -> src/pv/ntscalar.h
|
||||
- `src/nt/ntscalar.cpp -> src/ntscalar.cpp`
|
||||
- `src/nt/ntscalar.h -> src/pv/ntscalar.h`
|
||||
|
||||
Missing is_a implementations added
|
||||
----------------------------------
|
||||
### Missing `is_a()` implementations added
|
||||
|
||||
is_a(PVStructurePtr const &) implementation has been added for each type.
|
||||
`is_a(PVStructurePtr const &)` implementation has been added for each type.
|
||||
|
||||
|
||||
Release 5.0
|
||||
===========
|
||||
## Release 5.0 (EPICS V4.5, Oct 2015)
|
||||
|
||||
This release adds support through wrapper classes and builders for the
|
||||
remaining Normative Types:
|
||||
|
||||
* NTEnum
|
||||
* NTMatrix
|
||||
* NTURI
|
||||
* NTAttribute
|
||||
* NTContinuum
|
||||
* NTHistogram
|
||||
* NTAggregate
|
||||
* NTUnion
|
||||
* NTScalarMultiChannel
|
||||
- NTEnum
|
||||
- NTMatrix
|
||||
- NTURI
|
||||
- NTAttribute
|
||||
- NTContinuum
|
||||
- NTHistogram
|
||||
- NTAggregate
|
||||
- NTUnion
|
||||
- NTScalarMultiChannel
|
||||
|
||||
Release 5.0 therefore implements fully the
|
||||
[16 Mar 2015 version](http://epics-pvdata.sourceforge.net/alpha/normativeTypes/normativeTypes_20150316.html)
|
||||
of the normativeTypes specification.
|
||||
Release 5.0 therefore fully implements the 16 Mar 2015 version of the
|
||||
normativeTypes specification.
|
||||
|
||||
Each wrapper class has an extended API:
|
||||
|
||||
* is_a now has a convenience overload taking a PVStructure.
|
||||
* isCompatible, reporting introspection type compatibility, now has an overload
|
||||
taking a Structure. The PVStructure version is retained as a convenience
|
||||
method and for backwards compatibility.
|
||||
* An isValid function now reports validity of a compatible PVStructure's data
|
||||
with respect to the specification.
|
||||
- `is_a()` now has a convenience overload taking a PVStructure.
|
||||
- `isCompatible()`, reporting introspection type compatibility, now has an
|
||||
overload taking a Structure.
|
||||
The PVStructure version is retained as a convenience method and for backwards
|
||||
compatibility.
|
||||
- An `isValid()` function now reports validity of a compatible PVStructure's
|
||||
data with respect to the specification.
|
||||
|
||||
Other changes are:
|
||||
|
||||
* Support for NTAttributes extended as required by NTNDArray
|
||||
- Support for NTAttributes extended as required by NTNDArray
|
||||
(NTNDArrayAttributes).
|
||||
* A new class for parsing NT IDs (NTID).
|
||||
* Resolution of the confusion between column names and labels in NTTable and
|
||||
improved API. Function for adding columns is now addColumn rather than add.
|
||||
New getColumnNames function provided.
|
||||
* isConnected is treated as an optional rather than a required field in
|
||||
NTMultiChannelArray. isConnected() and addIsConnected() functions added to
|
||||
wrapper and builder respectively.
|
||||
* Unit tests for all new classes.
|
||||
- A new class for parsing NT IDs (NTID).
|
||||
- Resolution of the confusion between column names and labels in NTTable and
|
||||
improved API.
|
||||
Function for adding columns is now `addColumn()` rather than `add()`.
|
||||
A new `getColumnNames()` function provided.
|
||||
- `isConnected()` is treated as an optional rather than a required field in
|
||||
NTMultiChannelArray.
|
||||
`isConnected()` and `addIsConnected()` functions added to wrapper and builder
|
||||
respectively.
|
||||
|
||||
Release 4.0
|
||||
===========
|
||||
- Unit tests for all new classes.
|
||||
|
||||
## Release 4.0 (EPICS V4.4, Dec 2014)
|
||||
|
||||
This is the first release of normativeTypesCPP that is part of an official
|
||||
EPICS V4 release.
|
||||
@@ -94,26 +138,27 @@ It is a major rewrite of the previous versions of normativeTypesCPP.
|
||||
This release provides support through wrapper classes and builders for the
|
||||
following Normative Types:
|
||||
|
||||
* NTScalar
|
||||
* NTScalarArray
|
||||
* NTNameValue
|
||||
* NTTable
|
||||
* NTMultiChannel
|
||||
* NTNDArray
|
||||
- NTScalar
|
||||
- NTScalarArray
|
||||
- NTNameValue
|
||||
- NTTable
|
||||
- NTMultiChannel
|
||||
- NTNDArray
|
||||
|
||||
Each type has a wrapper class of the same name which has functions for checking
|
||||
compatibility of existing PVStructures (isCompatible) and the reported types of
|
||||
Structures (is_a), wraps existing PVStructures (wrap, wrapUnsafe) and provides
|
||||
a convenient interface to all required and optional fields.
|
||||
compatibility of existing PVStructures (`isCompatible()`) and the reported types
|
||||
of Structures (`is_a()`),
|
||||
wraps existing PVStructures (`wrap()`, `wrapUnsafe()`) and provides a convenient
|
||||
interface to all required and optional fields.
|
||||
|
||||
Each type has a builder which can create a Structure, a PVStructure or a
|
||||
wrapper around a new PVStructure. In each case optional or extra fields can be
|
||||
added and options such as choice of scalar type can be made.
|
||||
|
||||
wrapper around a new PVStructure.
|
||||
In each case optional or extra fields can be added and options such as choice of
|
||||
scalar type can be made.
|
||||
|
||||
Additional features are:
|
||||
|
||||
* Utility classes NTField and NTPVField for standard structure fields and
|
||||
- Utility classes NTField and NTPVField for standard structure fields and
|
||||
NTUtils for type IDs.
|
||||
* Unit tests for the implemented classes.
|
||||
- Unit tests for the implemented classes.
|
||||
|
||||
|
||||
7
documentation/_static/css/custom.css
Normal file
7
documentation/_static/css/custom.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.wy-side-nav-search {
|
||||
background-color: #18334B;
|
||||
}
|
||||
|
||||
.wy-side-nav-search input[type="text"] {
|
||||
border-color: #18334b;
|
||||
}
|
||||
77
documentation/conf.py
Normal file
77
documentation/conf.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'normativeTypes (C++)'
|
||||
copyright = '2019, EPICS Controls.'
|
||||
author = 'EPICS'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.intersphinx',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# Intersphinx links to subprojects
|
||||
intersphinx_mapping = {
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
html_css_files = [
|
||||
'css/custom.css',
|
||||
]
|
||||
|
||||
master_doc = 'index'
|
||||
|
||||
html_theme_options = {
|
||||
'logo_only': True,
|
||||
}
|
||||
html_logo = "images/EPICS_white_logo_v02.png"
|
||||
|
||||
html_extra_path = ['../html']
|
||||
|
||||
|
||||
# -- Run Doxygen ------------------------------------------------------------
|
||||
|
||||
import subprocess
|
||||
subprocess.call('cd ..; mkdir -p html/doxygen; doxygen', shell=True)
|
||||
BIN
documentation/images/EPICS_white_logo_v02.png
Normal file
BIN
documentation/images/EPICS_white_logo_v02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
17
documentation/index.rst
Normal file
17
documentation/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
NormativeTypes (C++) Library
|
||||
============================
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
EPICS Website <https://epics-controls.org>
|
||||
EPICS Documentation Home <https://docs.epics-controls.org>
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: normativeTypesCPP
|
||||
|
||||
Reference Manual <ntCPP>
|
||||
API Documentation <https://docs.epics-controls.org/projects/normativetypes-cpp/en/latest/doxygen>
|
||||
Source Code Repository on GitHub <https://github.com/epics-base/normativeTypesCPP>
|
||||
File diff suppressed because it is too large
Load Diff
3270
documentation/ntCPP.rst
Normal file
3270
documentation/ntCPP.rst
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,28 +21,20 @@ installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
# If microbench version does not exist, try without
|
||||
if [ "${MB}" = "WITH_MICROBENCH" ]; then
|
||||
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
else
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
tar -xzf ${module}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
###########################################
|
||||
# Defaults for EPICS Base and MB
|
||||
# Defaults for EPICS Base
|
||||
|
||||
DEFAULT_BASE=3.15.4
|
||||
BASE=${BASE:-${DEFAULT_BASE}}
|
||||
MB=${MB:-"NO_MICROBENCH"}
|
||||
|
||||
###########################################
|
||||
# Dependent module branches
|
||||
|
||||
PVDATA_BRANCH="release-6.0"
|
||||
PVDATA_BRANCH="master"
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
@@ -80,6 +72,6 @@ make distclean all
|
||||
make runtests
|
||||
|
||||
###########################################
|
||||
# Create distribution
|
||||
# Create cache
|
||||
|
||||
tar --exclude=test* -czf normativeTypes.CB-dist.tar.gz lib include
|
||||
|
||||
@@ -21,14 +21,7 @@ installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
# If microbench version does not exist, try without
|
||||
if [ "${MB}" = "WITH_MICROBENCH" ]; then
|
||||
if wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
else
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
tar -xzf ${module}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
@@ -38,7 +31,6 @@ installE4 () {
|
||||
BASE=3.15.4
|
||||
PUBLISH=${PUBLISH:-NO}
|
||||
BRANCH=${BRANCH:-master}
|
||||
MB=NO_MICROBENCH
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
@@ -65,9 +57,10 @@ doxygen
|
||||
###########################################
|
||||
# Publish
|
||||
|
||||
if [ "${PUBLISH}" != "NO" ]; then
|
||||
if [ "${PUBLISH}" != "DONT" ]; then
|
||||
# Upload explicit dummy to ensure target directory exists
|
||||
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
|
||||
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/normativeTypesCPP/${PUBLISH}/
|
||||
|
||||
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/normativeTypesCPP/${PUBLISH}/
|
||||
fi
|
||||
|
||||
@@ -47,7 +47,7 @@ LIBRARY = nt
|
||||
nt_LIBS += pvData Com
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION ?= 5.1
|
||||
SHRLIB_VERSION ?= $(EPICS_NTYPES_MAJOR_VERSION).$(EPICS_NTYPES_MINOR_VERSION).$(EPICS_NTYPES_MAINTENANCE_VERSION)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntaggregate.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -194,83 +196,26 @@ bool NTAggregate::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTAggregate::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarConstPtr valueField = structure->getField<Scalar>("value");
|
||||
if (valueField.get() == 0 || valueField->getScalarType() != pvDouble)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
ScalarConstPtr nField = structure->getField<Scalar>("N");
|
||||
if (nField.get() == 0 || nField->getScalarType() != pvLong)
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
FieldConstPtr field = structure->getField("dispersion");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr dispersionField = structure->getField<Scalar>("dispersion");
|
||||
if (!dispersionField.get() || dispersionField->getScalarType() != pvDouble)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("first");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr firstField = structure->getField<Scalar>("first");
|
||||
if (!firstField.get() || firstField->getScalarType() != pvDouble)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("firstTimeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("last");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr lastField = structure->getField<Scalar>("last");
|
||||
if (!lastField.get() || lastField->getScalarType() != pvDouble)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("lastTimeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("max");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr maxField = structure->getField<Scalar>("max");
|
||||
if (!maxField.get() || maxField->getScalarType() != pvDouble)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("min");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr minField = structure->getField<Scalar>("min");
|
||||
if (!minField.get() || minField->getScalarType() != pvDouble)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<Scalar>("value")
|
||||
.has<Scalar>("N")
|
||||
.maybeHas<Scalar>("dispersion")
|
||||
.maybeHas<Scalar>("first")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("firstTimeStamp")
|
||||
.maybeHas<Scalar>("last")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("lastTimeStamp")
|
||||
.maybeHas<Scalar>("max")
|
||||
.maybeHas<Scalar>("min")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTAggregate::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntattribute.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -130,46 +132,22 @@ bool NTAttribute::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTAttribute::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarConstPtr nameField = structure->getField<Scalar>("name");
|
||||
if (nameField.get() == 0 || nameField->getScalarType() != pvString)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
UnionConstPtr valueField = structure->getField<Union>("value");
|
||||
if (valueField.get() == 0 || !valueField->isVariant())
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
FieldConstPtr field = structure->getField("tags");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr tagsField = structure->getField<ScalarArray>("tags");
|
||||
if (tagsField.get() == 0 || tagsField->getElementType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<Scalar>("name")
|
||||
.has<Union>("value")
|
||||
.maybeHas<ScalarArray>("tags")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTAttribute::isCompatible(PVStructurePtr const & pvStructure)
|
||||
{
|
||||
if(!pvStructure) return false;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntcontinuum.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -122,42 +124,22 @@ bool NTContinuum::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTContinuum::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarArrayConstPtr baseField = structure->getField<ScalarArray>("base");
|
||||
if (baseField.get() == 0 || baseField->getElementType() != pvDouble)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if (valueField.get() == 0 || valueField->getElementType() != pvDouble)
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
ScalarArrayConstPtr unitsField = structure->getField<ScalarArray>("units");
|
||||
if (unitsField.get() == 0 || unitsField->getElementType() != pvString)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("base")
|
||||
.has<ScalarArray>("value")
|
||||
.has<ScalarArray>("units")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTContinuum::isCompatible(PVStructurePtr const & pvStructure)
|
||||
{
|
||||
if(!pvStructure) return false;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntenum.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -121,34 +123,20 @@ bool NTEnum::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTEnum::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
FieldConstPtr valueField = structure->getField("value");
|
||||
if (!valueField.get() || !ntField->isEnumerated(valueField))
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<&NTField::isEnumerated, Structure>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTEnum::isCompatible(PVStructurePtr const & pvStructure)
|
||||
{
|
||||
if(!pvStructure) return false;
|
||||
|
||||
241
src/ntfield.cpp
241
src/ntfield.cpp
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntfield.h>
|
||||
@@ -31,198 +32,97 @@ NTField::NTField()
|
||||
{
|
||||
}
|
||||
|
||||
Result& NTField::isEnumerated(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("index")
|
||||
.has<ScalarArray>("choices");
|
||||
}
|
||||
|
||||
bool NTField::isEnumerated(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=2) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("index")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("choices")!=0) return false;
|
||||
if(f->getType()!=scalarArray) return false;
|
||||
ScalarConstPtr sa = static_pointer_cast<const Scalar>(f);
|
||||
if(sa->getScalarType()!=pvString) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isEnumerated(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
Result& NTField::isTimeStamp(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("secondsPastEpoch")
|
||||
.has<Scalar>("nanoseconds")
|
||||
.has<Scalar>("userTag");
|
||||
}
|
||||
|
||||
bool NTField::isTimeStamp(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=3) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("secondsPastEpoch")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvLong) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("nanoseconds")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[2];
|
||||
if(names[2].compare("userTag")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isTimeStamp(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
Result& NTField::isAlarm(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("severity")
|
||||
.has<Scalar>("status")
|
||||
.has<Scalar>("message");
|
||||
}
|
||||
|
||||
bool NTField::isAlarm(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=3) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("severity")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("status")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[2];
|
||||
if(names[2].compare("message")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvString) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isAlarm(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
Result& NTField::isDisplay(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("limitLow")
|
||||
.has<Scalar>("limitHigh")
|
||||
.has<Scalar>("description")
|
||||
.has<Scalar>("format")
|
||||
.has<Scalar>("units");
|
||||
|
||||
}
|
||||
|
||||
bool NTField::isDisplay(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=5) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("limitLow")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("limitHigh")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[2];
|
||||
if(names[2].compare("description")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvString) return false;
|
||||
f = fields[3];
|
||||
if(names[3].compare("format")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvString) return false;
|
||||
f = fields[4];
|
||||
if(names[4].compare("units")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvString) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isDisplay(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
Result& NTField::isAlarmLimit(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("active")
|
||||
.has<Scalar>("lowAlarmLimit")
|
||||
.has<Scalar>("lowWarningLimit")
|
||||
.has<Scalar>("highWarningLimit")
|
||||
.has<Scalar>("highAlarmLimit")
|
||||
.has<Scalar>("lowAlarmSeverity")
|
||||
.has<Scalar>("lowWarningSeverity")
|
||||
.has<Scalar>("highWarningSeverity")
|
||||
.has<Scalar>("highAlarmSeverity")
|
||||
.has<Scalar>("hysteresis");
|
||||
}
|
||||
|
||||
bool NTField::isAlarmLimit(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=10) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("active")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvBoolean) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("lowAlarmLimit")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[2];
|
||||
if(names[2].compare("lowWarningLimit")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[3];
|
||||
if(names[3].compare("highWarningLimit")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[4];
|
||||
if(names[4].compare("highAlarmLimit")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[5];
|
||||
if(names[5].compare("lowAlarmSeverity")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[6];
|
||||
if(names[6].compare("lowWarningSeverity")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[7];
|
||||
if(names[7].compare("highWarningSeverity")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[8];
|
||||
if(names[8].compare("highAlarmSeverity")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvInt) return false;
|
||||
f = fields[9];
|
||||
if(names[9].compare("hysteresis")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isAlarmLimit(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
Result& NTField::isControl(Result& result)
|
||||
{
|
||||
return result
|
||||
.has<Scalar>("limitLow")
|
||||
.has<Scalar>("limitHigh")
|
||||
.has<Scalar>("minStep");
|
||||
}
|
||||
|
||||
bool NTField::isControl(FieldConstPtr const & field)
|
||||
{
|
||||
if(field->getType()!=structure) return false;
|
||||
StructureConstPtr structurePtr = static_pointer_cast<const Structure>(field);
|
||||
FieldConstPtrArray fields = structurePtr->getFields();
|
||||
StringArray names = structurePtr->getFieldNames();
|
||||
size_t n = structurePtr->getNumberFields();
|
||||
if(n!=3) return false;
|
||||
FieldConstPtr f = fields[0];
|
||||
if(names[0].compare("limitLow")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
ScalarConstPtr s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[1];
|
||||
if(names[1].compare("limitHigh")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
f = fields[2];
|
||||
if(names[2].compare("minStep")!=0) return false;
|
||||
if(f->getType()!=scalar) return false;
|
||||
s = static_pointer_cast<const Scalar>(f);
|
||||
if(s->getScalarType()!=pvDouble) return false;
|
||||
return true;
|
||||
Result result(field);
|
||||
return isControl(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
StructureConstPtr NTField::createEnumerated()
|
||||
@@ -339,4 +239,3 @@ PVStructureArrayPtr PVNTField::createAlarmArray()
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/nthistogram.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -135,37 +137,19 @@ bool NTHistogram::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTHistogram::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if(!structure.get()) return false;
|
||||
|
||||
ScalarArrayConstPtr rangesField = structure->getField<ScalarArray>("ranges");
|
||||
if(!rangesField.get() || rangesField->getElementType() != pvDouble) return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if(!valueField.get()) return false;
|
||||
|
||||
ScalarType scalarType = valueField->getElementType();
|
||||
if (scalarType != pvShort &&
|
||||
scalarType != pvInt &&
|
||||
scalarType != pvLong)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if(field)
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("ranges")
|
||||
.has<ScalarArray>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTHistogram::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
12
src/ntid.cpp
12
src/ntid.cpp
@@ -7,11 +7,11 @@
|
||||
#include <pv/ntid.h>
|
||||
#include <pv/typeCast.h>
|
||||
|
||||
namespace epics {
|
||||
namespace epics {
|
||||
|
||||
namespace nt {
|
||||
|
||||
const static std::string BAD_NAME = "?";
|
||||
const static std::string BAD_NAME = "?";
|
||||
|
||||
NTID::NTID(const std::string & id)
|
||||
: fullName(id),
|
||||
@@ -81,7 +81,7 @@ namespace nt {
|
||||
else
|
||||
{
|
||||
name = fullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace nt {
|
||||
{
|
||||
endMajorIndex = fullName.find('.', versionSepIndex+1);
|
||||
majorVersionStr = (endMajorIndex != std::string::npos)
|
||||
? fullName.substr(versionSepIndex+1, endMajorIndex-(versionSepIndex+1)) :
|
||||
? fullName.substr(versionSepIndex+1, endMajorIndex-(versionSepIndex+1)) :
|
||||
fullName.substr(versionSepIndex+1);
|
||||
}
|
||||
else
|
||||
@@ -150,7 +150,7 @@ namespace nt {
|
||||
{
|
||||
endMinorIndex = fullName.find('.', endMajorIndex+1);
|
||||
minorVersionStr = (endMinorIndex != std::string::npos)
|
||||
? fullName.substr(endMajorIndex+1, endMinorIndex-(endMajorIndex+1)) :
|
||||
? fullName.substr(endMajorIndex+1, endMinorIndex-(endMajorIndex+1)) :
|
||||
fullName.substr(endMajorIndex+1);
|
||||
}
|
||||
else
|
||||
@@ -186,5 +186,3 @@ namespace nt {
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntmatrix.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -139,43 +141,20 @@ bool NTMatrix::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTMatrix::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if (valueField.get() == 0 || valueField->getElementType() != pvDouble)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("dim");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr dimField = structure->getField<ScalarArray>("dim");
|
||||
if (dimField.get() == 0 || dimField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("display");
|
||||
if (field.get() && !ntField->isDisplay(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("value")
|
||||
.maybeHas<ScalarArray>("dim")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.maybeHas<&NTField::isDisplay, Structure>("display")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTMatrix::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntmultiChannel.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -13,7 +15,7 @@
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace nt {
|
||||
namespace epics { namespace nt {
|
||||
|
||||
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
@@ -232,86 +234,27 @@ bool NTMultiChannel::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTMultiChannel::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (!structure.get()) return false;
|
||||
|
||||
UnionArrayConstPtr valueField = structure->getField<UnionArray>("value");
|
||||
if (!valueField.get()) return false;
|
||||
|
||||
ScalarArrayConstPtr channelNameField = structure->getField<ScalarArray>(
|
||||
"channelName");
|
||||
if (!channelNameField.get()) return false;
|
||||
if (channelNameField->getElementType() != pvString) return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("severity");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr severityField = structure->getField<ScalarArray>("severity");
|
||||
if (!severityField.get() || severityField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("status");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr statusField = structure->getField<ScalarArray>("status");
|
||||
if (!statusField.get() || statusField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("message");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr messageField = structure->getField<ScalarArray>("message");
|
||||
if (!messageField.get() || messageField->getElementType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("secondsPastEpoch");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr secondsPastEpochField = structure->getField<ScalarArray>("secondsPastEpoch");
|
||||
if (!secondsPastEpochField.get() || secondsPastEpochField->getElementType() != pvLong)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("nanoseconds");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr nanosecondsField = structure->getField<ScalarArray>("nanoseconds");
|
||||
if (!nanosecondsField.get() || nanosecondsField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("userTag");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr userTagField = structure->getField<ScalarArray>("userTag");
|
||||
if (!userTagField.get() || userTagField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<UnionArray>("value")
|
||||
.has<ScalarArray>("channelName")
|
||||
.maybeHas<ScalarArray>("severity")
|
||||
.maybeHas<ScalarArray>("status")
|
||||
.maybeHas<ScalarArray>("message")
|
||||
.maybeHas<ScalarArray>("secondsPastEpoch")
|
||||
.maybeHas<ScalarArray>("nanoseconds")
|
||||
.maybeHas<ScalarArray>("userTag")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTMultiChannel::isCompatible(PVStructurePtr const &pvStructure)
|
||||
{
|
||||
if(!pvStructure.get()) return false;
|
||||
@@ -326,7 +269,7 @@ bool NTMultiChannel::isValid()
|
||||
if (getChannelName()->getLength() != valueLength) return false;
|
||||
|
||||
PVScalarArrayPtr arrayFields[] = {
|
||||
getSeverity(), getStatus(), getMessage(),
|
||||
getSeverity(), getStatus(), getMessage(),
|
||||
getSecondsPastEpoch(), getNanoseconds(), getUserTag()
|
||||
};
|
||||
size_t N = sizeof(arrayFields)/sizeof(arrayFields[0]);
|
||||
@@ -338,7 +281,7 @@ bool NTMultiChannel::isValid()
|
||||
if (arrayField.get() && arrayField->getLength() != valueLength)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntnameValue.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -134,35 +136,19 @@ bool NTNameValue::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTNameValue::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarArrayConstPtr nameField = structure->getField<ScalarArray>("name");
|
||||
if (nameField.get() == 0 || nameField->getElementType() != pvString)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if (valueField.get() == 0)
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("name")
|
||||
.has<ScalarArray>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTNameValue::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntndarray.h>
|
||||
#include <pv/ntndarrayAttribute.h>
|
||||
@@ -16,9 +21,6 @@ using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace nt {
|
||||
|
||||
static NTFieldPtr ntField = NTField::get();
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
@@ -69,7 +71,7 @@ StructureConstPtr NTNDArrayBuilder::createStructure()
|
||||
ScalarType st = static_cast<ScalarType>(i);
|
||||
fb->addArray(std::string(ScalarTypeFunc::name(st)) + "Value", st);
|
||||
}
|
||||
valueType = fb->createUnion();
|
||||
valueType = fb->createUnion();
|
||||
}
|
||||
|
||||
if (!codecStruc)
|
||||
@@ -125,7 +127,7 @@ StructureConstPtr NTNDArrayBuilder::createStructure()
|
||||
returnedStruc = fb->createStructure();
|
||||
|
||||
if (!isExtended)
|
||||
ntndarrayStruc[index] = returnedStruc;
|
||||
ntndarrayStruc[index] = returnedStruc;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -190,95 +192,11 @@ NTNDArrayBuilder::shared_pointer NTNDArrayBuilder::add(string const & name, Fiel
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const std::string NTNDArray::URI("epics:nt/NTNDArray:1.0");
|
||||
const std::string ntAttrStr("epics:nt/NTAttribute:1.0");
|
||||
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
|
||||
class NTValueType
|
||||
{
|
||||
public:
|
||||
static bool isCompatible(UnionConstPtr const &u)
|
||||
{
|
||||
if(!u.get()) return false;
|
||||
|
||||
if (u->getID() != Union::defaultId()) return false;
|
||||
if (u->isVariant()) return false;
|
||||
|
||||
for (int i = pvBoolean; i != pvString; ++i)
|
||||
{
|
||||
ScalarType scalarType = static_cast<ScalarType>(i);
|
||||
std::string name(ScalarTypeFunc::name(scalarType));
|
||||
name += "Value";
|
||||
ScalarArrayConstPtr scalarField = u->getField<ScalarArray>(name);
|
||||
if (scalarField.get() == 0 ||
|
||||
scalarField->getElementType() != scalarType)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class NTCodec
|
||||
{
|
||||
public:
|
||||
static bool isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if(!structure.get()) return false;
|
||||
|
||||
if (structure->getID() != "codec_t") return false;
|
||||
|
||||
ScalarConstPtr scalarField = structure->getField<Scalar>("name");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvString)
|
||||
return false;
|
||||
|
||||
UnionConstPtr paramField = structure->getField<Union>("parameters");
|
||||
if (paramField.get() == 0 || !paramField->isVariant())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class NTDimension
|
||||
{
|
||||
public:
|
||||
static bool isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if(!structure.get()) return false;
|
||||
|
||||
if (structure->getID() != "dimension_t") return false;
|
||||
|
||||
ScalarConstPtr scalarField = structure->getField<Scalar>("size");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
scalarField = structure->getField<Scalar>("offset");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
scalarField = structure->getField<Scalar>("fullSize");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
scalarField = structure->getField<Scalar>("binning");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
scalarField = structure->getField<Scalar>("reverse");
|
||||
if (scalarField.get() == 0 || scalarField->getScalarType() != pvBoolean)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
NTNDArray::shared_pointer NTNDArray::wrap(PVStructurePtr const & pvStructure)
|
||||
{
|
||||
if(!isCompatible(pvStructure)) return shared_pointer();
|
||||
@@ -300,84 +218,62 @@ bool NTNDArray::is_a(PVStructurePtr const & pvStructure)
|
||||
return is_a(pvStructure->getStructure());
|
||||
}
|
||||
|
||||
bool NTNDArray::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if(!structure.get()) return false;
|
||||
|
||||
UnionConstPtr valueField = structure->getField<Union>("value");
|
||||
if(!NTValueType::isCompatible(valueField)) return false;
|
||||
|
||||
StructureConstPtr codecField = structure->getField<Structure>("codec");
|
||||
if(!NTCodec::isCompatible(codecField)) return false;
|
||||
|
||||
ScalarConstPtr compressedSizeField = structure->getField<Scalar>("compressedSize");
|
||||
if (compressedSizeField.get() == 0)
|
||||
return false;
|
||||
|
||||
if (compressedSizeField->getScalarType() != pvLong)
|
||||
return false;
|
||||
|
||||
|
||||
ScalarConstPtr uncompressedSizeField = structure->getField<Scalar>("uncompressedSize");
|
||||
if (uncompressedSizeField.get() == 0)
|
||||
return false;
|
||||
|
||||
if (uncompressedSizeField->getScalarType() != pvLong)
|
||||
return false;
|
||||
|
||||
StructureArrayConstPtr dimensionField = structure->getField<StructureArray>("dimension");
|
||||
if (dimensionField.get() == 0)
|
||||
return false;
|
||||
StructureConstPtr dimElementStruc = dimensionField->getStructure();
|
||||
|
||||
if(!NTDimension::isCompatible(dimElementStruc))
|
||||
return false;
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
StructureConstPtr dataTimeStampField = structure->getField<Structure>(
|
||||
"dataTimeStamp");
|
||||
if (dataTimeStampField.get() == 0 || !ntField->isTimeStamp(dataTimeStampField))
|
||||
return false;
|
||||
|
||||
|
||||
ScalarConstPtr uniqueIdField = structure->getField<Scalar>("uniqueId");
|
||||
if (uniqueIdField.get() == 0)
|
||||
return false;
|
||||
|
||||
if (uniqueIdField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
|
||||
StructureArrayConstPtr attributeField = structure->getField<StructureArray>( "attribute");
|
||||
|
||||
StructureConstPtr attributeElementStruc = attributeField->getStructure();
|
||||
|
||||
if (!NTNDArrayAttribute::isCompatible(attributeElementStruc))
|
||||
return false;
|
||||
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
namespace {
|
||||
Result& isValue(Result& result)
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
result.is<Union>(Union::defaultId());
|
||||
|
||||
for (int i = pvBoolean; i < pvString; ++i) {
|
||||
ScalarType type = static_cast<ScalarType>(i);
|
||||
string name(ScalarTypeFunc::name(type));
|
||||
result.has<ScalarArray>(name + "Value");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
Result& isCodec(Result& result)
|
||||
{
|
||||
return result
|
||||
.is<Structure>("codec_t")
|
||||
.has<Scalar>("name")
|
||||
.has<Union>("parameters");
|
||||
}
|
||||
|
||||
Result& isDimension(Result& result)
|
||||
{
|
||||
return result
|
||||
.is<StructureArray>("dimension_t[]")
|
||||
.has<Scalar>("size")
|
||||
.has<Scalar>("offset")
|
||||
.has<Scalar>("fullSize")
|
||||
.has<Scalar>("binning")
|
||||
.has<Scalar>("reverse");
|
||||
}
|
||||
}
|
||||
|
||||
bool NTNDArray::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
field = structure->getField("display");
|
||||
if (field.get() && !ntField->isDisplay(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<&isValue>("value")
|
||||
.has<&isCodec>("codec")
|
||||
.has<Scalar>("compressedSize")
|
||||
.has<Scalar>("uncompressedSize")
|
||||
.has<&isDimension>("dimension")
|
||||
.has<Scalar>("uniqueId")
|
||||
.has<&NTField::isTimeStamp, Structure>("dataTimeStamp")
|
||||
.has<&NTNDArrayAttribute::isAttribute, StructureArray>("attribute")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.maybeHas<&NTField::isDisplay, Structure>("display")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
@@ -388,7 +284,6 @@ bool NTNDArray::isCompatible(PVStructurePtr const & pvStructure)
|
||||
return isCompatible(pvStructure->getStructure());
|
||||
}
|
||||
|
||||
|
||||
bool NTNDArray::isValid()
|
||||
{
|
||||
int64 valueSize = getValueSize();
|
||||
@@ -432,10 +327,8 @@ int64 NTNDArray::getValueSize()
|
||||
{
|
||||
int64 size = 0;
|
||||
PVScalarArrayPtr storedValue = getValue()->get<PVScalarArray>();
|
||||
if (!storedValue.get())
|
||||
{
|
||||
if (storedValue.get())
|
||||
size = storedValue->getLength()*getValueTypeSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntndarrayAttribute.h>
|
||||
#include <pv/ntattribute.h>
|
||||
@@ -93,6 +95,7 @@ NTNDArrayAttributeBuilder::NTNDArrayAttributeBuilder()
|
||||
|
||||
void NTNDArrayAttributeBuilder::reset()
|
||||
{
|
||||
tags = false;
|
||||
descriptor = false;
|
||||
alarm = false;
|
||||
timeStamp = false;
|
||||
@@ -131,24 +134,25 @@ bool NTNDArrayAttribute::is_a(PVStructurePtr const & pvStructure)
|
||||
return is_a(pvStructure->getStructure());
|
||||
}
|
||||
|
||||
Result& NTNDArrayAttribute::isAttribute(Result& result) {
|
||||
return result
|
||||
.has<Scalar>("name")
|
||||
.has<Union>("value")
|
||||
.maybeHas<ScalarArray>("tags")
|
||||
.has<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.has<Scalar>("sourceType")
|
||||
.has<Scalar>("source");
|
||||
}
|
||||
|
||||
bool NTNDArrayAttribute::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (!NTAttribute::isCompatible(structure)) return false;
|
||||
|
||||
// descriptor required field for attibute in an ndarray
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (descriptorField.get() == 0 || descriptorField->getScalarType() != pvString)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
ScalarConstPtr sourcedTypeField = structure->getField<Scalar>("sourceType");
|
||||
if (sourcedTypeField.get() == 0 || sourcedTypeField->getScalarType() != pvInt)
|
||||
return false;
|
||||
|
||||
ScalarConstPtr sourcedField = structure->getField<Scalar>("source");
|
||||
if (sourcedField.get() == 0 || sourcedField->getScalarType() != pvString)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
Result result(structure);
|
||||
return isAttribute(result.is<Structure>()).valid();
|
||||
}
|
||||
|
||||
bool NTNDArrayAttribute::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntscalar.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -152,42 +154,22 @@ bool NTScalar::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTScalar::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarConstPtr valueField = structure->getField<Scalar>("value");
|
||||
if (valueField.get() == 0)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("display");
|
||||
if (field.get() && !ntField->isDisplay(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("control");
|
||||
if (field.get() && !ntField->isControl(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<Scalar>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.maybeHas<&NTField::isDisplay, Structure>("display")
|
||||
.maybeHas<&NTField::isControl, Structure>("control")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTScalar::isCompatible(PVStructurePtr const & pvStructure)
|
||||
{
|
||||
if(!pvStructure) return false;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntscalarArray.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -161,39 +163,20 @@ bool NTScalarArray::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTScalarArray::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if (valueField.get() == 0)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("display");
|
||||
if (field.get() && !ntField->isDisplay(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("control");
|
||||
if (field.get() && !ntField->isControl(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.maybeHas<&NTField::isDisplay, Structure>("display")
|
||||
.maybeHas<&NTField::isControl, Structure>("control")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTScalarArray::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntscalarMultiChannel.h>
|
||||
@@ -12,7 +13,7 @@
|
||||
using namespace std;
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics { namespace nt {
|
||||
namespace epics { namespace nt {
|
||||
|
||||
|
||||
static FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
@@ -228,86 +229,27 @@ bool NTScalarMultiChannel::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTScalarMultiChannel::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (!structure.get()) return false;
|
||||
|
||||
ScalarArrayConstPtr valueField = structure->getField<ScalarArray>("value");
|
||||
if (!valueField.get()) return false;
|
||||
|
||||
ScalarArrayConstPtr channelNameField = structure->getField<ScalarArray>(
|
||||
"channelName");
|
||||
if (!channelNameField.get()) return false;
|
||||
if (channelNameField->getElementType() != pvString) return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("severity");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr severityField = structure->getField<ScalarArray>("severity");
|
||||
if (!severityField.get() || severityField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("status");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr statusField = structure->getField<ScalarArray>("status");
|
||||
if (!statusField.get() || statusField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("message");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr messageField = structure->getField<ScalarArray>("message");
|
||||
if (!messageField.get() || messageField->getElementType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("secondsPastEpoch");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr secondsPastEpochField = structure->getField<ScalarArray>("secondsPastEpoch");
|
||||
if (!secondsPastEpochField.get() || secondsPastEpochField->getElementType() != pvLong)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("nanoseconds");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr nanosecondsField = structure->getField<ScalarArray>("nanoseconds");
|
||||
if (!nanosecondsField.get() || nanosecondsField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("userTag");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarArrayConstPtr userTagField = structure->getField<ScalarArray>("userTag");
|
||||
if (!userTagField.get() || userTagField->getElementType() != pvInt)
|
||||
return false;
|
||||
}
|
||||
|
||||
field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<ScalarArray>("value")
|
||||
.has<ScalarArray>("channelName")
|
||||
.maybeHas<ScalarArray>("severity")
|
||||
.maybeHas<ScalarArray>("status")
|
||||
.maybeHas<ScalarArray>("message")
|
||||
.maybeHas<ScalarArray>("secondsPastEpoch")
|
||||
.maybeHas<ScalarArray>("nanoseconds")
|
||||
.maybeHas<ScalarArray>("userTag")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
|
||||
bool NTScalarMultiChannel::isCompatible(PVStructurePtr const &pvStructure)
|
||||
{
|
||||
if(!pvStructure.get()) return false;
|
||||
@@ -321,7 +263,7 @@ bool NTScalarMultiChannel::isValid()
|
||||
if (getChannelName()->getLength() != valueLength) return false;
|
||||
|
||||
PVScalarArrayPtr arrayFields[] = {
|
||||
getSeverity(), getStatus(), getMessage(),
|
||||
getSeverity(), getStatus(), getMessage(),
|
||||
getSecondsPastEpoch(), getNanoseconds(), getUserTag()
|
||||
};
|
||||
size_t N = sizeof(arrayFields)/sizeof(arrayFields[0]);
|
||||
@@ -333,7 +275,7 @@ bool NTScalarMultiChannel::isValid()
|
||||
if (arrayField.get() && arrayField->getLength() != valueLength)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
NTScalarMultiChannelBuilderPtr NTScalarMultiChannel::createBuilder()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/nttable.h>
|
||||
@@ -149,42 +150,32 @@ bool NTTable::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTTable::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (!structure.get()) return false;
|
||||
|
||||
StructureConstPtr valueField = structure->getField<Structure>("value");
|
||||
if (!valueField.get())
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtrArray const & fields = valueField->getFields();
|
||||
for (FieldConstPtrArray::const_iterator it = fields.begin();
|
||||
it != fields.end(); ++it)
|
||||
{
|
||||
if ((*it)->getType() != scalarArray) return false;
|
||||
Result result(structure);
|
||||
|
||||
result
|
||||
.is<Structure>()
|
||||
.has<Structure>("value")
|
||||
.has<ScalarArray>("labels")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp");
|
||||
|
||||
StructureConstPtr value(structure->getField<Structure>("value"));
|
||||
if (value) {
|
||||
Result r(value);
|
||||
StringArray const & names(value->getFieldNames());
|
||||
StringArray::const_iterator it;
|
||||
|
||||
for (it = names.begin(); it != names.end(); ++it)
|
||||
r.has<ScalarArray>(*it);
|
||||
|
||||
result |= r;
|
||||
}
|
||||
|
||||
ScalarArrayConstPtr labelsField = structure->getField<ScalarArray>("labels");
|
||||
if (!labelsField.get() || labelsField->getElementType() != pvString)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result.valid();
|
||||
}
|
||||
|
||||
bool NTTable::isCompatible(PVStructurePtr const & pvStructure)
|
||||
@@ -197,7 +188,7 @@ bool NTTable::isCompatible(PVStructurePtr const & pvStructure)
|
||||
bool NTTable::isValid()
|
||||
{
|
||||
PVFieldPtrArray const & columns = pvValue->getPVFields();
|
||||
|
||||
|
||||
if (getLabels()->getLength() != columns.size()) return false;
|
||||
bool first = true;
|
||||
int length = 0;
|
||||
@@ -270,7 +261,7 @@ PVStringArrayPtr NTTable::getLabels() const
|
||||
|
||||
StringArray const & NTTable::getColumnNames() const
|
||||
{
|
||||
return pvNTTable->getStructure()->getFieldNames();
|
||||
return pvValue->getStructure()->getFieldNames();
|
||||
}
|
||||
|
||||
PVFieldPtr NTTable::getColumn(std::string const & columnName) const
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/ntunion.h>
|
||||
#include <pv/ntutils.h>
|
||||
@@ -128,31 +130,18 @@ bool NTUnion::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTUnion::isCompatible(StructureConstPtr const &structure)
|
||||
{
|
||||
if (structure.get() == 0) return false;
|
||||
|
||||
UnionConstPtr valueField = structure->getField<Union>("value");
|
||||
if (valueField.get() == 0)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
FieldConstPtr field = structure->getField("descriptor");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr descriptorField = structure->getField<Scalar>("descriptor");
|
||||
if (!descriptorField.get() || descriptorField->getScalarType() != pvString)
|
||||
return false;
|
||||
}
|
||||
Result result(structure);
|
||||
|
||||
NTFieldPtr ntField = NTField::get();
|
||||
|
||||
field = structure->getField("alarm");
|
||||
if (field.get() && !ntField->isAlarm(field))
|
||||
return false;
|
||||
|
||||
field = structure->getField("timeStamp");
|
||||
if (field.get() && !ntField->isTimeStamp(field))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result
|
||||
.is<Structure>()
|
||||
.has<Union>("value")
|
||||
.maybeHas<Scalar>("descriptor")
|
||||
.maybeHas<&NTField::isAlarm, Structure>("alarm")
|
||||
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
|
||||
.valid();
|
||||
}
|
||||
|
||||
bool NTUnion::isCompatible(PVStructurePtr const & pvStructure)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "validator.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/nturi.h>
|
||||
@@ -149,45 +150,31 @@ bool NTURI::is_a(PVStructurePtr const & pvStructure)
|
||||
|
||||
bool NTURI::isCompatible(StructureConstPtr const & structure)
|
||||
{
|
||||
if (!structure.get()) return false;
|
||||
|
||||
ScalarConstPtr schemeField = structure->getField<Scalar>("scheme");
|
||||
if (schemeField.get() == 0 || schemeField->getScalarType() != pvString)
|
||||
if (!structure)
|
||||
return false;
|
||||
|
||||
ScalarConstPtr pathField = structure->getField<Scalar>("path");
|
||||
if (pathField.get() == 0 || pathField->getScalarType() != pvString)
|
||||
return false;
|
||||
Result result(structure);
|
||||
|
||||
FieldConstPtr field = structure->getField("authority");
|
||||
if (field.get())
|
||||
{
|
||||
ScalarConstPtr authorityField = structure->getField<Scalar>("authority");
|
||||
if (!authorityField.get() || authorityField->getScalarType() != pvString)
|
||||
return false;
|
||||
result
|
||||
.is<Structure>()
|
||||
.has<Scalar>("scheme")
|
||||
.has<Scalar>("path")
|
||||
.maybeHas<Scalar>("authority")
|
||||
.maybeHas<Structure>("query");
|
||||
|
||||
StructureConstPtr query(structure->getField<Structure>("query"));
|
||||
if (query) {
|
||||
Result r(query);
|
||||
StringArray const & names(query->getFieldNames());
|
||||
StringArray::const_iterator it;
|
||||
|
||||
for (it = names.begin(); it != names.end(); ++it)
|
||||
r.has<ScalarArray>(*it);
|
||||
|
||||
result |= r;
|
||||
}
|
||||
|
||||
field = structure->getField("query");
|
||||
if (field.get())
|
||||
{
|
||||
StructureConstPtr queryField = structure->getField<Structure>("query");
|
||||
if (!queryField.get())
|
||||
return false;
|
||||
|
||||
FieldConstPtrArray const & fields = queryField->getFields();
|
||||
for (FieldConstPtrArray::const_iterator it = fields.begin();
|
||||
it != fields.end(); ++it)
|
||||
{
|
||||
if ((*it)->getType() != scalar) return false;
|
||||
ScalarType scalarType = std::tr1::dynamic_pointer_cast<const Scalar>(
|
||||
(*it))->getScalarType();
|
||||
if (scalarType != pvString &&
|
||||
scalarType != pvInt &&
|
||||
scalarType != pvDouble) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return result.valid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
/** @page Overview Documentation
|
||||
*
|
||||
* <a href = "ntCPP.html">ntCPP.html</a>
|
||||
* <a href = "../ntCPP.html">Normative Types (C++) Reference</a>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace detail {
|
||||
|
||||
void reset();
|
||||
|
||||
bool dim;
|
||||
bool descriptor;
|
||||
bool alarm;
|
||||
bool timeStamp;
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
namespace epics { namespace nt {
|
||||
|
||||
struct Result;
|
||||
|
||||
class NTField;
|
||||
typedef std::tr1::shared_ptr<NTField> NTFieldPtr;
|
||||
|
||||
@@ -149,6 +151,30 @@ private:
|
||||
NTField();
|
||||
epics::pvData::FieldCreatePtr fieldCreate;
|
||||
epics::pvData::StandardFieldPtr standardField;
|
||||
|
||||
// These won't be public just yet
|
||||
static Result& isEnumerated(Result&);
|
||||
static Result& isTimeStamp(Result&);
|
||||
static Result& isAlarm(Result&);
|
||||
static Result& isDisplay(Result&);
|
||||
static Result& isAlarmLimit(Result&);
|
||||
static Result& isControl(Result&);
|
||||
|
||||
friend class NTAggregate;
|
||||
friend class NTAttribute;
|
||||
friend class NTContinuum;
|
||||
friend class NTEnum;
|
||||
friend class NTHistogram;
|
||||
friend class NTMatrix;
|
||||
friend class NTMultiChannel;
|
||||
friend class NTNameValue;
|
||||
friend class NTNDArray;
|
||||
friend class NTNDArrayAttribute;
|
||||
friend class NTScalar;
|
||||
friend class NTScalarArray;
|
||||
friend class NTScalarMultiChannel;
|
||||
friend class NTTable;
|
||||
friend class NTUnion;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,12 +223,6 @@ public:
|
||||
*/
|
||||
epics::pvData::PVStructurePtr createDisplay();
|
||||
|
||||
/**
|
||||
* Creates an alarmLimit PVStructure.
|
||||
* @return an alarmLimit PVStructure.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr createAlarmLimit();
|
||||
|
||||
/**
|
||||
* Creates a control PVStructure.
|
||||
* @return a control PVStructure.
|
||||
|
||||
@@ -103,7 +103,6 @@ namespace detail {
|
||||
bool valueTypeSet;
|
||||
epics::pvData::ScalarType valueType;
|
||||
|
||||
bool dim;
|
||||
bool descriptor;
|
||||
bool alarm;
|
||||
bool timeStamp;
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
#include <string>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define ntscalarArrayEpicsExportSharedSymbols
|
||||
# define ntndarrayEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvDisplay.h>
|
||||
#include <pv/pvControl.h>
|
||||
|
||||
#ifdef ntscalarArrayEpicsExportSharedSymbols
|
||||
#ifdef ntndarrayEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef ntscalarArrayEpicsExportSharedSymbols
|
||||
# undef ntndarrayEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/ntfield.h>
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
* and if so returns an NTScalarArray which wraps it.
|
||||
* This method will return null if the structure is is not compatible
|
||||
* or is null.
|
||||
*
|
||||
*
|
||||
* @param pvStructure the PVStructure to be wrapped
|
||||
* @return NTScalarArray instance wrapping pvStructure on success, null otherwise
|
||||
*/
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
* <p>
|
||||
* No checks are made as to whether the specified PVStructure
|
||||
* is compatible with NTNDArray or is non-null.
|
||||
*
|
||||
*
|
||||
* @param pvStructure the PVStructure to be wrapped
|
||||
* @return NTNDArray instance wrapping pvStructure
|
||||
*/
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
* version of NTNDArray through its type ID, including checking version numbers.
|
||||
* The return value does not depend on whether the structure is actually
|
||||
* compatible in terms of its introspection type.
|
||||
*
|
||||
*
|
||||
* @param structure the pvStructure to test
|
||||
* @return (false,true) if the specified Structure (is not, is) a compatible NTNDArray
|
||||
*/
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
* version of NTNDArray through its type ID, including checking version numbers.
|
||||
* The return value does not depend on whether the structure is actually
|
||||
* compatible in terms of its introspection type.
|
||||
*
|
||||
*
|
||||
* @param pvStructure the PVStructure to test
|
||||
* @return (false,true) if the specified PVStructure (is not, is) a compatible NTNDArray
|
||||
*/
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
* <p>
|
||||
* Checks if the specified Structure is compatible with this version
|
||||
* of NTNDArray through the introspection interface.
|
||||
*
|
||||
*
|
||||
* @param structure the Structure to test
|
||||
* @return (false,true) if the specified Structure (is not, is) a compatible NTNDArray
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
namespace epics { namespace nt {
|
||||
|
||||
struct Result;
|
||||
class NTNDArrayAttribute;
|
||||
typedef std::tr1::shared_ptr<NTNDArrayAttribute> NTNDArrayAttributePtr;
|
||||
|
||||
@@ -302,10 +303,13 @@ public:
|
||||
|
||||
private:
|
||||
NTNDArrayAttribute(epics::pvData::PVStructurePtr const & pvStructure);
|
||||
static Result& isAttribute(Result& result);
|
||||
|
||||
epics::pvData::PVStructurePtr pvNTNDArrayAttribute;
|
||||
epics::pvData::PVUnionPtr pvValue;
|
||||
|
||||
friend class detail::NTNDArrayAttributeBuilder;
|
||||
friend class NTNDArray;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
277
src/validator.h
Normal file
277
src/validator.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/* validator.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
#ifndef VALIDATOR_H
|
||||
#define VALIDATOR_H
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
|
||||
namespace epics { namespace nt {
|
||||
|
||||
/**
|
||||
* @brief Validation methods for NT types.
|
||||
*
|
||||
* @author bsm
|
||||
*/
|
||||
|
||||
struct Result {
|
||||
struct Error {
|
||||
std::string path;
|
||||
enum Type {
|
||||
MissingField,
|
||||
IncorrectType,
|
||||
IncorrectId,
|
||||
} type;
|
||||
|
||||
Error(std::string const & path, Type type)
|
||||
: path(path), type(type) {}
|
||||
|
||||
bool operator==(const Error& other) const {
|
||||
return type == other.type && path == other.path;
|
||||
}
|
||||
|
||||
std::ostream& dump(std::ostream& os) const {
|
||||
os << "Error(path=" << (path.empty() ? "<root>" : path) << ": ";
|
||||
|
||||
switch(type) {
|
||||
case MissingField: os << "missing"; break;
|
||||
case IncorrectType: os << "incorrect type"; break;
|
||||
case IncorrectId: os << "incorrect ID"; break;
|
||||
}
|
||||
os << ")";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
epics::pvData::FieldConstPtr field;
|
||||
std::string path;
|
||||
std::vector<Error> errors;
|
||||
|
||||
enum result_t {
|
||||
Pass,
|
||||
Fail,
|
||||
} result;
|
||||
|
||||
Result(const epics::pvData::FieldConstPtr& field, const std::string& path = std::string())
|
||||
: field(field), path(path), errors(), result(Pass) {}
|
||||
|
||||
Result() {}
|
||||
|
||||
Result& operator|=(const Result& other) {
|
||||
result = std::max(result, other.result);
|
||||
errors.insert(errors.end(), other.errors.begin(), other.errors.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this Result is valid.
|
||||
*
|
||||
* @return true if all tests passed, false otherwise.
|
||||
*/
|
||||
inline bool valid(void) const {
|
||||
return result == Pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field is of a particular type 'T'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not of type 'T'.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<typename T>
|
||||
Result& is(void) {
|
||||
if (!dynamic_cast<T const *>(field.get())) {
|
||||
result = Fail;
|
||||
errors.push_back(Error(path, Error::IncorrectType));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field is of a particular type 'T' and has
|
||||
* an ID equal to 'id'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not of type 'T'.
|
||||
* Appends an Error::Type::IncorrectId if the field does not have an ID
|
||||
* equal to 'id'.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<typename T>
|
||||
Result& is(const std::string& id) {
|
||||
T const *s = dynamic_cast<T const *>(field.get());
|
||||
if (!s) {
|
||||
result = Fail;
|
||||
errors.push_back(Error(path, Error::IncorrectType));
|
||||
} else if (s->getID() != id) {
|
||||
result = Fail;
|
||||
errors.push_back(Error(path, Error::IncorrectId));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has a subfield with name 'name' and
|
||||
* apply the function 'fn' to the subfield.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
* Appends an Error::Type::MissingField if the subfield is not
|
||||
* present.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<Result& (*fn)(Result&)>
|
||||
Result& has(const std::string& name) {
|
||||
return has<epics::pvData::Field>(name, false, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has an optional subfield with name
|
||||
* 'name' and, if it has, apply the function 'fn' to the subfield.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<Result& (*fn)(Result&)>
|
||||
Result& maybeHas(const std::string& name) {
|
||||
return has<epics::pvData::Field>(name, true, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has a subfield with name 'name',
|
||||
* apply the function 'fn' to the subfield and
|
||||
* test that the subfield is of type 'T'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
* Appends an Error::Type::IncorrectType if the subfield is not of
|
||||
* type 'T'.
|
||||
* Appends an Error::Type::MissingField if the subfield is not
|
||||
* present.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<Result& (*fn)(Result&), typename T>
|
||||
Result& has(const std::string& name) {
|
||||
return has<T>(name, false, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has an optional subfield with name
|
||||
* 'name' and, if it has, apply the function 'fn' to the subfield and
|
||||
* test that the subfield is of type 'T'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
* Appends an Error::Type::IncorrectType if the subfield exists and
|
||||
* is not of type 'T'.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<Result& (*fn)(Result&), typename T>
|
||||
Result& maybeHas(const std::string& name) {
|
||||
return has<T>(name, true, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has a subfield with name 'name' and
|
||||
* test that the subfield is of type 'T'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
* Appends an Error::Type::IncorrectType if the subfield is not of
|
||||
* type 'T'.
|
||||
* Appends an Error::Type::MissingField if the subfield is not
|
||||
* present.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<typename T>
|
||||
Result& has(const std::string& name) {
|
||||
return has<T>(name, false, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that this Result's field has an optional subfield with name
|
||||
* 'name' and, if it has, test that the subfield is of type 'T'.
|
||||
*
|
||||
* Appends an Error::Type::IncorrectType if the field is not one of
|
||||
* Structure, StructureArray, Union, UnionArray.
|
||||
* Appends an Error::Type::IncorrectType if the subfield exists and
|
||||
* is not of type 'T'.
|
||||
*
|
||||
* @return itself
|
||||
*/
|
||||
template<typename T>
|
||||
Result& maybeHas(const std::string& name) {
|
||||
return has<T>(name, true, NULL);
|
||||
}
|
||||
|
||||
std::ostream& dump(std::ostream& os) const {
|
||||
os << "Result(valid=" << (result == Pass) << ", errors=[ ";
|
||||
|
||||
std::vector<Error>::const_iterator it;
|
||||
for (it = errors.begin(); it != errors.end(); ++it) {
|
||||
(*it).dump(os);
|
||||
os << " ";
|
||||
}
|
||||
os << "])";
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
Result& has(const std::string& name, bool optional, Result& (*check)(Result&) = NULL) {
|
||||
epics::pvData::FieldConstPtr subField;
|
||||
|
||||
switch(field->getType()) {
|
||||
case epics::pvData::structure:
|
||||
subField = static_cast<epics::pvData::Structure const *>(field.get())->getField(name);
|
||||
break;
|
||||
case epics::pvData::structureArray:
|
||||
subField = static_cast<epics::pvData::StructureArray const *>(field.get())->getStructure()->getField(name);
|
||||
break;
|
||||
case epics::pvData::union_:
|
||||
subField = static_cast<epics::pvData::Union const *>(field.get())->getField(name);
|
||||
break;
|
||||
case epics::pvData::unionArray:
|
||||
subField = static_cast<epics::pvData::UnionArray const *>(field.get())->getUnion()->getField(name);
|
||||
break;
|
||||
default:
|
||||
// Expected a structure-like Field
|
||||
result = Fail;
|
||||
errors.push_back(Error(path, Error::IncorrectType));
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string subFieldPath(path.empty() ? name : path + "." + name);
|
||||
|
||||
if (!subField) {
|
||||
if (!optional) {
|
||||
result = Fail;
|
||||
errors.push_back(Error(subFieldPath, Error::MissingField));
|
||||
}
|
||||
} else if (!dynamic_cast<T const *>(subField.get())) {
|
||||
result = Fail;
|
||||
errors.push_back(Error(subFieldPath, Error::IncorrectType));
|
||||
} else if (check) {
|
||||
Result r(subField, subFieldPath);
|
||||
*this |= check(r);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -72,6 +72,10 @@ TESTPROD_HOST += ntutilsTest
|
||||
ntutilsTest_SRCS = ntutilsTest.cpp
|
||||
TESTS += ntutilsTest
|
||||
|
||||
TESTPROD_HOST += validatorTest
|
||||
validatorTest_SRCS = validatorTest.cpp
|
||||
TESTS += validatorTest
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -78,7 +78,7 @@ void test_ntaggregate()
|
||||
// example how to set a value
|
||||
//
|
||||
ntAggregate->getValue()->put(1.0);
|
||||
|
||||
|
||||
//
|
||||
// example how to get a value
|
||||
//
|
||||
@@ -173,5 +173,3 @@ MAIN(testNTAggregate) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,5 +173,3 @@ MAIN(testNTAttribute) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -274,5 +274,3 @@ MAIN(testNTContinuum) {
|
||||
test_extra();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ void test_ntenum()
|
||||
choices[1] = "On";
|
||||
pvValue->getSubField<PVStringArray>("choices")->replace(freeze(choices));
|
||||
pvValue->getSubField<PVInt>("index")->put(1);
|
||||
|
||||
|
||||
//
|
||||
// example how to get a value
|
||||
//
|
||||
@@ -185,5 +185,3 @@ MAIN(testNTEnum) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -259,5 +259,3 @@ MAIN(testNTHistogram) {
|
||||
test_extra();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -151,7 +151,6 @@ void test_ntmatrix()
|
||||
display.setLow(-15);
|
||||
display.setHigh(15);
|
||||
display.setDescription("This is a test scalar array");
|
||||
display.setFormat("%d");
|
||||
display.setUnits("A");
|
||||
pvDisplay.set(display);
|
||||
}
|
||||
@@ -208,5 +207,3 @@ MAIN(testNTMatrix) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -193,4 +193,3 @@ MAIN(testCreateRequest)
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
@@ -254,5 +254,3 @@ MAIN(testNTNameValue) {
|
||||
test_extra();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -175,5 +175,3 @@ MAIN(testNTNDArrayAttribute) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ void test_builder(bool extraFields)
|
||||
testOk(builder.get() != 0, "Got builder");
|
||||
|
||||
builder->addDescriptor()->
|
||||
addTimeStamp()->
|
||||
addAlarm()->
|
||||
addTimeStamp()->
|
||||
addAlarm()->
|
||||
addDisplay();
|
||||
|
||||
if (extraFields)
|
||||
@@ -68,9 +68,9 @@ void test_all()
|
||||
|
||||
PVStructurePtr pvStructure = builder->
|
||||
addDescriptor()->
|
||||
addTimeStamp()->
|
||||
addAlarm()->
|
||||
addDisplay()->
|
||||
addTimeStamp()->
|
||||
addAlarm()->
|
||||
addDisplay()->
|
||||
add("extra1",fieldCreate->createScalar(pvString)) ->
|
||||
add("extra2",fieldCreate->createScalarArray(pvString)) ->
|
||||
createPVStructure();
|
||||
@@ -120,5 +120,3 @@ MAIN(testNTNDArray) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -167,7 +167,6 @@ void test_ntscalarArray()
|
||||
display.setLow(-15);
|
||||
display.setHigh(15);
|
||||
display.setDescription("This is a test scalar array");
|
||||
display.setFormat("%d");
|
||||
display.setUnits("A");
|
||||
pvDisplay.set(display);
|
||||
}
|
||||
@@ -243,5 +242,3 @@ MAIN(testNTScalarArray) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -180,4 +180,3 @@ MAIN(testCreateRequest)
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,6 @@ void test_ntscalar()
|
||||
display.setLow(-15);
|
||||
display.setHigh(15);
|
||||
display.setDescription("This is a test scalar");
|
||||
display.setFormat("%d");
|
||||
display.setUnits("A");
|
||||
pvDisplay.set(display);
|
||||
}
|
||||
@@ -234,5 +233,3 @@ MAIN(testNTScalar) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -245,5 +245,3 @@ MAIN(testNTTable) {
|
||||
test_wrap();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -196,5 +196,3 @@ MAIN(testNTUnion) {
|
||||
test_regular_union();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,5 +33,3 @@ MAIN(testNTUtils) {
|
||||
test_is_a();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
|
||||
|
||||
311
test/validatorTest.cpp
Normal file
311
test/validatorTest.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include "../src/validator.h"
|
||||
#include <pv/ntndarray.h>
|
||||
#include <pv/pvIntrospect.h>
|
||||
|
||||
using namespace epics::nt;
|
||||
using namespace epics::pvData;
|
||||
|
||||
static epics::pvData::FieldCreatePtr FC;
|
||||
|
||||
void test_is()
|
||||
{
|
||||
testDiag("test_is");
|
||||
|
||||
// Result::is<Scalar> must be valid for Scalars of any type
|
||||
for(int i = pvBoolean; i <= pvString; ++i) {
|
||||
ScalarType t = static_cast<ScalarType>(i);
|
||||
testOk(Result(FC->createScalar(t)).is<Scalar>().valid(),
|
||||
"Result(Scalar<%s>).is<Scalar>().valid()", ScalarTypeFunc::name(t));
|
||||
}
|
||||
|
||||
// Result::is<ScalarArray> must be valid for ScalarArray of any type
|
||||
for(int i = pvBoolean; i <= pvString; ++i) {
|
||||
ScalarType t = static_cast<ScalarType>(i);
|
||||
testOk(Result(FC->createScalarArray(t)).is<ScalarArray>().valid(),
|
||||
"Result(ScalarArray<%s>).is<ScalarArray>().valid()", ScalarTypeFunc::name(t));
|
||||
}
|
||||
|
||||
{
|
||||
// Result::is<Scalar> must be invalid for non-Scalar
|
||||
Result result(FC->createScalarArray(pvInt));
|
||||
result.is<Scalar>();
|
||||
testOk(!result.valid(), "!Result(ScalarArray<pvInt>).is<Scalar>.valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
|
||||
{
|
||||
// Result::is<ScalarArray> must be invalid for non-ScalarArray
|
||||
Result result(FC->createScalar(pvInt));
|
||||
result.is<ScalarArray>();
|
||||
testOk(!result.valid(), "!Result(ScalarArray<pvInt>).is<Scalar>.valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
}
|
||||
|
||||
void test_is_id()
|
||||
{
|
||||
testDiag("test_is_id");
|
||||
|
||||
FieldBuilderPtr FB(FieldBuilder::begin());
|
||||
|
||||
{
|
||||
// Both type and ID match for Structure
|
||||
Result result(FB->setId("TEST_ID")->createStructure());
|
||||
result.is<Structure>("TEST_ID");
|
||||
testOk(result.valid(), "Result(Structure['TEST_ID']).is<Structure>('TEST_ID').valid()");
|
||||
}
|
||||
|
||||
{
|
||||
// Both type and ID match for Union
|
||||
UnionConstPtr un(FB->
|
||||
setId("TEST_ID")->
|
||||
add("A", pvInt)->
|
||||
add("B", pvString)->
|
||||
createUnion()
|
||||
);
|
||||
Result result(un);
|
||||
result.is<Union>("TEST_ID");
|
||||
testOk(result.valid(), "Result(Union{A:int,B:string}['TEST_ID']).is<Union>('TEST_ID').valid()");
|
||||
}
|
||||
|
||||
{
|
||||
// Both type and ID match for Variant Union
|
||||
Result result(FB-> createUnion());
|
||||
result.is<Union>(Union::ANY_ID);
|
||||
testOk(result.valid(), "Result(Union).is<Union>('%s').valid()", Union::ANY_ID.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
// ID matches, type doesn't
|
||||
Result result(FB->setId("TEST_ID")->createStructure());
|
||||
result.is<Union>("TEST_ID");
|
||||
testOk(!result.valid(), "!Result(Union['TEST_ID']).is<Structure>('TEST_ID').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
|
||||
{
|
||||
// Type matches, ID doesn't
|
||||
Result result(FB->setId("WRONG_ID")->createStructure());
|
||||
result.is<Structure>("TEST_ID");
|
||||
testOk(!result.valid(), "!Result(Structure['WRONG_ID']).is<Structure>('TEST_ID').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectId));
|
||||
}
|
||||
|
||||
{
|
||||
// Neither type nor ID match (ID is not even checked in this case since it doesn't exist)
|
||||
Result result(FC->createScalar(pvDouble));
|
||||
result.is<Structure>("SOME_ID");
|
||||
testOk(!result.valid(), "!Result(Scalar).is<Structure>('SOME_ID').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
}
|
||||
|
||||
void test_has()
|
||||
{
|
||||
testDiag("test_has");
|
||||
|
||||
FieldBuilderPtr FB(FieldBuilder::begin());
|
||||
|
||||
StructureConstPtr struc(FB->
|
||||
add("A", pvInt)->
|
||||
add("B", pvString)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
std::string strucRepr("Structure{A:int,B:String}");
|
||||
|
||||
{
|
||||
// Test that struc has both A and B, both being Scalars
|
||||
Result result(struc);
|
||||
result
|
||||
.has<Scalar>("A")
|
||||
.has<Scalar>("B");
|
||||
|
||||
testOk(result.valid(),
|
||||
"Result(%s).has<Scalar>('A').has<Scalar>('B').valid()",
|
||||
strucRepr.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
// Test that struc does not have a field B of type ScalarArray
|
||||
Result result(struc);
|
||||
result
|
||||
.has<Scalar>("A")
|
||||
.has<ScalarArray>("B");
|
||||
testOk(!result.valid(),
|
||||
"!Result(%s).has<Scalar>('A').has<ScalarArray>('B').valid()",
|
||||
strucRepr.c_str());
|
||||
testOk1(result.errors.at(0) == Result::Error("B", Result::Error::IncorrectType));
|
||||
}
|
||||
|
||||
{
|
||||
// Test that struc does not have a field C
|
||||
Result result(struc);
|
||||
result
|
||||
.has<Scalar>("A")
|
||||
.has<Scalar>("C");
|
||||
testOk(!result.valid(),
|
||||
"!Result(%s).has<Scalar>('A').has<Scalar>('C').valid()",
|
||||
strucRepr.c_str());
|
||||
testOk1(result.errors.at(0) == Result::Error("C", Result::Error::MissingField));
|
||||
}
|
||||
|
||||
{
|
||||
// Test that 'has' fails for non-structure-like Fields
|
||||
Result result(FC->createScalar(pvByte));
|
||||
result.has<Scalar>("X");
|
||||
testOk(!result.valid(), "!Result(Scalar<pvByte>).has<Scalar>('X').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
}
|
||||
|
||||
void test_maybe_has()
|
||||
{
|
||||
testDiag("test_maybe_has");
|
||||
|
||||
FieldBuilderPtr FB(FieldBuilder::begin());
|
||||
|
||||
StructureConstPtr struc(FB->
|
||||
add("A", pvInt)->
|
||||
add("B", pvString)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
std::string strucRepr("Structure{A:int,B:String}");
|
||||
|
||||
{
|
||||
// Test that struc maybe has A and B, both being Scalars
|
||||
Result result(struc);
|
||||
result
|
||||
.maybeHas<Scalar>("A")
|
||||
.maybeHas<Scalar>("B");
|
||||
|
||||
testOk(result.valid(),
|
||||
"Result(%s).maybeHas<Scalar>('A').maybeHas<Scalar>('B').valid()",
|
||||
strucRepr.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
// Test that if struc has a field B, it must be of type ScalarArray
|
||||
Result result(struc);
|
||||
result
|
||||
.maybeHas<Scalar>("A")
|
||||
.maybeHas<ScalarArray>("B");
|
||||
testOk(!result.valid(),
|
||||
"!Result(%s).maybeHas<Scalar>('A').maybeHas<ScalarArray>('B').valid()",
|
||||
strucRepr.c_str());
|
||||
testOk1(result.errors.at(0) == Result::Error("B", Result::Error::IncorrectType));
|
||||
}
|
||||
|
||||
{
|
||||
// Test that struc maybe has A (which it does) and B (which it doesn't)
|
||||
Result result(struc);
|
||||
result
|
||||
.maybeHas<Scalar>("A")
|
||||
.maybeHas<Scalar>("C");
|
||||
testOk(result.valid(),
|
||||
"Result(%s).maybeHas<Scalar>('A').maybeHas<Scalar>('C').valid()",
|
||||
strucRepr.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
// Test that 'maybeHas' fails for non-structure-like Fields
|
||||
Result result(FC->createScalar(pvByte));
|
||||
result.maybeHas<Scalar>("X");
|
||||
testOk(!result.valid(), "!Result(Scalar<pvByte>).maybeHas<Scalar>('X').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("", Result::Error::IncorrectType));
|
||||
}
|
||||
}
|
||||
|
||||
Result& isStructABC(Result& result)
|
||||
{
|
||||
return result
|
||||
.is<Structure>("ABC")
|
||||
.has<Scalar>("A")
|
||||
.has<ScalarArray>("B")
|
||||
.maybeHas<Scalar>("C");
|
||||
}
|
||||
|
||||
void test_has_fn()
|
||||
{
|
||||
testDiag("test_has_fn");
|
||||
FieldBuilderPtr FB(FieldBuilder::begin());
|
||||
|
||||
{
|
||||
StructureConstPtr inner(FB->
|
||||
setId("ABC")->
|
||||
add("A", pvInt)->
|
||||
addArray("B", pvDouble)->
|
||||
add("C", pvString)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
Result result(FB->add("inner", inner)->createStructure());
|
||||
result.has<&isStructABC>("inner");
|
||||
|
||||
testOk(result.valid(), "Result({inner:<valid structABC>}).has<&isStructAbc>('inner').valid()");
|
||||
}
|
||||
|
||||
{
|
||||
StructureConstPtr inner(FB->
|
||||
setId("ABC")->
|
||||
add("A", pvInt)->
|
||||
addArray("B", pvDouble)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
Result result(FB->add("inner", inner)->createStructure());
|
||||
result.has<&isStructABC>("inner");
|
||||
|
||||
testOk(result.valid(), "Result({inner:<valid structABC w/o C>}).has<&isStructAbc>('inner').valid()");
|
||||
}
|
||||
|
||||
{
|
||||
StructureConstPtr inner(FB->
|
||||
setId("XYZ")->
|
||||
add("A", pvInt)->
|
||||
addArray("B", pvDouble)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
Result result(FB->add("inner", inner)->createStructure());
|
||||
result.has<&isStructABC>("inner");
|
||||
|
||||
testOk(!result.valid(), "!Result({inner:<structABC wrong id>}).has<&isStructAbc>('inner').valid()");
|
||||
testOk1(result.errors.at(0) == Result::Error("inner", Result::Error::IncorrectId));
|
||||
}
|
||||
|
||||
{
|
||||
StructureConstPtr inner(FB->
|
||||
setId("XYZ")->
|
||||
add("A", pvInt)->
|
||||
add("B", pvDouble)->
|
||||
createStructure()
|
||||
);
|
||||
|
||||
Result result(FB->add("inner", inner)->createStructure());
|
||||
result.has<&isStructABC>("inner");
|
||||
|
||||
testOk(!result.valid(), "!Result({inner:<structABC wrong id and fields>}).has<&isStructAbc>('inner').valid()");
|
||||
testOk1(result.errors.size() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
MAIN(testValidator) {
|
||||
testPlan(56);
|
||||
FC = epics::pvData::getFieldCreate();
|
||||
test_is();
|
||||
test_is_id();
|
||||
test_has();
|
||||
test_maybe_has();
|
||||
test_has_fn();
|
||||
return testDone();
|
||||
}
|
||||
Reference in New Issue
Block a user