Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e6c9f5ef | ||
|
|
073d2acafc | ||
|
|
8cf550ff57 | ||
|
|
c070a3485b | ||
|
|
b31d5079bf | ||
|
|
7c78b15a5c | ||
|
|
cd7d8735af | ||
|
|
94b48e4893 | ||
|
|
9d94e95521 | ||
|
|
e0d5925af3 | ||
|
|
f207e512d6 | ||
|
|
0a7d5b16aa | ||
|
|
aea8d9105e | ||
|
|
d18e0c913a |
93
.appveyor.yml
Normal file
93
.appveyor.yml
Normal file
@@ -0,0 +1,93 @@
|
||||
# .appveyor.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# This is YAML - indentation levels are crucial
|
||||
|
||||
cache:
|
||||
- C:\Users\appveyor\.tools
|
||||
|
||||
#---------------------------------#
|
||||
# repository cloning #
|
||||
#---------------------------------#
|
||||
|
||||
init:
|
||||
# Set autocrlf to make batch files work
|
||||
- git config --global core.autocrlf true
|
||||
|
||||
clone_depth: 5
|
||||
|
||||
# Build Configurations: dll/static, regular/debug
|
||||
configuration:
|
||||
- dynamic
|
||||
- static
|
||||
- dynamic-debug
|
||||
- static-debug
|
||||
|
||||
# Default OS Image
|
||||
image: Visual Studio 2019
|
||||
|
||||
# Environment variables: compiler toolchain, base version, setup file, ...
|
||||
environment:
|
||||
# common / default variables for all jobs
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
|
||||
matrix:
|
||||
- BASE: 3.15
|
||||
CMP: vs2019
|
||||
- BASE: 7.0
|
||||
CMP: vs2019
|
||||
- BASE: 7.0
|
||||
CMP: gcc
|
||||
- BASE: 7.0
|
||||
CMP: vs2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
|
||||
# Platform: processor architecture
|
||||
platform:
|
||||
- x64
|
||||
|
||||
#---------------------------------#
|
||||
# building & testing #
|
||||
#---------------------------------#
|
||||
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive
|
||||
- cmd: pip install git+https://github.com/mdavidsaver/ci-core-dumper#egg=ci-core-dumper
|
||||
- cmd: python .ci/cue.py prepare
|
||||
|
||||
build_script:
|
||||
- cmd: python .ci/cue.py build
|
||||
|
||||
test_script:
|
||||
- cmd: python -m ci_core_dumper install
|
||||
- cmd: python .ci/cue.py -T 20M test
|
||||
|
||||
on_finish:
|
||||
- ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
- cmd: python .ci/cue.py -T 5M test-results
|
||||
|
||||
on_failure:
|
||||
- cmd: python -m ci_core_dumper report
|
||||
|
||||
#---------------------------------#
|
||||
# debugging #
|
||||
#---------------------------------#
|
||||
|
||||
## if you want to connect by remote desktop to a failed build, uncomment these lines
|
||||
## note that you will need to connect within the usual build timeout limit (60 minutes)
|
||||
## so you may want to adjust the build matrix above to just build the one of interest
|
||||
|
||||
#on_failure:
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
#---------------------------------#
|
||||
# notifications #
|
||||
#---------------------------------#
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
to:
|
||||
- core-talk@aps.anl.gov
|
||||
on_build_success: false
|
||||
- provider: GitHubPullRequest
|
||||
1
.ci
Submodule
1
.ci
Submodule
Submodule .ci added at 130e88b709
14
.ci-local/defaults.set
Normal file
14
.ci-local/defaults.set
Normal file
@@ -0,0 +1,14 @@
|
||||
# EPICS Base
|
||||
BASE_DIRNAME=base
|
||||
BASE_REPONAME=epics-base
|
||||
BASE_REPOOWNER=epics-base
|
||||
BASE_VARNAME=EPICS_BASE
|
||||
BASE_RECURSIVE=NO
|
||||
|
||||
MODULES=PVDATA PVACCESS
|
||||
|
||||
PVDATA_REPONAME=pvDataCPP
|
||||
PVDATA_REPOOWNER=epics-base
|
||||
|
||||
PVACCESS_REPONAME=pvAccessCPP
|
||||
PVACCESS_REPOOWNER=epics-base
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e -x
|
||||
|
||||
make -j2 $EXTRA
|
||||
|
||||
if [ "$TEST" != "NO" ]
|
||||
then
|
||||
make -j2 tapfiles
|
||||
make -j2 -s test-results
|
||||
fi
|
||||
@@ -1,109 +0,0 @@
|
||||
#!/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}
|
||||
add_gh_flat pvAccess ${REPOPVA:-epics-base} pvAccessCPP ${BRPVA:-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
|
||||
make -j2 -C pvAccess $EXTRA
|
||||
172
.github/workflows/ci-scripts-build.yml
vendored
Normal file
172
.github/workflows/ci-scripts-build.yml
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
|
||||
# (see: https://github.com/epics-base/ci-scripts)
|
||||
|
||||
# This is YAML - indentation levels are crucial
|
||||
|
||||
# Workflow name
|
||||
|
||||
name: Base
|
||||
|
||||
# Trigger on pushes and PRs to any branch
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'documentation/*'
|
||||
- '.appveyor.yml'
|
||||
- '.readthedocs.yml'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'documentation/*'
|
||||
- '.appveyor.yml'
|
||||
- '.readthedocs.yml'
|
||||
|
||||
env:
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
EPICS_TEST_IMPRECISE_TIMING: YES
|
||||
|
||||
jobs:
|
||||
build-base:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
# Set environment variables from matrix parameters
|
||||
env:
|
||||
BASE: ${{ matrix.base }}
|
||||
CMP: ${{ matrix.cmp }}
|
||||
BCFG: ${{ matrix.configuration }}
|
||||
CI_CROSS_TARGETS: ${{ matrix.cross }}
|
||||
EXTRA: ${{ matrix.extra }}
|
||||
TEST: ${{ matrix.test }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Job names also name artifacts, character limitations apply
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
cross: "windows-x64-mingw"
|
||||
name: "7.0 Ub-22 gcc + MinGW"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
base: "7.0"
|
||||
cross: "windows-x64-mingw"
|
||||
name: "7.0 Ub-22 gcc + MinGW, static"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
base: "7.0"
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "7.0 Ub-22 gcc C++11, static"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: static
|
||||
base: "7.0"
|
||||
extra: "CMD_CFLAGS=-funsigned-char CMD_CXXFLAGS=-funsigned-char"
|
||||
name: "7.0 Ub-22 gcc uchar"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
name: "7.0 Ub-22 clang"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: clang
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
extra: "CMD_CXXFLAGS=-std=c++11"
|
||||
name: "7.0 Ub-22 clang C++11"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
cross: "RTEMS-pc686-qemu@5"
|
||||
name: "7.0 Ub-22 gcc + RT-5.1 pc686"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
cross: "RTEMS-pc386-qemu@4.10"
|
||||
test: NO
|
||||
name: "7.0 Ub-22 gcc + RT-4.10"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
cross: "RTEMS-pc386-qemu@4.9"
|
||||
name: "7.0 Ub-22 gcc + RT-4.9"
|
||||
|
||||
- os: macos-latest
|
||||
cmp: clang
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
name: "7.0 MacOS clang"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
name: "7.0 Win2019 MSC-19"
|
||||
extra: "CMD_CXXFLAGS=-analysis"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: static
|
||||
base: "7.0"
|
||||
name: "7.0 Win2019 MSC-19, static"
|
||||
extra: "CMD_CXXFLAGS=-analysis"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: vs2019
|
||||
configuration: debug
|
||||
base: "7.0"
|
||||
name: "7.0 Win2019 MSC-19, debug"
|
||||
|
||||
- os: windows-2019
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "7.0"
|
||||
name: "7.0 Win2019 mingw"
|
||||
|
||||
- os: ubuntu-22.04
|
||||
cmp: gcc
|
||||
configuration: default
|
||||
base: "3.15"
|
||||
wine: "64"
|
||||
name: "3.15 Ub-22 gcc + MinGW"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Automatic core dump analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
- name: "apt-get install"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install qemu-system-x86 g++-mingw-w64-x86-64 gdb
|
||||
if: runner.os == 'Linux'
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
run: python .ci/cue.py build
|
||||
- name: Run main module tests
|
||||
run: python .ci/cue.py -T 20M test
|
||||
- name: Upload tapfiles Artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tapfiles ${{ matrix.name }}
|
||||
path: '**/O.*/*.tap'
|
||||
if-no-files-found: ignore
|
||||
- name: Collect and show test results
|
||||
if: ${{ always() }}
|
||||
run: python .ci/cue.py -T 5M test-results
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule ".ci"]
|
||||
path = .ci
|
||||
url = https://github.com/epics-base/ci-scripts
|
||||
31
.travis.yml
31
.travis.yml
@@ -1,31 +0,0 @@
|
||||
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
|
||||
|
||||
2
Doxyfile
2
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = pvDatabaseCPP
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 4.7.1
|
||||
PROJECT_NUMBER = 4.7.3-dev
|
||||
|
||||
# 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
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
EPICS_PVDATABASE_MAJOR_VERSION = 4
|
||||
EPICS_PVDATABASE_MINOR_VERSION = 7
|
||||
EPICS_PVDATABASE_MAINTENANCE_VERSION = 1
|
||||
EPICS_PVDATABASE_MAINTENANCE_VERSION = 3
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
EPICS_PVDATABASE_DEVELOPMENT_FLAG = 0
|
||||
EPICS_PVDATABASE_DEVELOPMENT_FLAG = 1
|
||||
|
||||
# Immediately after a release the MAINTENANCE_VERSION
|
||||
# will be incremented and the DEVELOPMENT_FLAG set to 1
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
This document summarizes the changes to the module between releases.
|
||||
|
||||
## Release 4.7.2 (EPICS 7.0.9, Feb 2025)
|
||||
|
||||
* Resolved issue with changed field set in the case where the top level (master)
|
||||
field ("_") is not requested by the client, but the master field callback causes
|
||||
all fields to be marked as updated, rather than only those fields that have
|
||||
actually been modified.
|
||||
|
||||
## Release 4.7.1 (EPICS 7.0.8, Dec 2023)
|
||||
|
||||
* Added data distributor plugin which can be used for distributing data between
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
# pvDatabase C++ implementation
|
||||
# Jenkins @ Cloudbees build script
|
||||
#
|
||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
||||
# if any of the commands exits with a non-zero exit code.
|
||||
#
|
||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
||||
# Copyright (C) 2014-2016 ITER Organization.
|
||||
# All rights reserved. Use is subject to license terms.
|
||||
|
||||
installTool () {
|
||||
local module=$1
|
||||
local version=$2
|
||||
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
|
||||
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
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
|
||||
|
||||
DEFAULT_BASE=3.15.4
|
||||
BASE=${BASE:-${DEFAULT_BASE}}
|
||||
|
||||
###########################################
|
||||
# Dependent module branches
|
||||
|
||||
PVDATA_BRANCH="master"
|
||||
PVACCESS_BRANCH="master"
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
export STUFF=/tmp/stuff
|
||||
|
||||
rm -fr ${STUFF}
|
||||
mkdir -p ${STUFF}
|
||||
cd ${STUFF}
|
||||
|
||||
installTool Boost 1.61.0
|
||||
installTool Base ${BASE}
|
||||
|
||||
installE4 pvData ${PVDATA_BRANCH}
|
||||
installE4 pvAccess ${PVACCESS_BRANCH}
|
||||
|
||||
###########################################
|
||||
# Build
|
||||
|
||||
cd ${WORKSPACE}
|
||||
|
||||
export EPICS_BASE=${STUFF}
|
||||
export EPICS_HOST_ARCH=$(${EPICS_BASE}/startup/EpicsHostArch)
|
||||
export LD_LIBRARY_PATH=${EPICS_BASE}/lib/${EPICS_HOST_ARCH}
|
||||
export PATH=${STUFF}/bin:${PATH}
|
||||
|
||||
cat > configure/RELEASE.local << EOF
|
||||
EPICS_BASE=${EPICS_BASE}
|
||||
EOF
|
||||
|
||||
make distclean all
|
||||
|
||||
###########################################
|
||||
# Test
|
||||
|
||||
make runtests
|
||||
|
||||
###########################################
|
||||
# Create cache
|
||||
|
||||
tar -czf pvDatabase.CB-dist.tar.gz lib include dbd LICENSE
|
||||
@@ -1,66 +0,0 @@
|
||||
# pvDatabase C++ implementation
|
||||
# Jenkins @ Cloudbees documentation generation and deployment
|
||||
#
|
||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
||||
# if any of the commands exits with a non-zero exit code.
|
||||
#
|
||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
||||
# Copyright (C) 2014-2016 ITER Organization.
|
||||
# All rights reserved. Use is subject to license terms.
|
||||
|
||||
installTool () {
|
||||
local module=$1
|
||||
local version=$2
|
||||
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/${module}-${version}_Build/lastSuccessfulBuild/artifact/${module,,}-${version}.CB-dist.tar.gz
|
||||
tar -xzf ${module,,}-${version}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
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 parameters
|
||||
|
||||
BASE=3.15.4
|
||||
PUBLISH=${PUBLISH:-NO}
|
||||
BRANCH=${BRANCH:-master}
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
export STUFF=/tmp/stuff
|
||||
|
||||
rm -fr ${STUFF}
|
||||
mkdir -p ${STUFF}
|
||||
cd ${STUFF}
|
||||
|
||||
installTool Doxygen 1.8.11
|
||||
|
||||
###########################################
|
||||
# Generate
|
||||
|
||||
cd ${WORKSPACE}
|
||||
|
||||
installE4 pvDatabase ${BRANCH}
|
||||
|
||||
export PATH=${STUFF}/bin:${PATH}
|
||||
|
||||
doxygen
|
||||
|
||||
###########################################
|
||||
# Publish
|
||||
|
||||
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/pvDatabaseCPP/${PUBLISH}/
|
||||
|
||||
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/${PUBLISH}/
|
||||
fi
|
||||
@@ -432,6 +432,7 @@ bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||
PVStructurePtr pvMasterStructure = pvMaster;
|
||||
size_t len = pvRequest->getPVFields().size();
|
||||
bool entireMaster = false;
|
||||
requestHasMasterField = false;
|
||||
PVStructurePtr pvOptions;
|
||||
if(len==0) {
|
||||
entireMaster = true;
|
||||
@@ -441,6 +442,9 @@ bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||
// then assume the top level PV structure is requested
|
||||
PVStructurePtr masterFieldPtr = pvMaster->getSubField<PVStructure>("_");
|
||||
PVStructurePtr requestFieldPtr = pvRequest->getSubField<PVStructure>("_");
|
||||
if (requestFieldPtr) {
|
||||
requestHasMasterField = true;
|
||||
}
|
||||
if (!masterFieldPtr && requestFieldPtr) {
|
||||
entireMaster = true;
|
||||
pvOptions = requestFieldPtr->getSubField<PVStructure>("_options");
|
||||
|
||||
@@ -481,27 +481,30 @@ void PVRecordStructure::init()
|
||||
for(size_t i=0; i<numFields; i++) {
|
||||
PVFieldPtr pvField = pvFields[i];
|
||||
if(pvField->getField()->getType()==structure) {
|
||||
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
|
||||
PVRecordStructurePtr pvRecordStructure(
|
||||
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
|
||||
PVRecordStructurePtr pvRecordStructure(
|
||||
new PVRecordStructure(xxx,self,pvRecord));
|
||||
pvRecordFields->push_back(pvRecordStructure);
|
||||
pvRecordStructure->init();
|
||||
pvRecordFields->push_back(pvRecordStructure);
|
||||
pvRecordStructure->init();
|
||||
} else {
|
||||
PVRecordFieldPtr pvRecordField(
|
||||
PVRecordFieldPtr pvRecordField(
|
||||
new PVRecordField(pvField,self,pvRecord));
|
||||
pvRecordFields->push_back(pvRecordField);
|
||||
pvRecordField->init();
|
||||
// Master field listeners will be called before
|
||||
// calling listeners for the first subfield
|
||||
if (!masterFieldCallbackSet) {
|
||||
masterFieldCallbackSet = true;
|
||||
// Find master field
|
||||
PVRecordStructurePtr p = pvRecordField->parent.lock();
|
||||
while (p) {
|
||||
pvRecordField->master = p;
|
||||
p = p->parent.lock();
|
||||
}
|
||||
}
|
||||
pvRecordFields->push_back(pvRecordField);
|
||||
pvRecordField->init();
|
||||
// Master field listeners will be called before
|
||||
// calling listeners for the first subfield
|
||||
if (!masterFieldCallbackSet) {
|
||||
masterFieldCallbackSet = true;
|
||||
// Find master field
|
||||
PVRecordStructurePtr p = pvRecordField->parent.lock();
|
||||
while (p) {
|
||||
PVRecordStructurePtr p2 = p->parent.lock();
|
||||
if (!p2) {
|
||||
pvRecordField->master = p;
|
||||
}
|
||||
p = p2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,10 @@ public:
|
||||
* name is the subField name and value is the subField value.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getOptions(std::size_t fieldOffset);
|
||||
/**
|
||||
* Is master field requested?
|
||||
*/
|
||||
bool isMasterFieldRequested() const {return requestHasMasterField;}
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
@@ -183,6 +187,7 @@ private:
|
||||
CopyNodePtr headNode;
|
||||
epics::pvData::PVStructurePtr cacheInitStructure;
|
||||
epics::pvData::BitSetPtr ignorechangeBitSet;
|
||||
bool requestHasMasterField;
|
||||
|
||||
void traverseMaster(
|
||||
CopyNodePtr const &node,
|
||||
|
||||
@@ -292,6 +292,12 @@ void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
cout << "MonitorLocal::dataPut(pvRecordField)" << endl;
|
||||
}
|
||||
// If this record field is the master field, and the master field was not
|
||||
// requested, we do not proceed with copy
|
||||
bool isMasterField = pvRecordField->getPVRecord()->getPVStructure()->getFieldOffset()==0;
|
||||
if (isMasterField && !pvCopy->isMasterFieldRequested()) {
|
||||
return;
|
||||
}
|
||||
if(state!=active) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
|
||||
@@ -33,3 +33,8 @@ TESTPROD_HOST += testPVAServer
|
||||
testPVAServer_SRCS += testPVAServer.cpp
|
||||
testHarness_SRCS += testPVAServer.cpp
|
||||
TESTS += testPVAServer
|
||||
|
||||
TESTPROD_HOST += testChannelMonitor
|
||||
testChannelMonitor_SRCS += testChannelMonitor.cpp
|
||||
testHarness_SRCS += testChannelMonitor.cpp
|
||||
TESTS += testChannelMonitor
|
||||
|
||||
312
test/src/testChannelMonitor.cpp
Normal file
312
test/src/testChannelMonitor.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
/* testChannelMonitor.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/event.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
namespace TR1 = std::tr1;
|
||||
|
||||
static bool debug = true;
|
||||
|
||||
PVStructurePtr createTestPvStructure()
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
StandardFieldPtr standardField = getStandardField()
|
||||
;
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
|
||||
return pvDataCreate->createPVStructure(
|
||||
fieldCreate->createFieldBuilder()->
|
||||
add("id",pvInt) ->
|
||||
add("x",pvInt) ->
|
||||
add("y",pvInt) ->
|
||||
add("z",pvInt) ->
|
||||
add("alarm",standardField->alarm()) ->
|
||||
add("timeStamp",standardField->timeStamp()) ->
|
||||
createStructure());
|
||||
}
|
||||
|
||||
class ChannelMonitorRequesterImpl : public MonitorRequester
|
||||
{
|
||||
public:
|
||||
|
||||
ChannelMonitorRequesterImpl(const std::string& channelName_)
|
||||
: channelName(channelName_)
|
||||
, lastReceivedPvStructure(createTestPvStructure())
|
||||
, lastReceivedBitSet()
|
||||
{
|
||||
}
|
||||
|
||||
virtual string getRequesterName()
|
||||
{
|
||||
return "ChannelMonitorRequesterImpl";
|
||||
}
|
||||
|
||||
virtual void message(const std::string& message, MessageType messageType)
|
||||
{
|
||||
cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << endl;
|
||||
}
|
||||
|
||||
virtual void monitorConnect(const epics::pvData::Status& status, const Monitor::shared_pointer& /*monitor*/, const Structure::const_shared_pointer& /*structure*/)
|
||||
{
|
||||
if (status.isSuccess()) {
|
||||
// show warning
|
||||
if (!status.isOK()) {
|
||||
cout << "[" << channelName << "] channel monitor create: " << status << endl;
|
||||
}
|
||||
connectionEvent.signal();
|
||||
}
|
||||
else {
|
||||
cout << "[" << channelName << "] failed to create channel monitor: " << status << endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void monitorEvent(const Monitor::shared_pointer& monitor)
|
||||
{
|
||||
MonitorElement::shared_pointer element;
|
||||
while ((element = monitor->poll())) {
|
||||
cout << "changed/overrun " << *element->changedBitSet << '/' << *element->overrunBitSet << endl;
|
||||
if (!lastReceivedBitSet) {
|
||||
lastReceivedBitSet = BitSet::create(element->changedBitSet->size());
|
||||
}
|
||||
lastReceivedBitSet->clear();
|
||||
*lastReceivedBitSet |= *element->changedBitSet;
|
||||
lastReceivedPvStructure->copyUnchecked(*element->pvStructurePtr);
|
||||
monitor->release(element);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void unlisten(const Monitor::shared_pointer& /*monitor*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool waitUntilConnected(double timeOut)
|
||||
{
|
||||
return connectionEvent.wait(timeOut);
|
||||
}
|
||||
|
||||
PVStructurePtr getLastReceivedPvStructure()
|
||||
{
|
||||
return lastReceivedPvStructure;
|
||||
}
|
||||
|
||||
BitSetPtr getLastReceivedBitSet()
|
||||
{
|
||||
return lastReceivedBitSet;
|
||||
}
|
||||
|
||||
private:
|
||||
Event event;
|
||||
Event connectionEvent;
|
||||
string channelName;
|
||||
PVStructurePtr lastReceivedPvStructure;
|
||||
BitSetPtr lastReceivedBitSet;
|
||||
};
|
||||
|
||||
class ChannelRequesterImpl : public ChannelRequester
|
||||
{
|
||||
private:
|
||||
Event event;
|
||||
|
||||
public:
|
||||
|
||||
virtual string getRequesterName()
|
||||
{
|
||||
return "ChannelRequesterImpl";
|
||||
};
|
||||
|
||||
virtual void message(const std::string& message, MessageType messageType)
|
||||
{
|
||||
cout << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << endl;
|
||||
}
|
||||
|
||||
virtual void channelCreated(const Status& status, const Channel::shared_pointer& channel)
|
||||
{
|
||||
if (status.isSuccess()) {
|
||||
// show warning
|
||||
if (!status.isOK()) {
|
||||
cout << "[" << channel->getChannelName() << "] channel create: " << status << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout << "[" << channel->getChannelName() << "] failed to create a channel: " << status << endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void channelStateChange(const Channel::shared_pointer& /*channel*/, Channel::ConnectionState connectionState)
|
||||
{
|
||||
if (connectionState == Channel::CONNECTED) {
|
||||
event.signal();
|
||||
}
|
||||
else {
|
||||
cout << Channel::ConnectionStateNames[connectionState] << endl;
|
||||
exit(3);
|
||||
}
|
||||
}
|
||||
|
||||
bool waitUntilConnected(double timeOut)
|
||||
{
|
||||
return event.wait(timeOut);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void test()
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
string recordName = "positions";
|
||||
PVStructurePtr pvStructure = createTestPvStructure();
|
||||
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
master->addRecord(pvRecord);
|
||||
pvRecord = master->findRecord(recordName);
|
||||
{
|
||||
pvRecord->lock();
|
||||
pvRecord->process();
|
||||
pvRecord->unlock();
|
||||
}
|
||||
if(debug) {cout << "processed positions" << endl; }
|
||||
ServerContext::shared_pointer ctx = startPVAServer("local",0,true,true);
|
||||
testOk1(ctx.get() != 0);
|
||||
|
||||
ClientFactory::start();
|
||||
ChannelProvider::shared_pointer provider = ChannelProviderRegistry::clients()->getProvider("pva");
|
||||
|
||||
cout << "creating channel: " << recordName << endl;
|
||||
TR1::shared_ptr<ChannelRequesterImpl> channelRequesterImpl(new ChannelRequesterImpl());
|
||||
|
||||
Channel::shared_pointer channel = provider->createChannel(recordName, channelRequesterImpl);
|
||||
bool channelConnected = channelRequesterImpl->waitUntilConnected(1.0);
|
||||
testOk1(channelConnected);
|
||||
if (channelConnected) {
|
||||
string remoteAddress = channel->getRemoteAddress();
|
||||
cout << "remote address: " << remoteAddress << endl;
|
||||
}
|
||||
|
||||
string request = "";
|
||||
PVStructure::shared_pointer pvRequest = CreateRequest::create()->createRequest(request);
|
||||
TR1::shared_ptr<ChannelMonitorRequesterImpl> cmRequesterImpl(new ChannelMonitorRequesterImpl(channel->getChannelName()));
|
||||
Monitor::shared_pointer monitor = channel->createMonitor(cmRequesterImpl, pvRequest);
|
||||
bool monitorConnected = cmRequesterImpl->waitUntilConnected(1.0);
|
||||
testOk1(monitorConnected);
|
||||
Status status = monitor->start();
|
||||
testOk1(status.isOK());
|
||||
epicsThreadSleep(1);
|
||||
|
||||
// Set id, x
|
||||
{
|
||||
pvRecord->beginGroupPut();
|
||||
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||
id->put(1);
|
||||
PVIntPtr x = pvStructure->getSubField<PVInt>("x");
|
||||
x->put(1);
|
||||
pvRecord->endGroupPut();
|
||||
}
|
||||
epicsThreadSleep(1);
|
||||
|
||||
// Changed set for (id,x): 0 unset, 1 set, 2 set, 3 unset, 4 unset
|
||||
BitSetPtr changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||
testOk1(!changedSet->get(0) && changedSet->get(1) && changedSet->get(2) && !changedSet->get(3) && !changedSet->get(4));
|
||||
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||
|
||||
// Set id, y
|
||||
{
|
||||
pvRecord->beginGroupPut();
|
||||
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||
id->put(2);
|
||||
PVIntPtr y = pvStructure->getSubField<PVInt>("y");
|
||||
y->put(2);
|
||||
pvRecord->endGroupPut();
|
||||
}
|
||||
epicsThreadSleep(1);
|
||||
|
||||
// Changed set for (id,y): 0 unset, 1 set, 2 unset, 3 set, 4 unset
|
||||
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||
testOk1(!changedSet->get(0) && changedSet->get(1) && !changedSet->get(2) && changedSet->get(3) && !changedSet->get(4));
|
||||
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||
|
||||
// Set id, z
|
||||
{
|
||||
pvRecord->beginGroupPut();
|
||||
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||
id->put(3);
|
||||
PVIntPtr z = pvStructure->getSubField<PVInt>("z");
|
||||
z->put(3);
|
||||
pvRecord->endGroupPut();
|
||||
}
|
||||
epicsThreadSleep(1);
|
||||
|
||||
// Changed set for (id,z): 0 unset, 1 set, 2 unset, 3 unset, 4 set
|
||||
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||
testOk1(!changedSet->get(0) && changedSet->get(1) && !changedSet->get(2) && !changedSet->get(3) && changedSet->get(4));
|
||||
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||
|
||||
status = monitor->stop();
|
||||
testOk1(status.isOK());
|
||||
|
||||
// Test master field
|
||||
request = "field(_)";
|
||||
pvRequest = CreateRequest::create()->createRequest(request);
|
||||
cmRequesterImpl = TR1::shared_ptr<ChannelMonitorRequesterImpl>(new ChannelMonitorRequesterImpl(channel->getChannelName()));
|
||||
monitor = channel->createMonitor(cmRequesterImpl, pvRequest);
|
||||
monitorConnected = cmRequesterImpl->waitUntilConnected(1.0);
|
||||
testOk1(monitorConnected);
|
||||
status = monitor->start();
|
||||
testOk1(status.isOK());
|
||||
epicsThreadSleep(1);
|
||||
{
|
||||
pvRecord->beginGroupPut();
|
||||
PVIntPtr id = pvStructure->getSubField<PVInt>("id");
|
||||
id->put(4);
|
||||
PVIntPtr x = pvStructure->getSubField<PVInt>("x");
|
||||
x->put(4);
|
||||
pvRecord->endGroupPut();
|
||||
}
|
||||
epicsThreadSleep(1);
|
||||
// Changed set with master field requested: 0 set
|
||||
changedSet = cmRequesterImpl->getLastReceivedBitSet();
|
||||
testOk1(changedSet->get(0));
|
||||
testOk1(*pvStructure == *cmRequesterImpl->getLastReceivedPvStructure());
|
||||
|
||||
status = monitor->stop();
|
||||
testOk1(status.isOK());
|
||||
|
||||
}
|
||||
|
||||
MAIN(testChannelMonitor)
|
||||
{
|
||||
testPlan(16);
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -289,6 +289,7 @@ static void testMasterField(PVRecordPtr const& pvRecord)
|
||||
cout << "Master PV structure from copy" << endl << *pvMasterField << endl;
|
||||
cout << "Master PV structure from copy offset " << pvMasterField->getFieldOffset() << endl;
|
||||
}
|
||||
testOk1(pvCopy->isMasterFieldRequested());
|
||||
testOk1(pvMasterField->getNumberFields() == pvStructureRecord->getNumberFields());
|
||||
testOk1(pvMasterField->getFieldOffset() == 0);
|
||||
PVStructurePtr pvStructureCopy = pvCopy->createPVStructure();
|
||||
@@ -431,7 +432,7 @@ static void masterFieldTest()
|
||||
|
||||
MAIN(testPVCopy)
|
||||
{
|
||||
testPlan(70);
|
||||
testPlan(71);
|
||||
scalarTest();
|
||||
arrayTest();
|
||||
powerSupplyTest();
|
||||
|
||||
Reference in New Issue
Block a user