Merge branch 'database/master' back

This commit is contained in:
Ralph Lange
2018-06-20 09:32:23 +02:00
560 changed files with 94784 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
#!/bin/sh
set -e -x
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make -j2 tapfiles
make -s test-results
fi
+133
View File
@@ -0,0 +1,133 @@
#!/bin/sh
set -e -x
CURDIR="$PWD"
QDIR="$HOME/.cache/qemu"
if [ -n "$RTEMS" -a "$TEST" = "YES" ]
then
git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu"
cd "$HOME/.build/qemu"
HEAD=`git log -n1 --pretty=format:%H`
echo "HEAD revision $HEAD"
[ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"`
echo "Cached revision $BUILT"
if [ "$HEAD" != "$BUILT" ]
then
echo "Building QEMU"
git submodule --quiet update --init
install -d "$HOME/.build/qemu/build"
cd "$HOME/.build/qemu/build"
"$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror
make -j2
make install
echo "$HEAD" > "$HOME/.cache/qemu/built"
fi
fi
cd "$CURDIR"
cat << EOF > configure/RELEASE.local
EPICS_BASE=$HOME/.source/epics-base
EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_base_module() {
MODULE=$1
BRANCH=$2
( cd epics-base/modules && \
git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \
cd "$MODULE" && git log -n1 )
}
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
( cd epics-base && git log -n1 )
add_base_module libcom "${BRLIBCOM:-master}"
add_base_module ca "${BRCA:-master}"
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"
install -d /home/travis/.cache
curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \
| tar -C /home/travis/.cache -xj
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/travis/.cache/rtems${RTEMS}-i386
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386
EOF
# find local qemu-system-i386
export PATH="$HOME/.cache/qemu/usr/bin:$PATH"
echo -n "Using QEMU: "
type qemu-system-i386 || echo "Missing qemu"
EXTRA=RTEMS_QEMU_FIXUPS=YES
fi
make -j2 -C epics-base $EXTRA
+26
View File
@@ -0,0 +1,26 @@
sudo: false
dist: trusty
language: c
compiler:
- gcc
addons:
apt:
packages:
- libreadline6-dev
- libncurses5-dev
- perl
- clang
- g++-mingw-w64-i686
install:
- ./.ci/travis-prepare.sh
script:
- ./.ci/travis-build.sh
env:
- BRCORE=master BRLIBCOM=master BRCA=master
- CMPLR=clang
- USR_CXXFLAGS=-std=c++11
- CMPLR=clang USR_CXXFLAGS=-std=c++11
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO
- RTEMS=4.9 TEST=NO
+19
View File
@@ -0,0 +1,19 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure src
src_DEPEND_DIRS = configure
DIRS += test
test_DEPEND_DIRS = src
include $(TOP)/configure/RULES_TOP
+36
View File
@@ -0,0 +1,36 @@
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
BUILDING_DATABASE = DEFINED
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# Use new RSET definition
BASE_CPPFLAGS += -DUSE_TYPED_RSET
# Shared library ABI version.
SHRLIB_VERSION = 3.17.0
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif
@@ -0,0 +1,26 @@
#*************************************************************************
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set EPICS_DATABASE if necessary
ifndef EPICS_DATABASE
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
# Paths to tools built here
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
endif
# Set location of locally-built tools
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
# Libraries needed to link a basic IOC
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com
@@ -0,0 +1,4 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 17
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
+42
View File
@@ -0,0 +1,42 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building even if conflicts are found.
CHECK_RELEASE = YES
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</absolute/path/to/install/top>
# Set this when the IOC and build host use different paths
# to the install location. This may be needed to boot from
# a Microsoft FTP server say, or on some NFS configurations.
#IOCS_APPL_TOP = </IOC's/absolute/path/to/install/top>
# For application debugging purposes, override the HOST_OPT and/
# or CROSS_OPT settings from base/configure/CONFIG_SITE
#HOST_OPT = NO
#CROSS_OPT = NO
# These allow developers to override the CONFIG_SITE variable
# settings without having to modify the configure/CONFIG_SITE
# file itself.
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local
+15
View File
@@ -0,0 +1,15 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP = ..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
CFG += CONFIG_DATABASE_MODULE
CFG += CONFIG_DATABASE_VERSION
include $(TOP)/configure/RULES
+40
View File
@@ -0,0 +1,40 @@
# RELEASE - Location of external support modules
#
# 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.
#
# 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- 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.
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
# If building the EPICS modules individually, set these:
#EPICS_CA = $(MODULES)/ca-4.13.1
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
#EPICS_BASE = $(MODULES)/core-7.0.1
# Set RULES here if you want to use build rules from elsewhere:
#RULES = $(MODULES)/build-rules
# These lines allow developers to override these RELEASE settings
# without having to modify this file directly.
-include $(TOP)/../RELEASE.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local
+6
View File
@@ -0,0 +1,6 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile
+2
View File
@@ -0,0 +1,2 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc
+2
View File
@@ -0,0 +1,2 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS
+2
View File
@@ -0,0 +1,2 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP
+31
View File
@@ -0,0 +1,31 @@
#*************************************************************************
# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in the file LICENSE that is included with this distribution.
#*************************************************************************
TOP = ..
include $(TOP)/configure/CONFIG
# PDB Tools
DIRS += tools
# PDB Core
DIRS += ioc
ioc_DEPEND_DIRS = tools
# PDB Standard Record Definitions
DIRS += std
std_DEPEND_DIRS = ioc
# Templates
DIRS += template
include $(TOP)/configure/RULES_DIRS
+60
View File
@@ -0,0 +1,60 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP=../..
include $(TOP)/configure/CONFIG
SRC = $(TOP)/src
IOCDIR = $(SRC)/ioc
LIBRARY_IOC += dbCore
dbCore_LIBS += ca Com
dbCore_SYS_LIBS_WIN32 += ws2_32
dbCore_RCS += dbCore.rc
dbStaticHost_RCS = dbStaticHost.rc
INC += databaseVersion.h
INC += databaseVersionNum.h
PROD_LIBS = Com
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 17
EPICS_DATABASE_MAINTENANCE_VERSION = 0
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
include $(IOCDIR)/as/Makefile
include $(IOCDIR)/bpt/Makefile
include $(IOCDIR)/db/Makefile
include $(IOCDIR)/dbStatic/Makefile
include $(IOCDIR)/dbtemplate/Makefile
include $(IOCDIR)/misc/Makefile
include $(IOCDIR)/registry/Makefile
include $(IOCDIR)/rsrv/Makefile
EXPANDVARS += EPICS_DATABASE_MAJOR_VERSION
EXPANDVARS += EPICS_DATABASE_MINOR_VERSION
EXPANDVARS += EPICS_DATABASE_MAINTENANCE_VERSION
EXPANDVARS += EPICS_DATABASE_DEVELOPMENT_FLAG
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
include $(TOP)/configure/RULES
include $(IOCDIR)/dbStatic/RULES
include $(IOCDIR)/bpt/RULES
include $(IOCDIR)/db/RULES
include $(IOCDIR)/dbtemplate/RULES
# Can't use EXPAND as generated headers must appear
# in O.Common, but EXPAND emits rules for O.$(T_A)
../O.Common/databaseVersionNum.h: ../databaseVersionNum.h@
$(MKDIR) $(COMMON_DIR)
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
+26
View File
@@ -0,0 +1,26 @@
#*************************************************************************
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
# Brookhaven National Lab.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
SRC_DIRS += $(IOCDIR)/as
INC += asDbLib.h
INC += asCa.h
INC += asIocRegister.h
dbCore_SRCS += asDbLib.c
dbCore_SRCS += asCa.c
dbCore_SRCS += asIocRegister.c
PROD_HOST += ascheck
ascheck_SRCS = ascheck.c
ascheck_LIBS = dbCore ca Com
+335
View File
@@ -0,0 +1,335 @@
/*asCa.c*/
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 10-15-93 */
/*This module is separate from asDbLib because CA uses old database access*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "asLib.h"
#include "cantProceed.h"
#include "db_access.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "errlog.h"
#include "taskwd.h"
#include "cadef.h"
#include "caerr.h"
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "asCa.h"
#include "asDbLib.h"
#include "callback.h"
#include "epicsExport.h"
int asCaDebug = 0;
epicsExportAddress(int,asCaDebug);
static int firstTime = TRUE;
static epicsThreadId threadid=0;
static int caInitializing=FALSE;
static epicsMutexId asCaTaskLock; /*lock access to task */
static epicsEventId asCaTaskWait; /*Wait for task to respond*/
static epicsEventId asCaTaskAddChannels; /*Tell asCaTask to add channels*/
static epicsEventId asCaTaskClearChannels;/*Tell asCaTask to clear channels*/
typedef struct {
struct dbr_sts_double rtndata;
chid chid;
} CAPVT;
static void exceptionCallback(struct exception_handler_args args)
{
chid chid = args.chid;
long stat = args.stat; /* Channel access status code*/
const char *channel;
const char *context;
static char *unknown = "unknown";
const char *nativeType;
const char *requestType;
long nativeCount;
long requestCount;
int readAccess;
int writeAccess;
channel = (chid ? ca_name(chid) : unknown);
context = (args.ctx ? args.ctx : unknown);
nativeType = dbr_type_to_text((chid ? ca_field_type(chid) : -1));
requestType = dbr_type_to_text(args.type);
nativeCount = (chid ? ca_element_count(chid) : 0);
requestCount = args.count;
readAccess = (chid ? ca_read_access(chid) : 0);
writeAccess = (chid ? ca_write_access(chid) : 0);
errlogPrintf("dbCa:exceptionCallback stat \"%s\" channel \"%s\""
" context \"%s\"\n"
" nativeType %s requestType %s"
" nativeCount %ld requestCount %ld %s %s\n",
ca_message(stat),channel,context,
nativeType,requestType,
nativeCount,requestCount,
(readAccess ? "readAccess" : "noReadAccess"),
(writeAccess ? "writeAccess" : "noWriteAccess"));
}
/*connectCallback only handles disconnects*/
static void connectCallback(struct connection_handler_args arg)
{
chid chid = arg.chid;
ASGINP *pasginp = (ASGINP *)ca_puser(chid);
ASG *pasg = pasginp->pasg;
if(ca_state(chid)!=cs_conn) {
if(!(pasg->inpBad & (1<<pasginp->inpIndex))) {
/*was good so lets make it bad*/
pasg->inpBad |= (1<<pasginp->inpIndex);
if(!caInitializing) asComputeAsg(pasg);
if(asCaDebug) printf("as connectCallback disconnect %s\n",
ca_name(chid));
}
}
}
static void eventCallback(struct event_handler_args arg)
{
int caStatus = arg.status;
chid chid = arg.chid;
ASGINP *pasginp = (ASGINP *)arg.usr;
ASG *pasg;
CAPVT *pcapvt;
const struct dbr_sts_double *pdata;
if(caStatus!=ECA_NORMAL) {
if(chid) {
epicsPrintf("asCa: eventCallback error %s channel %s\n",
ca_message(caStatus),ca_name(chid));
} else {
epicsPrintf("asCa: eventCallback error %s chid is null\n",
ca_message(caStatus));
}
return;
}
pasg = pasginp->pasg;
pcapvt = (CAPVT *)pasginp->capvt;
if(chid!=pcapvt->chid) {
epicsPrintf("asCa: eventCallback error pcapvt->chid != arg.chid\n");
return;
}
if(ca_state(chid)!=cs_conn || !ca_read_access(chid)) {
if(!(pasg->inpBad & (1<<pasginp->inpIndex))) {
/*was good so lets make it bad*/
pasg->inpBad |= (1<<pasginp->inpIndex);
if(!caInitializing) asComputeAsg(pasg);
if(asCaDebug) {
printf("as eventCallback %s inpBad ca_state %d"
" ca_read_access %d\n",
ca_name(chid),ca_state(chid),ca_read_access(chid));
}
}
return;
}
pdata = arg.dbr;
pcapvt->rtndata = *pdata; /*structure copy*/
if(pdata->severity==INVALID_ALARM) {
pasg->inpBad |= (1<<pasginp->inpIndex);
if(asCaDebug)
printf("as eventCallback %s inpBad because INVALID_ALARM\n",
ca_name(chid));
} else {
pasg->inpBad &= ~((1<<pasginp->inpIndex));
pasg->pavalue[pasginp->inpIndex] = pdata->value;
if(asCaDebug)
printf("as eventCallback %s inpGood data %f\n",
ca_name(chid),pdata->value);
}
pasg->inpChanged |= (1<<pasginp->inpIndex);
if(!caInitializing) asComputeAsg(pasg);
}
static void asCaTask(void)
{
ASG *pasg;
ASGINP *pasginp;
CAPVT *pcapvt;
int status;
taskwdInsert(epicsThreadGetIdSelf(),NULL,NULL);
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
"asCaTask calling ca_context_create");
SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
"ca_add_exception_event");
while(TRUE) {
epicsEventMustWait(asCaTaskAddChannels);
caInitializing = TRUE;
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while(pasginp) {
pasg->inpBad |= (1<<pasginp->inpIndex);
pcapvt = pasginp->capvt = asCalloc(1,sizeof(CAPVT));
/*Note calls connectCallback immediately for local Pvs*/
status = ca_search_and_connect(pasginp->inp,&pcapvt->chid,
connectCallback,pasginp);
if(status!=ECA_NORMAL) {
epicsPrintf("asCa ca_search_and_connect error %s\n",
ca_message(status));
}
/*Note calls eventCallback immediately for local Pvs*/
status = ca_add_event(DBR_STS_DOUBLE,pcapvt->chid,
eventCallback,pasginp,0);
if(status!=ECA_NORMAL) {
epicsPrintf("asCa ca_add_event error %s\n",
ca_message(status));
}
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
SEVCHK(ca_flush_io(),"asCaTask");
caInitializing = FALSE;
asComputeAllAsg();
if(asCaDebug) printf("asCaTask initialized\n");
epicsEventSignal(asCaTaskWait);
epicsEventMustWait(asCaTaskClearChannels);
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while(pasginp) {
pcapvt = (CAPVT *)pasginp->capvt;
status = ca_clear_channel(pcapvt->chid);
if(status!=ECA_NORMAL) {
epicsPrintf("asCa ca_clear_channel error %s\n",
ca_message(status));
}
free(pasginp->capvt);
pasginp->capvt = 0;
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
if(asCaDebug) printf("asCaTask has cleared all channels\n");
epicsEventSignal(asCaTaskWait);
}
}
void asCaStart(void)
{
if(asCaDebug) printf("asCaStart called\n");
if(firstTime) {
firstTime = FALSE;
asCaTaskLock=epicsMutexMustCreate();
asCaTaskWait=epicsEventMustCreate(epicsEventEmpty);
asCaTaskAddChannels=epicsEventMustCreate(epicsEventEmpty);
asCaTaskClearChannels=epicsEventMustCreate(epicsEventEmpty);
threadid = epicsThreadCreate("asCaTask",
(epicsThreadPriorityScanLow - 3),
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)asCaTask,0);
if(threadid==0) {
errMessage(0,"asCaStart: taskSpawn Failure\n");
}
}
epicsMutexMustLock(asCaTaskLock);
epicsEventSignal(asCaTaskAddChannels);
epicsEventMustWait(asCaTaskWait);
if(asCaDebug) printf("asCaStart done\n");
epicsMutexUnlock(asCaTaskLock);
}
void asCaStop(void)
{
if(threadid==0) return;
if(asCaDebug) printf("asCaStop called\n");
epicsMutexMustLock(asCaTaskLock);
epicsEventSignal(asCaTaskClearChannels);
epicsEventMustWait(asCaTaskWait);
if(asCaDebug) printf("asCaStop done\n");
epicsMutexUnlock(asCaTaskLock);
}
int ascar(int level) { return ascarFP(stdout,level);}
int ascarFP(FILE *fp,int level)
{
ASG *pasg;
int n=0,nbad=0;
enum channel_state state;
if(!pasbase) {
fprintf(fp,"access security not started\n");
return(0);
}
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
ASGINP *pasginp;
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while(pasginp) {
CAPVT *pcapvt = (CAPVT *)pasginp->capvt;
chid chid = pcapvt->chid;
pcapvt = pasginp->capvt;
++n;
state = ca_state(chid);
if(state!=cs_conn) ++nbad;
if(level>1 || (level==1 && state!=cs_conn)) {
fprintf(fp,"connected:");
if(state==cs_never_conn) fprintf(fp,"never ");
else if(state==cs_prev_conn) fprintf(fp,"prev ");
else if(state==cs_conn) fprintf(fp,"yes ");
else if(state==cs_closed) fprintf(fp,"closed");
else fprintf(fp,"unknown");
fprintf(fp," read:%s write:%s",
(ca_read_access(chid) ? "yes" : "no "),
(ca_write_access(chid) ? "yes" : "no "));
fprintf(fp," %s %s\n", ca_name(chid),ca_host_name(chid));
}
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
fprintf(fp,"%d channels %d not connected\n",n,nbad);
return(0);
}
void ascaStats(int *pchans, int *pdiscon)
{
ASG *pasg;
int n = 0;
int nbad = 0;
if(!pasbase) {
if (pchans) *pchans = n;
if (pdiscon) *pdiscon = nbad;
return;
}
pasg = (ASG *)ellFirst(&pasbase->asgList);
while (pasg) {
ASGINP *pasginp;
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while (pasginp) {
CAPVT *pcapvt = (CAPVT *)pasginp->capvt;
chid chid = pcapvt->chid;
++n;
if (ca_state(chid) != cs_conn) ++nbad;
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
if (pchans) *pchans = n;
if (pdiscon) *pdiscon = nbad;
}
+30
View File
@@ -0,0 +1,30 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* asCa.h */
#ifndef INCasCah
#define INCasCah
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc void asCaStart(void);
epicsShareFunc void asCaStop(void);
epicsShareFunc int ascar(int level);
epicsShareFunc int ascarFP(FILE *fp, int level);
epicsShareFunc void ascaStats(int *pchans, int *pdiscon);
#ifdef __cplusplus
}
#endif
#endif /*INCasCah*/
+336
View File
@@ -0,0 +1,336 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 02-11-94*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "asLib.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "errlog.h"
#include "taskwd.h"
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "asCa.h"
#include "asDbLib.h"
#include "callback.h"
#include "dbAccess.h"
#include "dbChannel.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "db_field_log.h"
#include "dbStaticLib.h"
#include "recSup.h"
static char *pacf=NULL;
static char *psubstitutions=NULL;
static epicsThreadId asInitTheadId=0;
static int firstTime = TRUE;
static long asDbAddRecords(void)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
dbCommon *precord;
dbInitEntry(pdbbase,pdbentry);
status = dbFirstRecordType(pdbentry);
while(!status) {
status = dbFirstRecord(pdbentry);
while(!status) {
precord = pdbentry->precnode->precord;
if(!precord->asp) {
status = asAddMember(&precord->asp, precord->asg);
if(status) errMessage(status,"asDbAddRecords:asAddMember");
asPutMemberPvt(precord->asp,precord);
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
return(0);
}
int asSetFilename(const char *acf)
{
if (pacf)
free (pacf);
if (acf) {
pacf = calloc(1, strlen(acf)+1);
if (!pacf) {
errMessage(0, "asSetFilename calloc failure");
} else {
strcpy(pacf, acf);
if (*pacf != '/' && !strchr(pacf, ':')) {
printf("asSetFilename: Warning - relative paths won't usually "
"work\n");
}
}
} else {
pacf = NULL;
}
return 0;
}
int asSetSubstitutions(const char *substitutions)
{
if(psubstitutions) free ((void *)psubstitutions);
if(substitutions) {
psubstitutions = calloc(1,strlen(substitutions)+1);
if(!psubstitutions) {
errMessage(0,"asSetSubstitutions calloc failure");
} else {
strcpy(psubstitutions,substitutions);
}
} else {
psubstitutions = NULL;
}
return(0);
}
static void asSpcAsCallback(struct dbCommon *precord)
{
asChangeGroup(&precord->asp, precord->asg);
}
static void asInitCommonOnce(void *arg)
{
int *firstTime = (int *)arg;
*firstTime = FALSE;
}
static long asInitCommon(void)
{
long status;
int asWasActive = asActive;
int wasFirstTime = firstTime;
static epicsThreadOnceId asInitCommonOnceFlag = EPICS_THREAD_ONCE_INIT;
epicsThreadOnce(&asInitCommonOnceFlag,asInitCommonOnce,(void *)&firstTime);
if(wasFirstTime) {
if(!pacf) return(0); /*access security will NEVER be turned on*/
} else {
if(!asActive) {
printf("Access security is NOT enabled."
" Was asSetFilename specified before iocInit?\n");
return(S_asLib_asNotActive);
}
if(pacf) {
asCaStop();
} else { /*Just leave everything as is */
return(S_asLib_badConfig);
}
}
status = asInitFile(pacf,psubstitutions);
if(asActive) {
if(!asWasActive) {
dbSpcAsRegisterCallback(asSpcAsCallback);
asDbAddRecords();
}
asCaStart();
}
return(status);
}
int asInit(void)
{
return(asInitCommon());
}
int asShutdown(void) {
volatile ASBASE *pbase = pasbase;
pasbase = NULL;
firstTime = TRUE;
if(pbase)
asFreeAll((ASBASE*)pbase);
return 0;
}
static void wdCallback(void *arg)
{
ASDBCALLBACK *pcallback = (ASDBCALLBACK *)arg;
pcallback->status = S_asLib_InitFailed;
callbackRequest(&pcallback->callback);
}
static void asInitTask(ASDBCALLBACK *pcallback)
{
long status;
taskwdInsert(epicsThreadGetIdSelf(), wdCallback, (void *)pcallback);
status = asInitCommon();
taskwdRemove(epicsThreadGetIdSelf());
asInitTheadId = 0;
if(pcallback) {
pcallback->status = status;
callbackRequest(&pcallback->callback);
}
}
int asInitAsyn(ASDBCALLBACK *pcallback)
{
if(!pacf) return(0);
if(asInitTheadId) {
errMessage(-1,"asInit: asInitTask already active");
if(pcallback) {
pcallback->status = S_asLib_InitFailed;
callbackRequest(&pcallback->callback);
}
return(-1);
}
asInitTheadId = epicsThreadCreate("asInitTask",
(epicsThreadPriorityCAServerHigh + 1),
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)asInitTask,(void *)pcallback);
if(asInitTheadId==0) {
errMessage(0,"asInit: epicsThreadCreate Error");
if(pcallback) {
pcallback->status = S_asLib_InitFailed;
callbackRequest(&pcallback->callback);
}
asInitTheadId = 0;
}
return(0);
}
int asDbGetAsl(struct dbChannel *chan)
{
return dbChannelFldDes(chan)->as_level;
}
void * asDbGetMemberPvt(struct dbChannel *chan)
{
return dbChannelRecord(chan)->asp;
}
static void astacCallback(ASCLIENTPVT clientPvt,asClientStatus status)
{
char *recordname;
recordname = (char *)asGetClientPvt(clientPvt);
printf("astac callback %s: status=%d",recordname,status);
printf(" get %s put %s\n",(asCheckGet(clientPvt) ? "Yes" : "No"),
(asCheckPut(clientPvt) ? "Yes" : "No"));
}
int astac(const char *pname,const char *user,const char *location)
{
DBADDR *paddr;
long status;
ASCLIENTPVT *pasclientpvt=NULL;
dbCommon *precord;
dbFldDes *pflddes;
char *puser;
char *plocation;
paddr = dbCalloc(1,sizeof(DBADDR) + sizeof(ASCLIENTPVT));
pasclientpvt = (ASCLIENTPVT *)(paddr + 1);
status=dbNameToAddr(pname,paddr);
if(status) {
errMessage(status,"dbNameToAddr error");
return(1);
}
precord = paddr->precord;
pflddes = paddr->pfldDes;
puser = asCalloc(1,strlen(user)+1);
strcpy(puser,user);
plocation = asCalloc(1,strlen(location)+1);
strcpy(plocation,location);
status = asAddClient(pasclientpvt,precord->asp,
(int)pflddes->as_level,puser,plocation);
if(status) {
errMessage(status,"asAddClient error");
return(1);
} else {
asPutClientPvt(*pasclientpvt,(void *)precord->name);
asRegisterClientCallback(*pasclientpvt,astacCallback);
}
return(0);
}
static void myMemberCallback(ASMEMBERPVT memPvt,FILE *fp)
{
dbCommon *precord;
precord = asGetMemberPvt(memPvt);
if(precord) fprintf(fp," Record:%s",precord->name);
}
int asdbdump(void)
{
asDumpFP(stdout,myMemberCallback,NULL,1);
return(0);
}
int asdbdumpFP(FILE *fp)
{
asDumpFP(fp,myMemberCallback,NULL,1);
return(0);
}
int aspuag(const char *uagname)
{
asDumpUagFP(stdout,uagname);
return(0);
}
int aspuagFP(FILE *fp,const char *uagname)
{
asDumpUagFP(fp,uagname);
return(0);
}
int asphag(const char *hagname)
{
asDumpHagFP(stdout,hagname);
return(0);
}
int asphagFP(FILE *fp,const char *hagname)
{
asDumpHagFP(fp,hagname);
return(0);
}
int asprules(const char *asgname)
{
asDumpRulesFP(stdout,asgname);
return(0);
}
int asprulesFP(FILE *fp,const char *asgname)
{
asDumpRulesFP(fp,asgname);
return(0);
}
int aspmem(const char *asgname,int clients)
{
asDumpMemFP(stdout,asgname,myMemberCallback,clients);
return(0);
}
int aspmemFP(FILE *fp,const char *asgname,int clients)
{
asDumpMemFP(fp,asgname,myMemberCallback,clients);
return(0);
}
+54
View File
@@ -0,0 +1,54 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 02-23-94*/
#ifndef INCdbAsLibh
#define INCdbAsLibh
#include "callback.h"
#include "shareLib.h"
typedef struct {
CALLBACK callback;
long status;
} ASDBCALLBACK;
struct dbChannel;
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc int asSetFilename(const char *acf);
epicsShareFunc int asSetSubstitutions(const char *substitutions);
epicsShareFunc int asInit(void);
epicsShareFunc int asInitAsyn(ASDBCALLBACK *pcallback);
epicsShareFunc int asShutdown(void);
epicsShareFunc int asDbGetAsl(struct dbChannel *chan);
epicsShareFunc void * asDbGetMemberPvt(struct dbChannel *chan);
epicsShareFunc int asdbdump(void);
epicsShareFunc int asdbdumpFP(FILE *fp);
epicsShareFunc int aspuag(const char *uagname);
epicsShareFunc int aspuagFP(FILE *fp,const char *uagname);
epicsShareFunc int asphag(const char *hagname);
epicsShareFunc int asphagFP(FILE *fp,const char *hagname);
epicsShareFunc int asprules(const char *asgname);
epicsShareFunc int asprulesFP(FILE *fp,const char *asgname);
epicsShareFunc int aspmem(const char *asgname,int clients);
epicsShareFunc int aspmemFP(
FILE *fp,const char *asgname,int clients);
epicsShareFunc int astac(
const char *recordname,const char *user,const char *location);
#ifdef __cplusplus
}
#endif
#endif /*INCdbAsLibh*/
+129
View File
@@ -0,0 +1,129 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "asLib.h"
#include "iocsh.h"
#define epicsExportSharedSymbols
#include "asCa.h"
#include "asDbLib.h"
#include "asIocRegister.h"
/* asSetFilename */
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgString};
static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
static const iocshFuncDef asSetFilenameFuncDef =
{"asSetFilename",1,asSetFilenameArgs};
static void asSetFilenameCallFunc(const iocshArgBuf *args)
{
asSetFilename(args[0].sval);
}
/* asSetSubstitutions */
static const iocshArg asSetSubstitutionsArg0 = { "substitutions",iocshArgString};
static const iocshArg * const asSetSubstitutionsArgs[] = {&asSetSubstitutionsArg0};
static const iocshFuncDef asSetSubstitutionsFuncDef =
{"asSetSubstitutions",1,asSetSubstitutionsArgs};
static void asSetSubstitutionsCallFunc(const iocshArgBuf *args)
{
asSetSubstitutions(args[0].sval);
}
/* asInit */
static const iocshFuncDef asInitFuncDef = {"asInit",0};
static void asInitCallFunc(const iocshArgBuf *args)
{
asInit();
}
/* asdbdump */
static const iocshFuncDef asdbdumpFuncDef = {"asdbdump",0};
static void asdbdumpCallFunc(const iocshArgBuf *args)
{
asdbdump();
}
/* aspuag */
static const iocshArg aspuagArg0 = { "uagname",iocshArgString};
static const iocshArg * const aspuagArgs[] = {&aspuagArg0};
static const iocshFuncDef aspuagFuncDef = {"aspuag",1,aspuagArgs};
static void aspuagCallFunc(const iocshArgBuf *args)
{
aspuag(args[0].sval);
}
/* asphag */
static const iocshArg asphagArg0 = { "hagname",iocshArgString};
static const iocshArg * const asphagArgs[] = {&asphagArg0};
static const iocshFuncDef asphagFuncDef = {"asphag",1,asphagArgs};
static void asphagCallFunc(const iocshArgBuf *args)
{
asphag(args[0].sval);
}
/* asprules */
static const iocshArg asprulesArg0 = { "asgname",iocshArgString};
static const iocshArg * const asprulesArgs[] = {&asprulesArg0};
static const iocshFuncDef asprulesFuncDef = {"asprules",1,asprulesArgs};
static void asprulesCallFunc(const iocshArgBuf *args)
{
asprules(args[0].sval);
}
/* aspmem */
static const iocshArg aspmemArg0 = { "asgname",iocshArgString};
static const iocshArg aspmemArg1 = { "clients",iocshArgInt};
static const iocshArg * const aspmemArgs[] = {&aspmemArg0,&aspmemArg1};
static const iocshFuncDef aspmemFuncDef = {"aspmem",2,aspmemArgs};
static void aspmemCallFunc(const iocshArgBuf *args)
{
aspmem(args[0].sval,args[1].ival);
}
/* astac */
static const iocshArg astacArg0 = { "recordname",iocshArgString};
static const iocshArg astacArg1 = { "user",iocshArgString};
static const iocshArg astacArg2 = { "location",iocshArgString};
static const iocshArg * const astacArgs[] = {&astacArg0,&astacArg1,&astacArg2};
static const iocshFuncDef astacFuncDef = {"astac",3,astacArgs};
static void astacCallFunc(const iocshArgBuf *args)
{
astac(args[0].sval,args[1].sval,args[2].sval);
}
/* ascar */
static const iocshArg ascarArg0 = { "level",iocshArgInt};
static const iocshArg * const ascarArgs[] = {&ascarArg0};
static const iocshFuncDef ascarFuncDef = {"ascar",1,ascarArgs};
static void ascarCallFunc(const iocshArgBuf *args)
{
ascar(args[0].ival);
}
/* asDumpHash */
static const iocshFuncDef asDumpHashFuncDef = {"asDumpHash",0,0};
static void asDumpHashCallFunc(const iocshArgBuf *args)
{
asDumpHash();
}
void asIocRegister(void)
{
iocshRegister(&asSetFilenameFuncDef,asSetFilenameCallFunc);
iocshRegister(&asSetSubstitutionsFuncDef,asSetSubstitutionsCallFunc);
iocshRegister(&asInitFuncDef,asInitCallFunc);
iocshRegister(&asdbdumpFuncDef,asdbdumpCallFunc);
iocshRegister(&aspuagFuncDef,aspuagCallFunc);
iocshRegister(&asphagFuncDef,asphagCallFunc);
iocshRegister(&asprulesFuncDef,asprulesCallFunc);
iocshRegister(&aspmemFuncDef,aspmemCallFunc);
iocshRegister(&astacFuncDef,astacCallFunc);
iocshRegister(&ascarFuncDef,ascarCallFunc);
iocshRegister(&asDumpHashFuncDef,asDumpHashCallFunc);
}
@@ -0,0 +1,25 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_asIocRegister_H
#define INC_asIocRegister_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc void asIocRegister(void);
#ifdef __cplusplus
}
#endif
#endif /* INC_asIocRegister_H */
+56
View File
@@ -0,0 +1,56 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 03-24-94 */
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "asLib.h"
#include "dbStaticLib.h"
#include "errlog.h"
int main(int argc,char **argv)
{
int argn = 1;
char *sub = NULL;
int subLength = 0;
char **pstr;
char *psep;
int *len;
long status = 0;
static char *subSep = ",";
/* Look for -Smacro=value options */
while (argc>argn && (strncmp(argv[argn], "-S", 2)==0)) {
pstr = &sub;
psep = subSep;
len = &subLength;
if (strlen(argv[argn])==2) {
dbCatString(pstr, len, argv[++argn], psep);
} else {
dbCatString(pstr, len, argv[argn]+2, psep);
}
argn++;
}
if (argc == argn) {
status = asInitFP(stdin, sub);
if(status) errlogPrintf("ascheck: Access Security File failed.\n");
} else if (argc == argn+1) {
status = asInitFile(argv[argn], sub);
if(status) errlogPrintf("ascheck: Access Security File failed.\n");
} else {
printf("usage: ascheck [-Smac=sub ...] [<] file\n");
status = -1;
}
errlogFlush();
return status;
}
+29
View File
@@ -0,0 +1,29 @@
#*************************************************************************
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
SRC_DIRS += $(IOCDIR)/bpt
INC += cvtTable.h
DBDINC += menuConvert
BPT_DBD += bptTypeJdegC.dbd
BPT_DBD += bptTypeJdegF.dbd
BPT_DBD += bptTypeKdegC.dbd
BPT_DBD += bptTypeKdegF.dbd
DBD += $(BPT_DBD)
PROD_HOST += makeBpt
makeBpt_SRCS = makeBpt
HTMLS += menuConvert.html
+15
View File
@@ -0,0 +1,15 @@
#*************************************************************************
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
# Brookhaven National Lab.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
@@ -0,0 +1,142 @@
!header
"typeJdegC" 0 0 700 4095 .5 -210 760 1
!data
-8.096 -8.076 -8.057 -8.037 -8.017 -7.996 -7.976 -7.955 -7.934 -7.912
-7.890 -7.868 -7.846 -7.824 -7.801 -7.778 -7.755 -7.731 -7.707 -7.683
-7.659 -7.634 -7.609 -7.584 -7.559 -7.533 -7.508 -7.482 -7.455 -7.429
-7.402 -7.375 -7.348 -7.321 -7.293 -7.265 -7.237 -7.209 -7.180 -7.151
-7.122 -7.093 -7.064 -7.034 -7.004 -6.974 -6.944 -6.914 -6.883 -6.852
-6.821 -6.790 -6.758 -6.727 -6.695 -6.663 -6.630 -6.598 -6.565 -6.532
-6.499 -6.466 -6.433 -6.399 -6.365 -6.331 -6.297 -6.263 -6.228 -6.194
-6.159 -6.124 -6.089 -6.053 -6.018 -5.982 -5.946 -5.910 -5.874 -5.837
-5.801 -5.764 -5.727 -5.690 -5.653 -5.615 -5.578 -5.540 -5.502 -5.464
-5.426 -5.388 -5.349 -5.311 -5.272 -5.233 -5.194 -5.155 -5.115 -5.076
-5.036 -4.996 -4.956 -4.916 -4.876 -4.836 -4.795 -4.755 -4.714 -4.673
-4.632 -4.591 -4.550 -4.508 -4.467 -4.425 -4.383 -4.341 -4.299 -4.257
-4.215 -4.172 -4.130 -4.087 -4.044 -4.001 -3.958 -3.915 -3.872 -3.829
-3.785 -3.742 -3.698 -3.654 -3.610 -3.566 -3.522 -3.478 -3.433 -3.389
-3.344 -3.299 -3.255 -3.210 -3.165 -3.120 -3.074 -3.029 -2.984 -2.938
-2.892 -2.847 -2.801 -2.755 -2.709 -2.663 -2.617 -2.570 -2.524 -2.478
-2.431 -2.384 -2.338 -2.291 -2.244 -2.197 -2.150 -2.102 -2.055 -2.008
-1.960 -1.913 -1.865 -1.818 -1.770 -1.722 -1.674 -1.626 -1.578 -1.530
-1.481 -1.433 -1.385 -1.336 -1.288 -1.239 -1.190 -1.141 -1.093 -1.044
-0.995 -0.945 -0.896 -0.847 -0.798 -0.748 -0.699 -0.650 -0.600 -0.550
-0.501 -0.451 -0.401 -0.351 -0.301 -0.251 -0.201 -0.151 -0.101 -0.050
0.0 0.050 0.101 0.151 0.202 0.253 0.303 0.354 0.405 0.456
0.507 0.558 0.609 0.660 0.711 0.762 0.813 0.865 0.916 0.967
1.019 1.070 1.122 1.174 1.225 1.277 1.329 1.381 1.432 1.484
1.536 1.588 1.640 1.693 1.745 1.797 1.849 1.901 1.954 2.006
2.058 2.111 2.163 2.216 2.268 2.321 2.374 2.426 2.479 2.532
2.585 2.638 2.691 2.743 2.796 2.849 2.902 2.956 3.009 3.062
3.115 3.168 3.221 3.275 3.328 3.381 3.435 3.488 3.542 3.595
3.649 3.702 3.756 3.809 3.863 3.917 3.971 4.024 4.078 4.132
4.186 4.239 4.293 4.347 4.401 4.455 4.509 4.563 4.617 4.671
4.725 4.780 4.834 4.888 4.942 4.996 5.050 5.105 5.159 5.213
5.268 5.322 5.376 5.431 5.485 5.540 5.594 5.649 5.703 5.758
5.812 5.867 5.921 5.976 6.031 6.085 6.140 6.195 6.249 6.304
6.359 6.414 6.468 6.523 6.578 6.633 6.688 6.742 6.797 6.852
6.907 6.962 7.017 7.072 7.127 7.182 7.237 7.292 7.347 7.402
7.457 7.512 7.567 7.622 7.677 7.732 7.787 7.843 7.898 7.953
8.008 8.063 8.118 8.174 8.229 8.284 8.339 8.394 8.450 8.505
8.560 8.616 8.671 8.726 8.781 8.837 8.892 8.947 9.003 9.058
9.113 9.169 9.224 9.279 9.335 9.390 9.446 9.501 9.556 9.612
9.667 9.723 9.778 9.834 9.889 9.944 10.000 10.055 10.111 10.166
10.222 10.277 10.333 10.388 10.444 10.499 10.555 10.610 10.666 10.721
10.777 10.832 10.888 10.943 10.999 11.054 11.110 11.165 11.221 11.276
11.332 11.387 11.443 11.498 11.554 11.609 11.665 11.720 11.776 11.831
11.887 11.943 11.998 12.054 12.109 12.165 12.220 12.276 12.331 12.387
12.442 12.498 12.553 12.609 12.664 12.720 12.776 12.831 12.887 12.942
12.998 13.053 13.109 13.164 13.220 13.275 13.331 13.386 13.442 13.497
13.553 13.608 13.664 13.719 13.775 13.830 13.886 13.941 13.997 14.052
14.108 14.163 14.219 14.274 14.330 14.385 14.441 14.496 14.552 14.607
14.663 14.718 14.774 14.829 14.885 14.940 14.995 15.051 15.106 15.162
15.217 15.273 15.328 15.383 15.439 15.494 15.550 15.605 15.661 15.716
15.771 15.827 15.882 15.938 15.993 16.048 16.104 16.159 16.214 16.270
16.325 16.380 16.436 16.491 16.547 16.602 16.657 16.713 16.768 16.823
16.879 16.934 16.989 17.044 17.100 17.155 17.210 17.266 17.321 17.376
17.432 17.487 17.542 17.597 17.653 17.708 17.763 17.818 17.874 17.929
17.984 18.039 18.095 18.150 18.205 18.260 18.316 18.371 18.426 18.481
18.537 18.592 18.647 18.702 18.757 18.813 18.868 18.923 18.978 19.033
19.089 19.144 19.199 19.254 19.309 19.364 19.420 19.475 19.530 19.585
19.640 19.695 19.751 19.806 19.861 19.916 19.971 20.026 20.081 20.137
20.192 20.247 20.302 20.357 20.412 20.467 20.523 20.578 20.633 20.688
20.743 20.798 20.853 20.909 20.964 21.019 21.074 21.129 21.184 21.239
21.295 21.350 21.405 21.460 21.515 21.570 21.625 21.680 21.736 21.791
21.846 21.901 21.956 22.011 22.066 22.122 22.177 22.232 22.287 22.342
22.397 22.453 22.508 22.563 22.618 22.673 22.728 22.784 22.839 22.894
22.949 23.004 23.060 23.115 23.170 23.225 23.280 23.336 23.391 23.446
23.501 23.556 23.612 23.667 23.722 23.777 23.833 23.888 23.943 23.999
24.054 24.109 24.164 24.220 24.275 24.330 24.386 24.441 24.496 24.552
24.607 24.662 24.718 24.773 24.829 24.884 24.939 24.995 25.050 25.106
25.161 25.217 25.272 25.327 25.383 25.438 25.494 25.549 25.605 25.661
25.716 25.772 25.827 25.883 25.938 25.994 26.050 26.105 26.161 26.216
26.272 26.328 26.383 26.439 26.495 26.551 26.606 26.662 26.718 26.774
26.829 26.885 26.941 26.997 27.053 27.109 27.165 27.220 27.276 27.332
27.388 27.444 27.500 27.556 27.612 27.668 27.724 27.780 27.836 27.893
27.949 28.005 28.061 28.117 28.173 28.230 28.286 28.342 28.398 28.455
28.511 28.567 28.624 28.680 28.736 28.793 28.849 28.906 28.962 29.019
29.075 29.132 29.188 29.245 29.301 29.358 29.415 29.471 29.528 29.585
29.642 29.698 29.755 29.812 29.869 29.926 29.983 30.039 30.096 30.153
30.210 30.267 30.324 30.381 30.439 30.496 30.553 30.610 30.667 30.724
30.782 30.839 30.896 30.954 31.011 31.068 31.126 31.183 31.241 31.298
31.356 31.413 31.471 31.528 31.586 31.644 31.702 31.759 31.817 31.875
31.933 31.991 32.048 32.106 32.164 32.222 32.280 32.338 32.396 32.455
32.513 32.571 32.629 32.687 32.746 32.804 32.862 32.921 32.979 33.038
33.096 33.155 33.213 33.272 33.330 33.389 33.448 33.506 33.565 33.624
33.683 33.742 33.800 33.859 33.918 33.977 34.036 34.095 34.155 34.214
34.273 34.332 34.391 34.451 34.510 34.569 34.629 34.688 34.748 34.807
34.867 34.926 34.986 35.046 35.105 35.165 35.225 35.285 35.344 35.404
35.464 35.524 35.584 35.644 35.704 35.764 35.825 35.885 35.945 36.005
36.066 36.126 36.186 36.247 36.307 36.368 36.428 36.489 36.549 36.610
36.671 36.732 36.792 36.853 36.914 36.975 37.036 37.097 37.158 37.219
37.280 37.341 37.402 37.463 37.525 37.586 37.647 37.709 37.770 37.831
37.893 37.954 38.016 38.078 38.139 38.201 38.262 38.324 38.386 38.448
38.510 38.572 38.633 38.695 38.757 38.819 38.882 38.944 39.006 39.068
39.130 39.192 39.255 39.317 39.379 39.442 39.504 39.567 39.629 39.692
39.754 39.817 39.880 39.942 40.005 40.068 40.131 40.193 40.256 40.319
40.382 40.445 40.508 40.571 40.634 40.697 40.760 40.823 40.886 40.950
41.013 41.076 41.139 41.203 41.266 41.329 41.393 41.456 41.520 41.583
41.647 41.710 41.774 41.837 41.901 41.965 42.028 42.092 42.156 42.219
42.283 42.347 42.411 42.475 42.538 42.602 42.666 42.730 42.794 42.858
42.922
@@ -0,0 +1,213 @@
! cvtTypeJdegF.data
"typeJdegF" 32 0 1200 4095 1.0 -350 1400 1
!
-8.137 -8.127 -8.117 -8.106 -8.096 -8.085 -8.074 -8.063 -8.052 -8.041
-8.030 -8.019 -8.008 -7.996 -7.985 -7.973 -7.962 -7.950 -7.938 -7.927
-7.915 -7.903 -7.890 -7.878 -7.866 -7.854 -7.841 -7.829 -7.816 -7.803
-7.791 -7.778 -7.765 -7.752 -7.739 -7.726 -7.712 -7.699 -7.686 -7.672
-7.659 -7.645 -7.631 -7.618 -7.604 -7.590 -7.576 -7.562 -7.548 -7.533
-7.519 -7.505 -7.490 -7.476 -7.461 -7.447 -7.432 -7.417 -7.402 -7.387
-7.372 -7.357 -7.342 -7.327 -7.311 -7.296 -7.281 -7.265 -7.250 -7.234
-7.218 -7.202 -7.187 -7.171 -7.155 -7.139 -7.122 -7.106 -7.090 -7.074
-7.057 -7.041 -7.024 -7.008 -6.991 -6.974 -6.958 -6.941 -6.924 -6.907
-6.890 -6.873 -6.856 -6.838 -6.821 -6.804 -6.786 -6.769 -6.751 -6.734
-6.716 -6.698 -6.680 -6.663 -6.645 -6.627 -6.609 -6.591 -6.572 -6.554
-6.536 -6.518 -6.499 -6.481 -6.462 -6.444 -6.425 -6.407 -6.388 -6.369
-6.350 -6.331 -6.312 -6.293 -6.274 -6.255 -6.236 -6.217 -6.198 -6.178
-6.159 -6.139 -6.120 -6.100 -6.081 -6.061 -6.041 -6.022 -6.002 -5.982
-5.962 -5.942 -5.922 -5.902 -5.882 -5.861 -5.841 -5.821 -5.801 -5.780
-5.760 -5.739 -5.719 -5.698 -5.678 -5.657 -5.636 -5.615 -5.594 -5.574
-5.553 -5.532 -5.511 -5.490 -5.468 -5.447 -5.426 -5.405 -5.383 -5.362
-5.341 -5.319 -5.298 -5.276 -5.255 -5.233 -5.211 -5.190 -5.168 -5.146
-5.124 -5.102 -5.080 -5.058 -5.036 -5.014 -4.992 -4.970 -4.948 -4.925
-4.903 -4.881 -4.858 -4.836 -4.813 -4.791 -4.768 -4.746 -4.723 -4.700
-4.678 -4.655 -4.632 -4.609 -4.586 -4.563 -4.540 -4.517 -4.494 -4.471
-4.448 -4.425 -4.402 -4.379 -4.355 -4.332 -4.309 -4.285 -4.262 -4.238
-4.215 -4.191 -4.168 -4.144 -4.120 -4.097 -4.073 -4.049 -4.025 -4.001
-3.978 -3.954 -3.930 -3.906 -3.882 -3.858 -3.833 -3.809 -3.785 -3.761
-3.737 -3.712 -3.688 -3.664 -3.639 -3.615 -3.590 -3.566 -3.541 -3.517
-3.492 -3.468 -3.443 -3.418 -3.394 -3.369 -3.344 -3.319 -3.294 -3.270
-3.245 -3.220 -3.195 -3.170 -3.145 -3.120 -3.094 -3.069 -3.044 -3.019
-2.994 -2.968 -2.943 -2.918 -2.892 -2.867 -2.842 -2.816 -2.791 -2.765
-2.740 -2.714 -2.689 -2.663 -2.637 -2.612 -2.586 -2.560 -2.534 -2.509
-2.483 -2.457 -2.431 -2.405 -2.379 -2.353 -2.327 -2.301 -2.275 -2.249
-2.223 -2.197 -2.171 -2.144 -2.118 -2.092 -2.066 -2.039 -2.013 -1.987
-1.960 -1.934 -1.908 -1.881 -1.855 -1.828 -1.802 -1.775 -1.748 -1.722
-1.695 -1.669 -1.642 -1.615 -1.589 -1.562 -1.535 -1.508 -1.481 -1.455
-1.428 -1.401 -1.374 -1.347 -1.320 -1.293 -1.266 -1.239 -1.212 -1.185
-1.158 -1.131 -1.103 -1.076 -1.049 -1.022 -0.995 -0.967 -0.940 -0.913
-0.885 -0.858 -0.831 -0.803 -0.776 -0.748 -0.721 -0.694 -0.666 -0.639
-0.611 -0.583 -0.556 -0.528 -0.501 -0.473 -0.445 -0.418 -0.390 -0.362
-0.334 -0.307 -0.279 -0.251 -0.223 -0.195 -0.168 -0.140 -0.112 -0.084
-0.056 -0.028 0.000 0.028 0.056 0.084 0.112 0.140 0.168 0.196
0.224 0.253 0.281 0.309 0.337 0.365 0.394 0.422 0.450 0.478
0.507 0.535 0.563 0.592 0.620 0.648 0.677 0.705 0.734 0.762
0.791 0.819 0.848 0.876 0.905 0.933 0.962 0.990 1.019 1.048
1.076 1.105 1.134 1.162 1.191 1.220 1.248 1.277 1.306 1.335
1.363 1.392 1.421 1.450 1.479 1.507 1.536 1.565 1.594 1.623
1.652 1.681 1.710 1.739 1.768 1.797 1.826 1.855 1.884 1.913
1.942 1.971 2.000 2.029 2.058 2.088 2.117 2.146 2.175 2.204
2.233 2.263 2.292 2.321 2.350 2.380 2.409 2.438 2.467 2.497
2.526 2.555 2.585 2.614 2.644 2.673 2.702 2.732 2.761 2.791
2.820 2.849 2.879 2.908 2.938 2.967 2.997 3.026 3.056 3.085
3.115 3.145 3.174 3.204 3.233 3.263 3.293 3.322 3.352 3.381
3.411 3.441 3.470 3.500 3.530 3.560 3.589 3.619 3.649 3.678
3.708 3.738 3.768 3.798 3.827 3.857 3.887 3.917 3.947 3.976
4.006 4.036 4.066 4.096 4.126 4.156 4.186 4.216 4.245 4.275
4.305 4.335 4.365 4.395 4.425 4.455 4.485 4.515 4.545 4.575
4.605 4.635 4.665 4.695 4.725 4.755 4.786 4.816 4.846 4.876
4.906 4.936 4.966 4.996 5.026 5.057 5.087 5.117 5.147 5.177
5.207 5.238 5.268 5.298 5.328 5.358 5.389 5.419 5.449 5.479
5.509 5.540 5.570 5.600 5.630 5.661 5.691 5.721 5.752 5.782
5.812 5.843 5.873 5.903 5.934 5.964 5.994 6.025 6.055 6.085
6.116 6.146 6.176 6.207 6.237 6.268 6.298 6.328 6.359 6.389
6.420 6.450 6.481 6.511 6.541 6.572 6.602 6.633 6.663 6.694
6.724 6.755 6.785 6.816 6.846 6.877 6.907 6.938 6.968 6.999
7.029 7.060 7.090 7.121 7.151 7.182 7.212 7.243 7.274 7.304
7.335 7.365 7.396 7.426 7.457 7.488 7.518 7.549 7.579 7.610
7.641 7.671 7.702 7.732 7.763 7.794 7.824 7.855 7.885 7.916
7.947 7.977 8.008 8.039 8.069 8.100 8.131 8.161 8.192 8.223
8.253 8.284 8.315 8.345 8.376 8.407 8.437 8.468 8.499 8.530
8.560 8.591 8.622 8.652 8.683 8.714 8.745 8.775 8.806 8.837
8.867 8.898 8.929 8.960 8.990 9.021 9.052 9.083 9.113 9.144
9.175 9.206 9.236 9.267 9.298 9.329 9.359 9.390 9.421 9.452
9.483 9.513 9.544 9.575 9.606 9.636 9.667 9.698 9.729 9.760
9.790 9.821 9.852 9.883 9.914 9.944 9.975 10.006 10.037 10.068
10.098 10.129 10.160 10.191 10.222 10.252 10.283 10.314 10.345 10.376
10.407 10.437 10.468 10.499 10.530 10.561 10.592 10.622 10.653 10.684
10.715 10.746 10.777 10.807 10.838 10.869 10.900 10.931 10.962 10.992
11.023 11.054 11.085 11.116 11.147 11.177 11.208 11.239 11.270 11.301
11.332 11.363 11.393 11.424 11.455 11.486 11.517 11.548 11.578 11.609
11.640 11.671 11.702 11.733 11.764 11.794 11.825 11.856 11.887 11.918
11.949 11.980 12.010 12.041 12.072 12.103 12.134 12.165 12.196 12.226
12.257 12.288 12.319 12.350 12.381 12.411 12.442 12.473 12.504 12.535
12.566 12.597 12.627 12.658 12.689 12.720 12.751 12.782 12.813 12.843
12.874 12.905 12.936 12.967 12.998 13.029 13.059 13.090 13.121 13.152
13.183 13.214 13.244 13.275 13.306 13.337 13.368 13.399 13.430 13.460
13.491 13.522 13.553 13.584 13.615 13.645 13.676 13.707 13.738 13.769
13.800 13.830 13.861 13.892 13.923 13.954 13.985 14.015 14.046 14.077
14.108 14.139 14.170 14.200 14.231 14.262 14.293 14.324 14.355 14.385
14.416 14.447 14.478 14.509 14.539 14.570 14.601 14.632 14.663 14.694
14.724 14.755 14.786 14.817 14.848 14.878 14.909 14.940 14.971 15.002
15.032 15.063 15.094 15.125 15.156 15.186 15.217 15.248 15.279 15.310
15.340 15.371 15.402 15.433 15.464 15.494 15.525 15.556 15.587 15.617
15.648 15.679 15.710 15.741 15.771 15.802 15.833 15.864 15.894 15.925
15.956 15.987 16.018 16.048 16.079 16.110 16.141 16.171 16.202 16.233
16.264 16.294 16.325 16.356 16.387 16.417 16.448 16.479 16.510 16.540
16.571 16.602 16.633 16.663 16.694 16.725 16.756 16.786 16.817 16.848
16.879 16.909 16.940 16.971 17.001 17.032 17.063 17.094 17.124 17.155
17.186 17.217 17.247 17.278 17.309 17.339 17.370 17.401 17.432 17.462
17.493 17.524 17.554 17.585 17.616 17.646 17.677 17.708 17.739 17.769
17.800 17.831 17.861 17.892 17.923 17.953 17.984 18.015 18.046 18.076
18.107 18.138 18.168 18.199 18.230 18.260 18.291 18.322 18.352 18.383
18.414 18.444 18.475 18.506 18.537 18.567 18.598 18.629 18.659 18.690
18.721 18.751 18.782 18.813 18.843 18.874 18.905 18.935 18.966 18.997
19.027 19.058 19.089 19.119 19.150 19.180 19.211 19.242 19.272 19.303
19.334 19.364 19.395 19.426 19.456 19.487 19.518 19.548 19.579 19.610
19.640 19.671 19.702 19.732 19.763 19.793 19.824 19.855 19.885 19.916
19.947 19.977 20.008 20.039 20.069 20.100 20.131 20.161 20.192 20.222
20.253 20.284 20.314 20.345 20.376 20.406 20.437 20.467 20.498 20.529
20.559 20.590 20.621 20.651 20.682 20.713 20.743 20.774 20.804 20.835
20.866 20.896 20.927 20.958 20.988 21.019 21.049 21.080 21.111 21.141
21.172 21.203 21.233 21.264 21.295 21.325 21.356 21.386 21.417 21.448
21.478 21.509 21.540 21.570 21.601 21.631 21.662 21.693 21.723 21.754
21.785 21.815 21.846 21.877 21.907 21.938 21.968 21.999 22.030 22.060
22.091 22.122 22.152 22.183 22.214 22.244 22.275 22.305 22.336 22.367
22.397 22.428 22.459 22.489 22.520 22.551 22.581 22.612 22.643 22.673
22.704 22.735 22.765 22.796 22.826 22.857 22.888 22.918 22.949 22.980
23.010 23.041 23.072 23.102 23.133 23.164 23.194 23.225 23.256 23.286
23.317 23.348 23.378 23.409 23.440 23.471 23.501 23.532 23.563 23.593
23.624 23.655 23.685 23.716 23.747 23.777 23.808 23.839 23.870 23.900
23.931 23.962 23.992 24.023 24.054 24.085 24.115 24.146 24.177 24.207
24.238 24.269 24.300 24.330 24.361 24.392 24.423 24.453 24.484 24.515
24.546 24.576 24.607 24.638 24.669 24.699 24.730 24.761 24.792 24.822
24.853 24.854 24.915 24.946 24.976 25.007 25.038 25.069 25.099 25.130
25.161 25.192 25.223 25.254 25.284 25.315 25.346 25.377 25.408 25.438
25.469 25.500 25.531 25.562 25.593 25.623 25.654 25.685 25.716 25.747
25.778 25.809 25.840 25.870 25.901 25.932 25.963 25.994 26.025 26.056
26.087 26.118 26.148 26.179 26.210 26.241 26.272 26.303 26.334 26.365
26.396 26.427 26.458 26.489 26.520 26.551 26.582 26.613 26.644 26.675
26.705 26.736 26.767 26.798 26.829 26.860 26.891 26.922 26.954 26.985
27.016 27.047 27.078 27.109 27.140 27.171 27.202 27.233 27.264 27.295
27.326 27.357 27.388 27.419 27.450 27.482 27.513 27.544 27.575 27.606
27.637 27.668 27.699 27.731 27.762 27.793 27.824 27.855 27.886 27.917
27.949 27.980 28.011 28.042 28.073 28.105 28.136 28.167 28.198 28.230
28.261 28.292 28.323 28.355 28.386 28.417 28.448 28.480 28.511 28.542
28.573 28.605 28.636 28.667 28.699 28.730 28.761 28.793 28.824 28.855
28.887 28.918 28.950 28.981 29.012 29.044 29.075 29.107 29.138 29.169
29.201 29.232 29.264 29.295 29.327 29.358 29.390 29.421 29.452 29.484
29.515 29.547 29.578 29.610 29.642 29.673 29.705 29.736 29.768 29.799
29.831 29.862 29.894 29.926 29.957 29.989 30.020 30.052 30.084 30.115
30.147 30.179 30.210 30.242 30.274 30.305 30.337 30.369 30.400 30.432
30.464 30.496 30.527 30.559 30.591 30.623 30.654 30.686 30.718 30.750
30.782 30.813 30.845 30.877 30.909 30.941 30.973 31.005 31.036 31.068
31.100 31.132 31.164 31.196 31.228 31.260 31.292 31.324 31.356 31.388
31.420 31.452 31.484 31.516 31.548 31.580 31.612 31.644 31.676 31.708
31.740 31.772 31.804 31.836 31.868 31.901 31.933 31.965 31.997 32.029
32.061 32.094 32.126 32.158 32.190 32.222 32.255 32.287 32.319 32.351
32.384 32.416 32.448 32.480 32.513 32.545 32.577 32.610 32.642 32.674
32.707 32.739 32.772 32.804 32.836 32.869 32.901 32.934 32.966 32.999
33.031 33.064 33.096 33.129 33.161 33.194 33.226 33.259 33.291 33.324
33.356 33.389 33.422 33.454 33.487 33.519 33.552 33.585 33.617 33.650
33.683 33.715 33.748 33.781 33.814 33.846 33.879 33.912 33.945 33.977
34.010 34.043 34.076 34.109 34.141 34.174 34.207 34.240 34.273 34.306
34.339 34.372 34.405 34.437 34.470 34.503 34.536 34.569 34.602 34.635
34.668 34.701 34.734 34.767 34.801 34.834 34.867 34.900 34.933 34.966
34.999 35.032 35.065 35.099 35.132 35.165 35.198 35.231 35.265 35.298
35.331 35.364 35.398 35.431 35.464 35.498 35.531 35.564 35.598 35.631
35.664 35.698 35.731 35.764 35.798 35.831 35.865 35.898 35.932 35.965
35.999 36.032 36.066 36.099 36.133 36.166 36.200 36.233 36.267 36.301
36.334 36.368 36.401 36.435 36.469 36.502 36.536 36.570 36.603 36.637
36.671 36.705 36.738 36.772 36.806 36.840 36.873 36.907 36.941 36.975
37.009 37.043 37.076 37.110 37.144 37.178 37.212 37.246 37.280 37.314
37.348 37.382 37.416 37.450 37.484 37.518 37.552 37.586 37.620 37.654
37.688 37.722 37.756 37.790 37.825 37.859 37.893 37.927 37.961 37.995
38.030 38.064 38.098 38.132 38.167 38.201 38.235 38.269 38.304 38.338
38.372 38.407 38.441 38.475 38.510 38.544 38.578 38.613 38.647 38.682
38.716 38.751 38.785 38.819 38.854 38.888 38.923 38.957 38.992 39.027
39.061 39.096 39.130 39.165 39.199 39.234 39.269 39.303 39.338 39.373
39.407 39.442 39.477 39.511 39.546 39.581 39.615 39.650 39.685 39.720
39.754 39.789 39.824 39.859 39.894 39.928 39.963 39.998 40.033 40.068
40.103 40.138 40.172 40.207 40.242 40.277 40.312 40.347 40.382 40.417
40.452 40.487 40.522 40.557 40.592 40.627 40.662 40.697 40.732 40.767
40.802 40.837 40.872 40.908 40.943 40.978 41.013 41.048 41.083 41.118
41.154 41.189 41.224 41.259 41.294 41.329 41.365 41.400 41.435 41.470
41.506 41.541 41.576 41.611 41.647 41.682 41.717 41.753 41.788 41.823
41.859 41.894 41.929 41.965 42.000 42.035 42.071 42.106 42.142 42.177
42.212 42.248 42.283 42.319 42.354 42.390 42.425 42.460 42.496 42.531
42.567 42.602 42.638 42.673 42.709 42.744 42.780 42.815 42.851 42.886
42.922
@@ -0,0 +1,201 @@
! cvtTypeKdegC.data
"typeKdegC" 0 0 1000 4095 .5 -270 1372 1
!
-6.458 -6.457 -6.456 -6.455 -6.453 -6.452 -6.450 -6.448 -6.446 -6.444
-6.441 -6.438 -6.435 -6.432 -6.429 -6.425 -6.421 -6.417 -6.413 -6.408
-6.404 -6.399 -6.394 -6.388 -6.382 -6.377 -6.371 -6.364 -6.358 -6.351
-6.344 -6.337 -6.329 -6.322 -6.314 -6.306 -6.297 -6.289 -6.280 -6.271
-6.262 -6.253 -6.243 -6.233 -6.223 -6.213 -6.202 -6.192 -6.181 -6.170
-6.158 -6.147 -6.135 -6.123 -6.111 -6.099 -6.087 -6.074 -6.061 -6.048
-6.035 -6.021 -6.007 -5.994 -5.980 -5.965 -5.951 -5.936 -5.922 -5.907
-5.891 -5.876 -5.860 -5.845 -5.829 -5.813 -5.796 -5.780 -5.763 -5.747
-5.730 -5.712 -5.695 -5.678 -5.660 -5.642 -5.624 -5.606 -5.587 -5.569
-5.550 -5.531 -5.512 -5.493 -5.474 -5.454 -5.434 -5.414 -5.394 -5.374
-5.354 -5.333 -5.313 -5.292 -5.271 -5.249 -5.228 -5.207 -5.185 -5.163
-5.141 -5.119 -5.097 -5.074 -5.051 -5.029 -5.006 -4.983 -4.959 -4.936
-4.912 -4.889 -4.865 -4.841 -4.817 -4.792 -4.768 -4.743 -4.719 -4.694
-4.669 -4.644 -4.618 -4.593 -4.567 -4.541 -4.515 -4.489 -4.463 -4.437
-4.410 -4.384 -4.357 -4.330 -4.303 -4.276 -4.248 -4.221 -4.193 -4.166
-4.138 -4.110 -4.082 -4.053 -4.025 -3.997 -3.968 -3.939 -3.910 -3.881
-3.852 -3.823 -3.793 -3.764 -3.734 -3.704 -3.674 -3.644 -3.614 -3.584
-3.553 -3.523 -3.492 -3.461 -3.430 -3.399 -3.368 -3.337 -3.305 -3.274
-3.242 -3.211 -3.179 -3.147 -3.115 -3.082 -3.050 -3.018 -2.985 -2.953
-2.920 -2.887 -2.854 -2.821 -2.788 -2.754 -2.721 -2.687 -2.654 -2.620
-2.586 -2.552 -2.518 -2.484 -2.450 -2.416 -2.381 -2.347 -2.312 -2.277
-2.243 -2.208 -2.173 -2.137 -2.102 -2.067 -2.032 -1.996 -1.961 -1.925
-1.889 -1.853 -1.817 -1.781 -1.745 -1.709 -1.673 -1.636 -1.600 -1.563
-1.527 -1.490 -1.453 -1.416 -1.379 -1.342 -1.305 -1.268 -1.231 -1.193
-1.156 -1.118 -1.081 -1.043 -1.005 -0.968 -0.930 -0.892 -0.854 -0.816
-0.777 -0.739 -0.701 -0.662 -0.624 -0.585 -0.547 -0.508 -0.469 -0.431
-0.392 -0.353 -0.314 -0.275 -0.236 -0.197 -0.157 -0.118 -0.079 -0.039
0.000 0.039 0.079 0.119 0.158 0.198 0.238 0.277 0.317 0.357
0.397 0.437 0.477 0.517 0.557 0.597 0.637 0.677 0.718 0.758
0.798 0.838 0.879 0.919 0.960 1.000 1.041 1.081 1.122 1.162
1.203 1.244 1.285 1.325 1.366 1.407 1.448 1.489 1.529 1.570
1.611 1.652 1.693 1.734 1.776 1.817 1.858 1.899 1.940 1.981
2.022 2.064 2.105 2.146 2.188 2.229 2.270 2.312 2.353 2.394
2.436 2.477 2.519 2.560 2.601 2.643 2.684 2.726 2.767 2.809
2.850 2.892 2.933 2.975 3.016 3.058 3.100 3.141 3.183 3.224
3.266 3.307 3.349 3.390 3.432 3.473 3.515 3.556 3.598 3.639
3.681 3.722 3.764 3.805 3.847 3.888 3.930 3.971 4.012 4.054
4.095 4.137 4.178 4.219 4.261 4.302 4.343 4.384 4.426 4.467
4.508 4.549 4.590 4.632 4.673 4.714 4.755 4.796 4.837 4.878
4.919 4.960 5.001 5.042 5.083 5.124 5.164 5.205 5.246 5.287
5.327 5.368 5.409 5.450 5.490 5.531 5.571 5.612 5.652 5.693
5.733 5.774 5.814 5.855 5.895 5.936 5.976 6.016 6.057 6.097
6.137 6.177 6.218 6.258 6.298 6.338 6.378 6.419 6.459 6.499
6.539 6.579 6.619 6.659 6.699 6.739 6.779 6.819 6.859 6.899
6.939 6.979 7.019 7.059 7.099 7.139 7.179 7.219 7.259 7.299
7.338 7.378 7.418 7.458 7.498 7.538 7.578 7.618 7.658 7.697
7.737 7.777 7.817 7.857 7.897 7.937 7.977 8.017 8.057 8.097
8.137 8.177 8.216 8.256 8.296 8.336 8.376 8.416 8.456 8.497
8.537 8.577 8.617 8.657 8.697 8.737 8.777 8.817 8.857 8.898
8.938 8.978 9.018 9.058 9.099 9.139 9.179 9.220 9.260 9.300
9.341 9.381 9.421 9.462 9.502 9.543 9.583 9.624 9.664 9.705
9.745 9.786 9.826 9.867 9.907 9.948 9.989 10.029 10.070 10.111
10.151 10.192 10.233 10.274 10.315 10.355 10.396 10.437 10.478 10.519
10.560 10.600 10.641 10.682 10.723 10.764 10.805 10.846 10.887 10.928
10.969 11.010 11.051 11.093 11.134 11.175 11.216 11.257 11.298 11.339
11.381 11.422 11.463 11.504 11.546 11.587 11.628 11.669 11.711 11.752
11.793 11.835 11.876 11.918 11.959 12.000 12.042 12.083 12.125 12.166
12.207 12.249 12.290 12.332 12.373 12.415 12.456 12.498 12.539 12.581
12.623 12.664 12.706 12.747 12.789 12.831 12.872 12.914 12.955 12.997
13.039 13.080 13.122 13.164 13.205 13.247 13.289 13.331 13.372 13.414
13.456 13.497 13.539 13.581 13.623 13.665 13.706 13.748 13.790 13.832
13.874 13.915 13.957 13.999 14.041 14.083 14.125 14.167 14.208 14.250
14.292 14.334 14.376 14.418 14.460 14.502 14.544 14.586 14.628 14.670
14.712 14.754 14.796 14.838 14.880 14.922 14.964 15.006 15.048 15.090
15.132 15.174 15.216 15.258 15.300 15.342 15.384 15.426 15.468 15.510
15.552 15.594 15.636 15.679 15.721 15.763 15.805 15.847 15.889 15.931
15.974 16.016 16.058 16.100 16.142 16.184 16.227 16.269 16.311 16.353
16.395 16.438 16.480 16.522 16.564 16.607 16.649 16.691 16.733 16.776
16.818 16.860 16.902 16.945 16.987 17.029 17.072 17.114 17.156 17.199
17.241 17.283 17.326 17.368 17.410 17.453 17.495 17.537 17.580 17.622
17.664 17.707 17.749 17.792 17.834 17.876 17.919 17.961 18.004 18.046
18.088 18.131 18.173 18.216 18.258 18.301 18.343 18.385 18.428 18.470
18.513 18.555 18.598 18.640 18.683 18.725 18.768 18.810 18.853 18.895
18.938 18.980 19.023 19.065 19.108 19.150 19.193 19.235 19.278 19.320
19.363 19.405 19.448 19.490 19.533 19.576 19.618 19.661 19.703 19.746
19.788 19.831 19.873 19.916 19.959 20.001 20.044 20.086 20.129 20.172
20.214 20.257 20.299 20.342 20.385 20.427 20.470 20.512 20.555 20.598
20.640 20.683 20.725 20.768 20.811 20.853 20.896 20.938 20.981 21.024
21.066 21.109 21.152 21.194 21.237 21.280 21.322 21.365 21.407 21.450
21.493 21.535 21.578 21.621 21.663 21.706 21.749 21.791 21.834 21.876
21.919 21.962 22.004 22.047 22.090 22.132 22.175 22.218 22.260 22.303
22.346 22.388 22.431 22.473 22.516 22.559 22.601 22.644 22.687 22.729
22.772 22.815 22.857 22.900 22.942 22.985 23.028 23.070 23.113 23.156
23.198 23.241 23.284 23.326 23.369 23.411 23.454 23.497 23.539 23.582
23.624 23.667 23.710 23.752 23.795 23.837 23.880 23.923 23.965 24.008
24.050 24.093 24.136 24.178 24.221 24.263 24.306 24.348 24.391 24.434
24.476 24.519 24.561 24.604 24.646 24.689 24.731 24.774 24.817 24.859
24.902 24.944 24.987 25.029 25.072 25.114 25.157 25.199 25.242 25.284
25.327 25.369 25.412 25.454 25.497 25.539 25.582 25.624 25.666 25.709
25.751 25.794 25.836 25.879 25.921 25.964 26.006 26.048 26.091 26.133
26.176 26.218 26.260 26.303 26.345 26.387 26.430 26.472 26.515 26.557
26.599 26.642 26.684 26.726 26.769 26.811 26.853 26.896 26.938 26.980
27.022 27.065 27.107 27.149 27.192 27.234 27.276 27.318 27.361 27.403
27.445 27.487 27.529 27.572 27.614 27.656 27.698 27.740 27.783 27.825
27.867 27.909 27.951 27.993 28.035 28.078 28.120 28.162 28.204 28.246
28.288 28.330 28.372 28.414 28.456 28.498 28.540 28.583 28.625 28.667
28.709 28.751 28.793 28.835 28.877 28.919 28.961 29.002 29.044 29.086
29.128 29.170 29.212 29.254 29.296 29.338 29.380 29.422 29.464 29.505
29.547 29.589 29.631 29.673 29.715 29.756 29.798 29.840 29.882 29.924
29.965 30.007 30.049 30.091 30.132 30.174 30.216 30.257 30.299 30.341
30.383 30.424 30.466 30.508 30.549 30.591 30.632 30.674 30.716 30.757
30.799 30.840 30.882 30.924 30.965 31.007 31.048 31.090 31.131 31.173
31.214 31.256 31.297 31.339 31.380 31.422 31.463 31.504 31.546 31.587
31.629 31.670 31.712 31.753 31.794 31.836 31.877 31.918 31.960 32.001
32.042 32.084 32.125 32.166 32.207 32.249 32.290 32.331 32.372 32.414
32.455 32.496 32.537 32.578 32.619 32.661 32.702 32.743 32.784 32.825
32.866 32.907 32.948 32.990 33.031 33.072 33.113 33.154 33.195 33.236
33.277 33.318 33.359 33.400 33.441 33.482 33.523 33.564 33.604 33.645
33.686 33.727 33.768 33.809 33.850 33.891 33.931 33.972 34.013 34.054
34.095 34.136 34.176 34.217 34.258 34.299 34.339 34.380 34.421 34.461
34.502 34.543 34.583 34.624 34.665 34.705 34.746 34.787 34.827 34.868
34.909 34.949 34.990 35.030 35.071 35.111 35.152 35.192 35.233 35.273
35.314 35.354 35.395 35.435 35.476 35.516 35.557 35.597 35.637 35.678
35.718 35.758 35.799 35.839 35.880 35.920 35.960 36.000 36.041 36.081
36.121 36.162 36.202 36.242 36.282 36.323 36.363 36.403 36.443 36.483
36.524 36.564 36.604 36.644 36.684 36.724 36.764 36.804 36.844 36.885
36.925 36.965 37.005 37.045 37.085 37.125 37.165 37.205 37.245 37.285
37.325 37.365 37.405 37.445 37.484 37.524 37.564 37.604 37.644 37.684
37.724 37.764 37.803 37.843 37.883 37.923 37.963 38.002 38.042 38.082
38.122 38.162 38.201 38.241 38.281 38.320 38.360 38.400 38.439 38.479
38.519 38.558 38.598 38.638 38.677 38.717 38.756 38.796 38.836 38.875
38.915 38.954 38.994 39.033 39.073 39.112 39.152 39.191 39.231 39.270
39.310 39.349 39.388 39.428 39.467 39.507 39.546 39.585 39.625 39.644
39.703 39.743 39.782 39.821 39.861 39.900 39.939 39.979 40.018 40.057
40.096 40.136 40.175 40.214 40.253 40.292 40.332 40.371 40.410 40.449
40.488 40.527 40.566 40.605 40.645 40.684 40.723 40.762 40.801 40.840
40.879 40.918 40.957 40.996 41.035 41.074 41.113 41.152 41.191 41.230
41.269 41.308 41.347 41.385 41.424 41.463 41.502 41.541 41.580 41.619
41.657 41.696 41.735 41.774 41.813 41.851 41.890 41.929 41.968 42.006
42.045 42.084 42.123 42.161 42.200 42.239 42.277 42.316 42.355 42.393
42.432 42.470 42.509 42.548 42.586 42.625 42.663 42.702 42.740 42.779
42.817 42.856 42.894 42.933 42.971 43.010 43.048 43.087 43.125 43.164
43.202 43.240 43.279 43.317 43.356 43.394 43.432 43.471 43.509 43.547
43.585 43.624 43.662 43.700 43.739 43.777 43.815 43.853 43.891 43.930
43.968 44.006 44.044 44.082 44.121 44.159 44.197 44.235 44.273 44.311
44.349 44.387 44.425 44.463 44.501 44.539 44.577 44.615 44.653 44.691
44.729 44.767 44.805 44.843 44.881 44.919 44.957 44.995 45.033 45.070
45.108 45.146 45.184 45.222 45.260 45.297 45.335 45.373 45.411 45.448
45.486 45.524 45.561 45.599 45.637 45.675 45.712 45.750 45.787 45.825
45.863 45.900 45.938 45.975 46.013 46.051 46.088 46.126 46.163 46.201
46.238 46.275 46.313 46.350 46.388 46.425 46.463 46.500 46.537 46.575
46.612 46.649 46.687 46.724 46.761 46.799 46.836 46.873 46.910 46.948
46.985 47.022 47.059 47.096 47.134 47.171 47.208 47.245 47.282 47.319
47.356 47.393 47.430 47.468 47.505 47.542 47.579 47.616 47.653 47.689
47.726 47.763 47.800 47.837 47.874 47.911 47.948 47.985 48.021 48.058
48.095 48.132 48.169 48.205 48.242 48.279 48.316 48.352 48.389 48.426
48.462 48.499 48.536 48.572 48.609 48.645 48.682 48.718 48.755 48.792
48.828 48.865 48.901 48.937 48.974 49.010 49.047 49.083 49.120 49.156
49.192 49.229 49.265 49.301 49.338 49.374 49.410 49.446 49.483 49.519
49.555 49.591 49.627 49.663 49.700 49.736 49.772 49.808 49.844 49.880
49.916 49.952 49.988 50.024 50.060 50.096 50.132 50.168 50.204 50.240
50.276 50.311 50.347 50.383 50.419 50.455 50.491 50.526 50.562 50.598
50.633 50.669 50.705 50.741 50.776 50.812 50.847 50.883 50.919 50.954
50.990 51.025 51.061 51.096 51.132 51.167 51.203 51.238 51.274 51.309
51.344 51.380 51.415 51.450 51.486 51.521 51.556 51.592 51.627 51.662
51.697 51.733 51.768 51.803 51.838 51.873 51.908 51.943 51.979 52.014
52.049 52.084 52.119 52.154 52.189 52.224 52.259 52.294 52.329 52.364
52.398 52.433 52.468 52.503 52.538 52.573 52.608 52.642 52.677 52.712
52.747 52.781 52.816 52.851 52.886 52.920 52.955 52.989 53.024 53.059
53.093 53.128 53.162 53.197 53.232 53.266 53.301 53.335 53.370 53.404
53.439 53.473 53.507 53.542 53.576 53.611 53.645 53.679 53.714 53.748
53.782 53.817 53.851 53.885 53.920 53.954 53.988 54.022 54.057 54.091
54.125 54.159 54.193 54.228 54.262 54.296 54.330 54.364 54.398 54.432
54.466 54.501 54.535 54.569 54.603 54.637 54.671 54.705 54.739 54.773
54.807 54.841 54.875
@@ -0,0 +1,360 @@
! cvtTypeKdegF.data
"typeKdegF" 32 0 1832 4095 1.0 -454 2500 1
!
-6.458 -6.457 -6.457 -6.456
-6.456 -6.455 -6.454 -6.454 -6.453 -6.452 -6.451 -6.450 -6.449 -6.448
-6.447 -6.445 -6.444 -6.443 -6.441 -6.440 -6.438 -6.436 -6.435 -6.433
-6.431 -6.429 -6.427 -6.425 -6.423 -6.421 -6.419 -6.416 -6.414 -6.411
-6.409 -6.406 -6.404 -6.401 -6.398 -6.395 -6.392 -6.389 -6.386 -6.383
-6.380 -6.377 -6.373 -6.370 -6.366 -6.363 -6.359 -6.355 -6.352 -6.348
-6.344 -6.340 -6.336 -6.332 -6.328 -6.323 -6.319 -6.315 -6.310 -6.306
-6.301 -6.296 -6.292 -6.287 -6.282 -6.277 -6.272 -6.267 -6.262 -6.257
-6.251 -6.246 -6.241 -6.235 -6.230 -6.224 -6.219 -6.213 -6.207 -6.201
-6.195 -6.189 -6.183 -6.177 -6.171 -6.165 -6.158 -6.152 -6.146 -6.139
-6.133 -6.126 -6.119 -6.113 -6.106 -6.099 -6.092 -6.085 -6.078 -6.071
-6.064 -6.057 -6.049 -6.042 -6.035 -6.027 -6.020 -6.012 -6.004 -5.997
-5.989 -5.981 -5.973 -5.965 -5.957 -5.949 -5.941 -5.933 -5.925 -5.917
-5.908 -5.900 -5.891 -5.883 -5.874 -5.866 -5.857 -5.848 -5.839 -5.831
-5.822 -5.813 -5.804 -5.795 -5.786 -5.776 -5.767 -5.758 -5.748 -5.739
-5.730 -5.720 -5.711 -5.701 -5.691 -5.682 -5.672 -5.662 -5.652 -5.642
-5.632 -5.622 -5.612 -5.602 -5.592 -5.581 -5.571 -5.561 -5.550 -5.540
-5.529 -5.519 -5.508 -5.497 -5.487 -5.476 -5.465 -5.454 -5.443 -5.432
-5.421 -5.410 -5.399 -5.388 -5.376 -5.365 -5.354 -5.342 -5.331 -5.319
-5.308 -5.296 -5.285 -5.273 -5.261 -5.249 -5.238 -5.226 -5.214 -5.202
-5.190 -5.178 -5.165 -5.153 -5.141 -5.129 -5.116 -5.104 -5.092 -5.079
-5.067 -5.054 -5.041 -5.029 -5.016 -5.003 -4.990 -4.978 -4.965 -4.952
-4.939 -4.926 -4.912 -4.899 -4.886 -4.873 -4.860 -4.846 -4.833 -4.819
-4.806 -4.792 -4.779 -4.765 -4.752 -4.738 -4.724 -4.710 -4.697 -4.683
-4.669 -4.655 -4.641 -4.627 -4.613 -4.598 -4.584 -4.570 -4.556 -4.541
-4.527 -4.512 -4.498 -4.484 -4.469 -4.454 -4.440 -4.425 -4.410 -4.396
-4.381 -4.366 -4.351 -4.336 -4.321 -4.306 -4.291 -4.276 -4.261 -4.245
-4.230 -4.215 -4.200 -4.184 -4.169 -4.153 -4.138 -4.122 -4.107 -4.091
-4.075 -4.060 -4.044 -4.028 -4.012 -3.997 -3.981 -3.965 -3.949 -3.933
-3.917 -3.901 -3.884 -3.868 -3.852 -3.836 -3.819 -3.803 -3.787 -3.770
-3.754 -3.737 -3.721 -3.704 -3.688 -3.671 -3.654 -3.637 -3.621 -3.604
-3.587 -3.570 -3.553 -3.536 -3.519 -3.502 -3.485 -3.468 -3.451 -3.434
-3.417 -3.399 -3.382 -3.365 -3.347 -3.330 -3.312 -3.295 -3.277 -3.260
-3.242 -3.225 -3.207 -3.189 -3.172 -3.154 -3.136 -3.118 -3.100 -3.082
-3.065 -3.047 -3.029 -3.010 -2.992 -2.974 -2.956 -2.938 -2.920 -2.902
-2.883 -2.865 -2.847 -2.828 -2.810 -2.791 -2.773 -2.754 -2.736 -2.717
-2.699 -2.680 -2.661 -2.643 -2.624 -2.605 -2.586 -2.567 -2.549 -2.530
-2.511 -2.492 -2.473 -2.454 -2.435 -2.416 -2.397 -2.377 -2.358 -2.339
-2.320 -2.300 -2.281 -2.262 -2.243 -2.223 -2.204 -2.184 -2.165 -2.145
-2.126 -2.106 -2.087 -2.067 -2.047 -2.028 -2.008 -1.988 -1.968 -1.949
-1.929 -1.909 -1.889 -1.869 -1.849 -1.829 -1.809 -1.789 -1.769 -1.749
-1.729 -1.709 -1.689 -1.669 -1.648 -1.628 -1.608 -1.588 -1.567 -1.547
-1.527 -1.506 -1.486 -1.465 -1.445 -1.424 -1.404 -1.383 -1.363 -1.342
-1.322 -1.301 -1.280 -1.260 -1.239 -1.218 -1.197 -1.177 -1.156 -1.135
-1.114 -1.093 -1.072 -1.051 -1.031 -1.010 -0.989 -0.968 -0.946 -0.925
-0.904 -0.883 -0.862 -0.841 -0.820 -0.799 -0.777 -0.756 -0.735 -0.714
-0.692 -0.671 -0.650 -0.628 -0.607 -0.585 -0.564 -0.543 -0.521 -0.500
-0.478 -0.457 -0.435 -0.413 -0.392 -0.370 -0.349 -0.327 -0.305 -0.284
-0.262 -0.240 -0.218 -0.197 -0.175 -0.153 -0.131 -0.109 -0.088 -0.066
-0.044 -0.022 0.000 0.022 0.044 0.066 0.088 0.110 0.132 0.154
0.176 0.198 0.220 0.242 0.264 0.286 0.308 0.331 0.353 0.375
0.397 0.419 0.441 0.464 0.486 0.508 0.530 0.553 0.575 0.597
0.619 0.642 0.664 0.686 0.709 0.731 0.753 0.776 0.798 0.821
0.843 0.865 0.888 0.910 0.933 0.955 0.978 1.000 1.023 1.045
1.068 1.090 1.113 1.135 1.158 1.181 1.203 1.226 1.248 1.271
1.294 1.316 1.339 1.362 1.384 1.407 1.430 1.452 1.475 1.498
1.520 1.543 1.566 1.589 1.611 1.634 1.657 1.680 1.703 1.725
1.748 1.771 1.794 1.817 1.839 1.862 1.885 1.908 1.931 1.954
1.977 2.000 2.022 2.045 2.068 2.091 2.114 2.137 2.160 2.183
2.206 2.229 2.252 2.275 2.298 2.321 2.344 2.367 2.390 2.413
2.436 2.459 2.482 2.505 2.528 2.551 2.574 2.597 2.620 2.643
2.666 2.689 2.712 2.735 2.758 2.781 2.804 2.827 2.850 2.873
2.896 2.920 2.943 2.966 2.989 3.012 3.035 3.058 3.081 3.104
3.127 3.150 3.173 3.196 3.220 3.243 3.266 3.289 3.312 3.335
3.358 3.381 3.404 3.427 3.450 3.473 3.496 3.519 3.543 3.566
3.589 3.612 3.635 3.658 3.681 3.704 3.727 3.750 3.773 3.796
3.819 3.842 3.865 3.888 3.911 3.934 3.957 3.980 4.003 4.026
4.049 4.072 4.095 4.118 4.141 4.164 4.187 4.210 4.233 4.256
4.279 4.302 4.325 4.348 4.371 4.394 4.417 4.439 4.462 4.485
4.508 4.531 4.554 4.577 4.600 4.622 4.645 4.668 4.691 4.714
4.737 4.759 4.782 4.805 4.828 4.851 4.873 4.896 4.919 4.942
4.964 4.987 5.010 5.033 5.055 5.078 5.101 5.124 5.146 5.169
5.192 5.214 5.237 5.260 5.282 5.305 5.327 5.350 5.373 5.395
5.418 5.440 5.463 5.486 5.508 5.531 5.553 5.576 5.598 5.621
5.643 5.666 5.688 5.711 5.733 5.756 5.778 5.801 5.823 5.846
5.868 5.891 5.913 5.936 5.958 5.980 6.003 6.025 6.048 6.070
6.092 6.115 6.137 6.160 6.182 6.204 6.227 6.249 6.271 6.294
6.316 6.338 6.361 6.383 6.405 6.428 6.450 6.472 6.494 6.517
6.539 6.561 6.583 6.606 6.628 6.650 6.672 6.695 6.717 6.739
6.761 6.784 6.806 6.828 6.850 6.873 6.895 6.917 6.939 6.961
6.984 7.006 7.028 7.050 7.072 7.094 7.117 7.139 7.161 7.183
7.205 7.228 7.250 7.272 7.294 7.316 7.338 7.361 7.383 7.405
7.427 7.449 7.471 7.494 7.516 7.538 7.560 7.582 7.604 7.627
7.649 7.671 7.693 7.715 7.737 7.760 7.782 7.804 7.826 7.848
7.870 7.893 7.915 7.937 7.959 7.981 8.003 8.026 8.048 8.070
8.092 8.114 8.137 8.159 8.181 8.203 8.225 8.248 8.270 8.292
8.314 8.336 8.359 8.381 8.403 8.425 8.448 8.470 8.492 8.514
8.537 8.559 8.581 8.603 8.626 8.648 8.670 8.692 8.715 8.737
8.759 8.782 8.804 8.826 8.849 8.871 8.893 8.916 8.938 8.960
8.983 9.005 9.027 9.050 9.072 9.094 9.117 9.139 9.161 9.184
9.206 9.229 9.251 9.273 9.296 9.318 9.341 9.363 9.385 9.408
9.430 9.453 9.475 9.498 9.520 9.543 9.565 9.588 9.610 9.633
9.655 9.678 9.700 9.723 9.745 9.768 9.790 9.813 9.835 9.858
9.880 9.903 9.926 9.948 9.971 9.993 10.016 10.038 10.061 10.084
10.106 10.129 10.151 10.174 10.197 10.219 10.242 10.265 10.287 10.310
10.333 10.355 10.378 10.401 10.423 10.446 10.469 10.491 10.514 10.537
10.560 10.582 10.605 10.628 10.650 10.673 10.696 10.719 10.741 10.764
10.787 10.810 10.833 10.855 10.878 10.901 10.924 10.947 10.969 10.992
11.015 11.038 11.061 11.083 11.106 11.129 11.152 11.175 11.198 11.221
11.243 11.266 11.289 11.312 11.335 11.358 11.381 11.404 11.426 11.449
11.472 11.495 11.518 11.541 11.564 11.587 11.610 11.633 11.656 11.679
11.702 11.725 11.748 11.770 11.793 11.816 11.839 11.862 11.885 11.908
11.931 11.954 11.977 12.000 12.023 12.046 12.069 12.092 12.115 12.138
12.161 12.184 12.207 12.230 12.254 12.277 12.300 12.323 12.346 12.369
12.392 12.415 12.438 12.461 12.484 12.507 12.530 12.553 12.576 12.599
12.623 12.646 12.669 12.692 12.715 12.738 12.761 12.784 12.807 12.831
12.854 12.877 12.900 12.923 12.946 12.969 12.992 13.016 13.039 13.062
13.085 13.108 13.131 13.154 13.178 13.201 13.224 13.247 13.270 13.293
13.317 13.340 13.363 13.386 13.409 13.433 13.456 13.479 13.502 13.525
13.549 13.572 13.595 13.618 13.641 13.665 13.688 13.711 13.734 13.757
13.781 13.804 13.827 13.850 13.874 13.897 13.920 13.943 13.967 13.990
14.013 14.036 14.060 14.083 14.106 14.129 14.153 14.176 14.199 14.222
14.246 14.269 14.292 14.316 14.339 14.362 14.385 14.409 14.432 14.455
14.479 14.502 14.525 14.548 14.572 14.595 14.618 14.642 14.665 14.688
14.712 14.735 14.758 14.782 14.805 14.828 14.852 14.875 14.898 14.922
14.945 14.968 14.992 15.015 15.038 15.062 15.085 15.108 15.132 15.155
15.178 15.202 15.225 15.248 15.272 15.295 15.318 15.342 15.365 15.389
15.412 15.435 15.459 15.482 15.505 15.529 15.552 15.576 15.599 15.622
15.646 15.669 15.693 15.716 15.739 15.763 15.786 15.810 15.833 15.856
15.880 15.903 15.927 15.950 15.974 15.997 16.020 16.044 16.067 16.091
16.114 16.138 16.161 16.184 16.208 16.231 16.255 16.278 16.302 16.325
16.349 16.372 16.395 16.419 16.442 16.466 16.489 16.513 16.536 16.560
16.583 16.607 16.630 16.654 16.677 16.700 16.724 16.747 16.771 16.794
16.818 16.841 16.865 16.888 16.912 16.935 16.959 16.982 17.006 17.029
17.053 17.076 17.100 17.123 17.147 17.170 17.194 17.217 17.241 17.264
17.288 17.311 17.335 17.358 17.382 17.406 17.429 17.453 17.476 17.500
17.523 17.547 17.570 17.594 17.617 17.641 17.664 17.688 17.711 17.735
17.759 17.782 17.806 17.829 17.853 17.876 17.900 17.923 17.947 17.971
17.994 18.018 18.041 18.065 18.088 18.112 18.136 18.159 18.183 18.206
18.230 18.253 18.277 18.301 18.324 18.348 18.371 18.395 18.418 18.442
18.466 18.489 18.513 18.536 18.560 18.584 18.607 18.631 18.654 18.678
18.702 18.725 18.749 18.772 18.796 18.820 18.843 18.867 18.890 18.914
18.938 18.961 18.985 19.008 19.032 19.056 19.079 19.103 19.127 19.150
19.174 19.197 19.221 19.245 19.268 19.292 19.316 19.339 19.363 19.386
19.410 19.434 19.457 19.481 19.505 19.528 19.552 19.576 19.599 19.623
19.646 19.670 19.694 19.717 19.741 19.765 19.788 19.812 19.836 19.859
19.883 19.907 19.930 19.954 19.978 20.001 20.025 20.049 20.072 20.096
20.120 20.143 20.167 20.190 20.214 20.238 20.261 20.285 20.309 20.332
20.356 20.380 20.403 20.427 20.451 20.474 20.498 20.522 20.545 20.569
20.593 20.616 20.640 20.664 20.688 20.711 20.735 20.759 20.782 20.806
20.830 20.853 20.877 20.901 20.924 20.948 20.972 20.995 21.019 21.043
21.066 21.090 21.114 21.137 21.161 21.185 21.208 21.232 21.256 21.280
21.303 21.327 21.351 21.374 21.398 21.422 21.445 21.469 21.493 21.516
21.540 21.564 21.587 21.611 21.635 21.659 21.682 21.706 21.730 21.753
21.777 21.801 21.824 21.848 21.872 21.895 21.919 21.943 21.966 21.990
22.014 22.038 22.061 22.085 22.109 22.132 22.156 22.180 22.203 22.227
22.251 22.274 22.298 22.322 22.346 22.369 22.393 22.417 22.440 22.464
22.488 22.511 22.535 22.559 22.582 22.606 22.630 22.654 22.677 22.701
22.725 22.748 22.772 22.796 22.819 22.843 22.867 22.890 22.914 22.938
22.961 22.985 23.009 23.032 23.056 23.080 23.104 23.127 23.151 23.175
23.198 23.222 23.246 23.269 23.293 23.317 23.340 23.364 23.388 23.411
23.435 23.459 23.482 23.506 23.530 23.553 23.577 23.601 23.624 23.648
23.672 23.695 23.719 23.743 23.766 23.790 23.814 23.837 23.861 23.885
23.908 23.932 23.956 23.979 24.003 24.027 24.050 24.074 24.098 24.121
24.145 24.169 24.192 24.216 24.240 24.263 24.287 24.311 24.334 24.358
24.382 24.405 24.429 24.453 24.476 24.500 24.523 24.547 24.571 24.594
24.618 24.642 24.665 24.689 24.713 24.736 24.760 24.783 24.807 24.831
24.854 24.878 24.902 24.925 24.949 24.972 24.996 25.020 25.043 25.067
25.091 25.114 25.138 25.161 25.185 25.209 25.232 25.256 25.279 25.303
25.327 25.350 25.374 25.397 25.421 25.445 25.468 25.492 25.515 25.539
25.563 25.586 25.610 25.633 25.657 25.681 25.704 25.728 25.751 25.775
25.799 25.822 25.846 25.869 25.893 25.916 25.940 25.964 25.987 26.011
26.034 26.058 26.081 26.105 26.128 26.152 26.176 26.199 26.223 26.246
26.270 26.293 26.317 26.340 26.364 26.387 26.411 26.435 26.458 26.482
26.505 26.529 26.552 26.576 26.599 26.623 26.646 26.670 26.693 26.717
26.740 26.764 26.787 26.811 26.834 26.858 26.881 26.905 26.928 26.952
26.975 26.999 27.022 27.046 27.069 27.093 27.116 27.140 27.163 27.187
27.210 27.234 27.257 27.281 27.304 27.328 27.351 27.375 27.398 27.422
27.445 27.468 27.492 27.515 27.539 27.562 27.586 27.609 27.633 27.656
27.679 27.703 27.726 27.750 27.773 27.797 27.820 27.843 27.867 27.890
27.914 27.937 27.961 27.984 28.007 28.031 28.054 28.078 28.101 28.124
28.148 28.171 28.195 28.218 28.241 28.265 28.288 28.311 28.335 28.358
28.382 28.405 28.428 28.452 28.475 28.498 28.522 28.545 28.569 28.592
28.615 28.639 28.662 28.685 28.709 28.732 28.755 28.779 28.802 28.825
28.849 28.872 28.895 28.919 28.942 28.965 28.988 29.012 29.035 29.058
29.082 29.105 29.128 29.152 29.175 29.198 29.221 29.245 29.268 29.291
29.315 29.338 29.361 29.384 29.408 29.431 29.454 29.477 29.501 29.524
29.547 29.570 29.594 29.617 29.640 29.663 29.687 29.710 29.733 29.756
29.780 29.803 29.826 29.849 29.872 29.896 29.919 29.942 29.965 29.989
30.012 30.035 30.058 30.081 30.104 30.128 30.151 30.174 30.197 30.220
30.244 30.267 30.290 30.313 30.336 30.359 30.383 30.406 30.429 30.452
30.475 30.498 30.521 30.545 30.568 30.591 30.614 30.637 30.660 30.683
30.706 30.730 30.753 30.776 30.799 30.822 30.845 30.868 30.891 30.914
30.937 30.961 30.984 31.007 31.030 31.053 31.076 31.099 31.122 31.145
31.168 31.191 31.214 31.237 31.260 31.283 31.306 31.329 31.353 31.376
31.399 31.422 31.445 31.468 31.491 31.514 31.537 31.560 31.583 31.606
31.629 31.652 31.675 31.698 31.721 31.744 31.767 31.790 31.813 31.836
31.859 31.882 31.905 31.927 31.950 31.973 31.996 32.019 32.042 32.065
32.088 32.111 32.134 32.157 32.180 32.203 32.226 32.249 32.272 32.294
32.317 32.340 32.363 32.386 32.409 32.432 32.455 32.478 32.501 32.523
32.546 32.569 32.592 32.615 32.638 32.661 32.683 32.706 32.729 32.752
32.775 32.798 32.821 32.843 32.866 32.889 32.912 32.935 32.958 32.980
33.003 33.026 33.049 33.072 33.094 33.117 33.140 33.163 33.186 33.208
33.231 33.254 33.277 33.300 33.322 33.345 33.368 33.391 33.413 33.436
33.459 33.482 33.504 33.527 33.550 33.573 33.595 33.618 33.641 33.664
33.686 33.709 33.732 33.754 33.777 33.800 33.823 33.845 33.868 33.891
33.913 33.936 33.959 33.981 34.004 34.027 34.049 34.072 34.095 34.117
34.140 34.163 34.185 34.208 34.231 34.253 34.276 34.299 34.321 34.344
34.366 34.389 34.412 34.434 34.457 34.480 34.502 34.525 34.547 34.570
34.593 34.615 34.638 34.660 34.683 34.705 34.728 34.751 34.773 34.796
34.818 34.841 34.863 34.886 34.909 34.931 34.954 34.976 34.999 35.021
35.044 35.066 35.089 35.111 35.134 35.156 35.179 35.201 35.224 35.246
35.269 35.291 35.314 35.336 35.359 35.381 35.404 35.426 35.449 35.471
35.494 35.516 35.539 35.561 35.583 35.606 35.628 35.651 35.673 35.696
35.718 35.741 35.763 35.785 35.808 35.830 35.853 35.875 35.897 35.920
35.942 35.965 35.987 36.009 36.032 36.054 36.077 36.099 36.121 36.144
36.166 36.188 36.211 36.233 36.256 36.278 36.300 36.323 36.345 36.367
36.390 36.412 36.434 36.457 36.479 36.501 36.524 36.546 36.568 36.590
36.613 36.635 36.657 36.680 36.702 36.724 36.746 36.769 36.791 36.813
36.836 36.858 36.880 36.902 36.925 36.947 36.969 36.991 37.014 37.036
37.058 37.080 37.103 37.125 37.147 37.169 37.191 37.214 37.236 37.258
37.280 37.303 37.325 37.347 37.369 37.391 37.413 37.436 37.458 37.480
37.502 37.524 37.547 37.569 37.591 37.613 37.635 37.657 37.679 37.702
37.724 37.746 37.768 37.790 37.812 37.834 37.857 37.879 37.901 37.923
37.945 37.967 37.989 38.011 38.033 38.055 38.078 38.100 38.122 38.144
38.166 38.188 38.210 38.232 38.254 38.276 38.298 38.320 38.342 38.364
38.387 38.409 38.431 38.453 38.475 38.497 38.519 38.541 38.563 38.585
38.607 38.629 38.651 38.673 38.695 38.717 38.739 38.761 38.783 38.805
38.827 38.849 38.871 38.893 38.915 38.937 38.959 38.981 39.003 39.024
39.046 39.068 39.090 39.112 39.134 39.156 39.178 39.200 39.222 39.244
39.266 39.288 39.310 39.331 39.353 39.375 39.397 39.419 39.441 39.463
39.485 39.507 39.529 39.550 39.572 39.594 39.616 39.638 39.660 39.682
39.703 39.725 39.747 39.769 39.791 39.813 39.835 39.856 39.878 39.900
39.922 39.944 39.965 39.987 40.009 40.031 40.053 40.075 40.096 40.118
40.140 40.162 40.183 40.205 40.227 40.249 40.271 40.292 40.314 40.336
40.358 40.379 40.401 40.423 40.445 40.466 40.488 40.510 40.532 40.553
40.575 40.597 40.619 40.640 40.662 40.684 40.705 40.727 40.749 40.770
40.792 40.814 40.836 40.857 40.879 40.901 40.922 40.944 40.966 40.987
41.009 41.031 41.052 41.074 41.096 41.117 41.139 41.161 41.182 41.204
41.225 41.247 41.269 41.290 41.312 41.334 41.355 41.377 41.398 41.420
41.442 41.463 41.485 41.506 41.528 41.550 41.571 41.593 41.614 41.636
41.657 41.679 41.701 41.722 41.744 41.765 41.787 41.808 41.830 41.851
41.873 41.895 41.916 41.938 41.959 41.981 42.002 42.024 42.045 42.067
42.088 42.110 42.131 42.153 42.174 42.196 42.217 42.239 42.260 42.282
42.303 42.325 42.346 42.367 42.389 42.410 42.432 42.453 42.475 42.496
42.518 42.539 42.560 42.582 42.603 42.625 42.646 42.668 42.689 42.710
42.732 42.753 42.775 42.796 42.817 42.839 42.860 42.882 42.903 42.924
42.946 42.967 42.989 43.010 43.031 43.053 43.074 43.095 43.117 43.138
43.159 43.181 43.202 43.223 43.245 43.266 43.287 43.309 43.330 43.351
43.373 43.394 43.415 43.436 43.458 43.479 43.500 43.522 43.543 43.564
43.585 43.607 43.628 43.649 43.671 43.692 43.713 43.734 43.756 43.777
43.798 43.819 43.841 43.862 43.883 43.904 43.925 43.947 43.968 43.989
44.010 44.031 44.053 44.074 44.095 44.116 44.137 44.159 44.180 44.201
44.222 44.243 44.265 44.286 44.307 44.328 44.349 44.370 44.391 44.413
44.434 44.455 44.476 44.497 44.518 44.539 44.560 44.582 44.603 44.624
44.645 44.666 44.687 44.708 44.729 44.750 44.771 44.793 44.814 44.835
44.856 44.877 44.898 44.919 44.940 44.961 44.982 45.003 45.024 45.045
45.066 45.087 45.108 45.129 45.150 45.171 45.192 45.213 45.234 45.255
45.276 45.297 45.318 45.339 45.360 45.381 45.402 45.423 45.444 45.465
45.486 45.507 45.528 45.549 45.570 45.591 45.612 45.633 45.654 45.675
45.695 45.716 45.737 45.758 45.779 45.800 45.821 45.842 45.863 45.884
45.904 45.925 45.946 45.967 45.988 46.009 46.030 46.051 46.071 46.092
46.113 46.134 46.155 46.176 46.196 46.217 46.238 46.259 46.280 46.300
46.321 46.342 46.363 46.384 46.404 46.425 46.446 46.467 46.488 46.508
46.529 46.550 46.571 46.591 46.612 46.633 46.654 46.674 46.695 46.716
46.737 46.757 46.778 46.799 46.819 46.840 46.861 46.881 46.902 46.923
46.944 46.964 46.985 47.006 47.026 47.047 47.068 47.088 47.109 47.130
47.150 47.171 47.191 47.212 47.233 47.253 47.274 47.295 47.315 47.336
47.356 47.377 47.398 47.418 47.439 47.459 47.480 47.500 47.521 47.542
47.562 47.583 47.603 47.624 47.644 47.665 47.685 47.706 47.726 47.747
47.767 47.788 47.808 47.829 47.849 47.870 47.890 47.911 47.931 47.952
47.972 47.993 48.013 48.034 48.054 48.075 48.095 48.116 48.136 48.156
48.177 48.197 48.218 48.238 48.258 48.279 48.299 48.320 48.340 48.360
48.381 48.401 48.422 48.442 48.462 48.483 48.503 48.523 48.544 48.564
48.584 48.605 48.625 48.645 48.666 48.686 48.706 48.727 48.747 48.767
48.787 48.808 48.828 48.848 48.869 48.889 48.909 48.929 48.950 48.970
48.990 49.010 49.031 49.051 49.071 49.091 49.111 49.132 49.152 49.172
49.192 49.212 49.233 49.253 49.273 49.293 49.313 49.333 49.354 49.374
49.394 49.414 49.434 49.454 49.474 49.495 49.515 49.535 49.555 49.575
49.595 49.615 49.635 49.655 49.675 49.696 49.716 49.736 49.756 49.776
49.796 49.816 49.836 49.856 49.876 49.896 49.916 49.936 49.956 49.976
49.996 50.016 50.036 50.056 50.076 50.096 50.116 50.136 50.156 50.176
50.196 50.216 50.236 50.256 50.276 50.296 50.315 50.335 50.355 50.375
50.395 50.415 50.435 50.455 50.475 50.494 50.514 50.534 50.554 50.574
50.594 50.614 50.633 50.653 50.673 50.693 50.713 50.733 50.752 50.772
50.792 50.812 50.832 50.851 50.871 50.891 50.911 50.930 50.950 50.970
50.990 51.009 51.029 51.049 51.069 51.088 51.108 51.128 51.148 51.167
51.187 51.207 51.226 51.246 51.266 51.285 51.305 51.325 51.344 51.364
51.384 51.403 51.423 51.443 51.462 51.482 51.501 51.521 51.541 51.560
51.580 51.599 51.619 51.639 51.658 51.678 51.697 51.717 51.736 51.756
51.776 51.795 51.815 51.834 51.854 51.873 51.893 51.912 51.932 51.951
51.971 51.990 52.010 52.029 52.049 52.068 52.088 52.107 52.127 52.146
52.165 52.185 52.204 52.224 52.243 52.263 52.282 52.301 52.321 52.340
52.360 52.379 52.398 52.418 52.437 52.457 52.476 52.495 52.515 52.534
52.553 52.573 52.592 52.611 52.631 52.650 52.669 52.689 52.708 52.727
52.747 52.766 52.785 52.805 52.824 52.843 52.862 52.882 52.901 52.920
52.939 52.959 52.978 52.997 53.016 53.036 53.055 53.074 53.093 53.113
53.132 53.151 53.170 53.189 53.209 53.228 53.247 53.266 53.285 53.304
53.324 53.343 53.362 53.381 53.400 53.419 53.439 53.458 53.477 53.496
53.515 53.534 53.553 53.572 53.592 53.611 53.630 53.649 53.668 53.687
53.706 53.725 53.744 53.763 53.782 53.801 53.821 53.840 53.859 53.878
53.897 53.916 53.935 53.954 53.973 53.992 54.011 54.030 54.049 54.068
54.087 54.106 54.125 54.144 54.163 54.182 54.201 54.220 54.239 54.258
54.277 54.296 54.315 54.334 54.353 54.372 54.391 54.410 54.429 54.447
54.466 54.485 54.504 54.523 54.542 54.561 54.580 54.599 54.618 54.637
54.656 54.675 54.694 54.712 54.731 54.750 54.769 54.788 54.807 54.826
54.845
+37
View File
@@ -0,0 +1,37 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Breakpoint Tables
*
* Author: Marty Kraimer
* Date: 11-7-90
*/
#ifndef INCcvtTableh
#define INCcvtTableh 1
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Global Routines*/
epicsShareFunc long cvtEngToRawBpt(
double *pval,short linr,short init,void **ppbrk,short *plbrk);
epicsShareFunc long cvtRawToEngBpt(
double *pval,short linr,short init,void **ppbrk, short *plbrk);
#ifdef __cplusplus
}
#endif
#endif
+427
View File
@@ -0,0 +1,427 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Marty Kraimer
* Date: 9/28/95
* Replacement for old bldCvtTable
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "dbDefs.h"
#include "ellLib.h"
#include "cvtTable.h"
#define MAX_LINE_SIZE 160
#define MAX_BREAKS 100
struct brkCreateInfo {
double engLow; /* Lowest value desired: engineering units */
double engHigh; /* Highest value desired: engineering units */
double rawLow; /* Raw value for EngLow */
double rawHigh; /* Raw value for EngHigh */
double accuracy; /* accuracy desired in engineering units */
double tblEngFirst;/* First table value: engineering units */
double tblEngLast; /* Last table value: engineering units */
double tblEngDelta;/* Change per table entry: eng units */
long nTable; /* number of table entries */
/* (last-first)/delta + 1 */
double *pTable; /* addr of data table */
} brkCreateInfo;
typedef struct brkInt { /* breakpoint interval */
double raw; /* raw value for beginning of interval */
double slope; /* slope for interval */
double eng; /* converted value for beginning of interval */
} brkInt;
brkInt brkint[MAX_BREAKS];
static int create_break(struct brkCreateInfo *pbci, brkInt *pabrkInt,
int max_breaks, int *n_breaks);
static char inbuf[MAX_LINE_SIZE];
static int linenum=0;
typedef struct dataList{
struct dataList *next;
double value;
}dataList;
static int getNumber(char **pbeg, double *value)
{
int nchars=0;
while(isspace((int)**pbeg) && **pbeg!= '\0') (*pbeg)++;
if(**pbeg == '!' || **pbeg == '\0') return(-1);
if(sscanf(*pbeg,"%lf%n",value,&nchars)!=1) return(-1);
*pbeg += nchars;
return(0);
}
static void errExit(char *pmessage)
{
fprintf(stderr, "%s\n", pmessage);
fflush(stderr);
exit(-1);
}
int main(int argc, char **argv)
{
char *pbeg;
char *pend;
double value;
char *pname = NULL;
dataList *phead;
dataList *pdataList;
dataList *pnext;
double *pdata;
long ndata;
int nBreak,n;
size_t len;
char *outFilename;
char *pext;
FILE *outFile;
FILE *inFile;
char *plastSlash;
if(argc<2) {
fprintf(stderr,"usage: makeBpt file.data [outfile]\n");
exit(-1);
}
if (argc==2) {
plastSlash = strrchr(argv[1],'/');
plastSlash = (plastSlash ? plastSlash+1 : argv[1]);
outFilename = calloc(1,strlen(plastSlash)+2);
if(!outFilename) {
fprintf(stderr,"calloc failed\n");
exit(-1);
}
strcpy(outFilename,plastSlash);
pext = strstr(outFilename,".data");
if(!pext) {
fprintf(stderr,"Input file MUST have .data extension\n");
exit(-1);
}
strcpy(pext,".dbd");
} else {
outFilename = calloc(1,strlen(argv[2])+1);
if(!outFilename) {
fprintf(stderr,"calloc failed\n");
exit(-1);
}
strcpy(outFilename,argv[2]);
}
inFile = fopen(argv[1],"r");
if(!inFile) {
fprintf(stderr,"Error opening %s\n",argv[1]);
exit(-1);
}
outFile = fopen(outFilename,"w");
if(!outFile) {
fprintf(stderr,"Error opening %s\n",outFilename);
exit(-1);
}
while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {
linenum++;
pbeg = inbuf;
while(isspace((int)*pbeg) && *pbeg!= '\0') pbeg++;
if(*pbeg == '!' || *pbeg == '\0') continue;
while(*pbeg!='"' && *pbeg!= '\0') pbeg++;
if(*pbeg!='"' ) errExit("Illegal Header");
pbeg++; pend = pbeg;
while(*pend!='"' && *pend!= '\0') pend++;
if(*pend!='"') errExit("Illegal Header");
len = pend - pbeg;
if(len<=1) errExit("Illegal Header");
pname = calloc(len+1,sizeof(char));
if(!pname) {
fprintf(stderr,"calloc failed while processing line %d\n",linenum);
exit(-1);
}
strncpy(pname,pbeg,len);
pname[len]='\0';
pbeg = pend + 1;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.engLow = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.rawLow = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.engHigh = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.rawHigh = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.accuracy = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.tblEngFirst = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.tblEngLast = value;
if(getNumber(&pbeg,&value)) errExit("Illegal Header");
brkCreateInfo.tblEngDelta = value;
goto got_header;
}
errExit("Illegal Header");
got_header:
phead = pnext = 0;
ndata = 0;
errno = 0;
while(fgets(inbuf,MAX_LINE_SIZE,inFile)) {
double value;
linenum++;
pbeg = inbuf;
while(!getNumber(&pbeg,&value)) {
ndata++;
pdataList = (dataList *)calloc(1,sizeof(dataList));
if(!pdataList) {
fprintf(stderr,"calloc failed (after header)"
" while processing line %d\n",linenum);
exit(-1);
}
if(!phead)
phead = pdataList;
else
pnext->next = pdataList;
pdataList->value = value;
pnext = pdataList;
}
}
if(!pname) {
errExit("create_break failed: no name specified\n");
}
brkCreateInfo.nTable = ndata;
pdata = (double *)calloc(brkCreateInfo.nTable,sizeof(double));
if(!pdata) {
fprintf(stderr,"calloc failed for table length %ld\n",brkCreateInfo.nTable);
exit(-1);
}
pnext = phead;
for(n=0; n<brkCreateInfo.nTable; n++) {
pdata[n] = pnext->value;
pdataList = pnext;
pnext = pnext->next;
free((void *)pdataList);
}
brkCreateInfo.pTable = pdata;
if(create_break(&brkCreateInfo,&brkint[0],MAX_BREAKS,&nBreak))
errExit("create_break failed\n");
fprintf(outFile,"breaktable(%s) {\n",pname);
for(n=0; n<nBreak; n++) {
fprintf(outFile,"\t%f %f\n",brkint[n].raw,brkint[n].eng);
}
fprintf(outFile,"}\n");
fclose(inFile);
fclose(outFile);
return(0);
}
static int create_break( struct brkCreateInfo *pbci, brkInt *pabrkInt,
int max_breaks, int *n_breaks)
{
brkInt *pbrkInt;
double *table = pbci->pTable;
long ntable = pbci->nTable;
double ilow,
ihigh,
tbllow,
tblhigh,
slope,
offset;
int ibeg,
iend,
i,
inc,
imax,
n;
double rawBeg,
engBeg,
rawEnd,
engEnd,
engCalc,
engActual,
error;
int valid,
all_ok,
expanding;
/* make checks to ensure that brkCreateInfo makes sense */
if (pbci->engLow >= pbci->engHigh) {
errExit("create_break: engLow >= engHigh");
return (-1);
}
if ((pbci->engLow < pbci->tblEngFirst)
|| (pbci->engHigh > pbci->tblEngLast)) {
errExit("create_break: engLow > engHigh");
return (-1);
}
if (pbci->tblEngDelta <= 0.0) {
errExit("create_break: tblEngDelta <= 0.0");
return (-1);
}
if (ntable < 3) {
errExit("raw data must have at least 3 elements");
return (-1);
}
/***************************************************************************
Convert Table to raw values
*
* raw and table values are assumed to be related by an equation of the form:
*
* raw = slope*table + offset
*
* The following algorithm converts each table value to raw units
*
* 1) Finds the locations in Table corresponding to engLow and engHigh
* Note that these locations need not be exact integers
* 2) Interpolates to obtain table values corresponding to engLow and enghigh
* we now have the equations:
* rawLow = slope*tblLow + offset
* rawHigh = slope*tblHigh + offset
* 4) Solving these equations for slope and offset gives:
* slope=(rawHigh-rawLow)/(tblHigh-tblLow)
* offset=rawHigh-slope*tblHigh
* 5) for each table value set table[i]=table[i]*slope+offset
*************************************************************************/
/* Find engLow in Table and then compute tblLow */
ilow = (pbci->engLow - pbci->tblEngFirst) / (pbci->tblEngDelta);
i = (int) ilow;
if (i >= ntable - 1)
i = ntable - 2;
tbllow = table[i] + (table[i + 1] - table[i]) * (ilow - (double) i);
/* Find engHigh in Table and then compute tblHigh */
ihigh = (pbci->engHigh - pbci->tblEngFirst) / (pbci->tblEngDelta);
i = (int) ihigh;
if (i >= ntable - 1)
i = ntable - 2;
tblhigh = table[i] + (table[i + 1] - table[i]) * (ihigh - (double) i);
/* compute slope and offset */
slope = (pbci->rawHigh - pbci->rawLow) / (tblhigh - tbllow);
offset = pbci->rawHigh - slope * tblhigh;
/* convert table to raw units */
for (i = 0; i < ntable; i++)
table[i] = table[i] * slope + offset;
/*****************************************************************************
* Now create break point table
*
* The algorithm does the following:
*
* It finds one breakpoint interval at a time. For each it does the following:
*
* 1) Use a relatively large portion of the remaining table as an interval
* 2) It attempts to use the entire interval as a breakpoint interval
* Success is determined by the following algorithm:
* a) compute the slope using the entire interval
* b) for each table entry in the interval determine the eng value
* using the slope just determined.
* c) compare the computed value with eng value associated with table
* d) if all table entries are within the accuracy desired then success.
* 3) If successful then attempt to expand the interval and try again.
* Note that it is expanded by up to 1/10 of the table size.
* 4) If not successful reduce the interval by 1 and try again.
* Once the interval is being decreased it will never be increased again.
* 5) The algorithm will ultimately fail or will have determined the optimum
* breakpoint interval
*************************************************************************/
/* Must start with table entry corresponding to engLow; */
i = (int) ilow;
if (i >= ntable - 1)
i = ntable - 2;
rawBeg = table[i] + (table[i + 1] - table[i]) * (ilow - (double) i);
engBeg = pbci->engLow;
ibeg = (int) (ilow); /* Make sure that ibeg > ilow */
if( ibeg < ilow ) ibeg = ibeg + 1;
/* start first breakpoint interval */
n = 1;
pbrkInt = pabrkInt;
pbrkInt->raw = rawBeg;
pbrkInt->eng = engBeg;
/* determine next breakpoint interval */
while ((engBeg <= pbci->engHigh) && (ibeg < ntable - 1)) {
/* determine next interval to try. Up to 1/10 full range */
rawEnd = rawBeg;
engEnd = engBeg;
iend = ibeg;
inc = (int) ((ihigh - ilow) / 10.0);
if (inc < 1)
inc = 1;
valid = TRUE;
/* keep trying intervals until cant do better */
expanding = TRUE; /* originally we are trying larger and larger
* intervals */
while (valid) {
imax = iend + inc;
if (imax >= ntable) {
/* don't go past end of table */
imax = ntable - 1;
inc = ntable - iend - 1;
expanding = FALSE;
}
if (imax > (int) (ihigh + 1.0)) { /* Don't go to far past
* engHigh */
imax = (int) (ihigh + 1.0);
inc = (int) (ihigh + 1.0) - iend;
expanding = FALSE;
}
if (imax <= ibeg)
break; /* failure */
rawEnd = table[imax];
engEnd = pbci->tblEngFirst + (double) imax *(pbci->tblEngDelta);
slope = (engEnd - engBeg) / (rawEnd - rawBeg);
all_ok = TRUE;
for (i = ibeg + 1; i <= imax; i++) {
engCalc = engBeg + slope * (table[i] - rawBeg);
engActual = pbci->tblEngFirst + ((double) i) * (pbci->tblEngDelta);
error = engCalc - engActual;
if (error < 0.0)
error = -error;
if (error >= pbci->accuracy) {
/* we will be trying smaller intervals */
expanding = FALSE;
/* just decrease inc and let while(valid) try again */
inc--;
all_ok = FALSE;
break;
}
} /* end for */
if (all_ok) {
iend = imax;
/* if not expanding we found interval */
if (!expanding)
break;
/* will automatically try larger interval */
}
} /* end while(valid) */
/* either we failed or optimal interval has been found */
if ((iend <= ibeg) && (iend < (int) ihigh)) {
errExit("Could not meet accuracy criteria");
return (-1);
}
pbrkInt->slope = slope;
/* get ready for next breakpoint interval */
if (n++ >= max_breaks) {
errExit("Break point table too large");
return (-1);
}
ibeg = iend;
pbrkInt++;
rawBeg = rawEnd;
engBeg = engEnd;
pbrkInt->raw = rawBeg;
pbrkInt->eng = engBeg + (pbrkInt->raw - rawBeg) * slope;
}
pbrkInt->slope = 0.0;
*n_breaks = n;
return (0);
}
@@ -0,0 +1,38 @@
#*************************************************************************
# Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Menu menuConvert
This menu defines the standard analog conversions which are included with Base.
IOC applications may add choices or replace the later choices in this menu,
although the first three choices must not be renamed or moved to different
positions. The breakpoint table name must exactly match the choice string
listed here.
=menu menuConvert
=cut
menu(menuConvert) {
choice(menuConvertNO_CONVERSION,"NO CONVERSION")
choice(menuConvertSLOPE,"SLOPE")
choice(menuConvertLINEAR,"LINEAR")
choice(menuConverttypeKdegF,"typeKdegF")
choice(menuConverttypeKdegC,"typeKdegC")
choice(menuConverttypeJdegF,"typeJdegF")
choice(menuConverttypeJdegC,"typeJdegC")
choice(menuConverttypeEdegF,"typeEdegF(ixe only)")
choice(menuConverttypeEdegC,"typeEdegC(ixe only)")
choice(menuConverttypeTdegF,"typeTdegF")
choice(menuConverttypeTdegC,"typeTdegC")
choice(menuConverttypeRdegF,"typeRdegF")
choice(menuConverttypeRdegC,"typeRdegC")
choice(menuConverttypeSdegF,"typeSdegF")
choice(menuConverttypeSdegC,"typeSdegC")
}
@@ -0,0 +1,27 @@
/*************************************************************************\
* Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef DATABASEVERSION_H
#define DATABASEVERSION_H
#include <epicsVersion.h>
#ifndef VERSION_INT
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#endif
/* include generated headers with:
* EPICS_DATABASE_MAJOR_VERSION
* EPICS_DATABASE_MINOR_VERSION
* EPICS_DATABASE_MAINTENANCE_VERSION
* EPICS_DATABASE_DEVELOPMENT_FLAG
*/
#include "databaseVersionNum.h"
#define DATABASE_VERSION_INT VERSION_INT(EPICS_DATABASE_MAJOR_VERSION, EPICS_DATABASE_MINOR_VERSION, EPICS_DATABASE_MAINTENANCE_VERSION, 0)
#endif // DATABASEVERSION_H
@@ -0,0 +1,7 @@
#ifndef DATABASEVERSION_H
# error include databaseVersion.h, not this header
#endif
#define EPICS_DATABASE_MAJOR_VERSION @EPICS_DATABASE_MAJOR_VERSION@
#define EPICS_DATABASE_MINOR_VERSION @EPICS_DATABASE_MINOR_VERSION@
#define EPICS_DATABASE_MAINTENANCE_VERSION @EPICS_DATABASE_MAINTENANCE_VERSION@
#define EPICS_DATABASE_DEVELOPMENT_FLAG @EPICS_DATABASE_DEVELOPMENT_FLAG@
+101
View File
@@ -0,0 +1,101 @@
#*************************************************************************
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
SRC_DIRS += $(IOCDIR)/db
INC += callback.h
INC += dbAccess.h
INC += dbAccessDefs.h
INC += dbAddr.h
INC += dbBkpt.h
INC += dbCa.h
INC += dbChannel.h
INC += dbConstLink.h
INC += dbConvert.h
INC += dbConvertFast.h
INC += dbConvertJSON.h
INC += dbDbLink.h
INC += dbExtractArray.h
INC += dbEvent.h
INC += dbJLink.h
INC += dbLink.h
INC += dbLock.h
INC += dbNotify.h
INC += dbScan.h
INC += dbServer.h
INC += dbTest.h
INC += dbCaTest.h
INC += db_test.h
INC += db_field_log.h
INC += initHooks.h
INC += recGbl.h
INC += dbIocRegister.h
INC += chfPlugin.h
INC += dbState.h
INC += db_access_routines.h
INC += db_convert.h
INC += dbUnitTest.h
# Generate menuGlobal.dbd, not really by concatenation, see RULES
DBDCAT += menuGlobal.dbd
menuGlobal_DBD += menuAlarmSevr.dbd
menuGlobal_DBD += menuAlarmStat.dbd
menuGlobal_DBD += menuFtype.dbd
menuGlobal_DBD += menuIvoa.dbd
menuGlobal_DBD += menuOmsl.dbd
menuGlobal_DBD += menuPini.dbd
menuGlobal_DBD += menuPost.dbd
menuGlobal_DBD += menuPriority.dbd
menuGlobal_DBD += menuYesNo.dbd
menuGlobal_DBD += menuSimm.dbd
DBDINC += $(basename $(menuGlobal_DBD))
DBDINC += menuScan
DBDINC += dbCommon
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
HTMLS += $(patsubst %.dbd.pod,%.html,$(menusPod))
dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
dbCore_SRCS += dbBkpt.c
dbCore_SRCS += dbChannel.c
dbCore_SRCS += dbConstLink.c
dbCore_SRCS += dbConvert.c
dbCore_SRCS += dbConvertJSON.c
dbCore_SRCS += dbDbLink.c
dbCore_SRCS += dbFastLinkConv.c
dbCore_SRCS += dbExtractArray.c
dbCore_SRCS += dbJLink.c
dbCore_SRCS += dbLink.c
dbCore_SRCS += dbNotify.c
dbCore_SRCS += dbScan.c
dbCore_SRCS += dbEvent.c
dbCore_SRCS += dbTest.c
dbCore_SRCS += db_access.c
dbCore_SRCS += db_test.c
dbCore_SRCS += recGbl.c
dbCore_SRCS += callback.c
dbCore_SRCS += dbCa.c
dbCore_SRCS += dbCaTest.c
dbCore_SRCS += initHooks.c
dbCore_SRCS += cvtBpt.c
dbCore_SRCS += dbContext.cpp
dbCore_SRCS += dbChannelIO.cpp
dbCore_SRCS += dbSubscriptionIO.cpp
dbCore_SRCS += dbPutNotifyBlocker.cpp
dbCore_SRCS += dbContextReadNotifyCache.cpp
dbCore_SRCS += dbIocRegister.c
dbCore_SRCS += chfPlugin.c
dbCore_SRCS += dbState.c
dbCore_SRCS += dbUnitTest.c
dbCore_SRCS += dbServer.c
+27
View File
@@ -0,0 +1,27 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
# Brookhaven National Lab.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -o $(COMMONDEP_TARGET) $< > $@
$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) -I ../db -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(IOCDIR)/db/RULES
# This is a target-specific variable
$(COMMON_DIR)/menuGlobal.dbd: DBDCAT_COMMAND = \
$(PERL) $(INSTALL_HOST_BIN)/makeIncludeDbd.pl $(menuGlobal_DBD) $(@F)
+354
View File
@@ -0,0 +1,354 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2013 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* callback.c */
/* general purpose callback tasks */
/*
* Original Author: Marty Kraimer
* Date: 07-18-91
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cantProceed.h"
#include "dbDefs.h"
#include "epicsAtomic.h"
#include "epicsEvent.h"
#include "epicsInterrupt.h"
#include "epicsRingPointer.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "epicsTimer.h"
#include "errlog.h"
#include "errMdef.h"
#include "taskwd.h"
#define epicsExportSharedSymbols
#include "callback.h"
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbCommon.h"
#include "dbFldTypes.h"
#include "dbLock.h"
#include "dbStaticLib.h"
#include "epicsExport.h"
#include "link.h"
#include "recSup.h"
static int callbackQueueSize = 2000;
typedef struct cbQueueSet {
epicsEventId semWakeUp;
epicsRingPointerId queue;
int queueOverflow;
int shutdown;
int threadsConfigured;
int threadsRunning;
} cbQueueSet;
static cbQueueSet callbackQueue[NUM_CALLBACK_PRIORITIES];
int callbackThreadsDefault = 1;
/* Don't know what a reasonable default is (yet).
* For the time being: parallel means 2 if not explicitly specified */
epicsShareDef int callbackParallelThreadsDefault = 2;
epicsExportAddress(int,callbackParallelThreadsDefault);
/* Timer for Delayed Requests */
static epicsTimerQueueId timerQueue;
/* Shutdown handling */
enum ctl {ctlInit, ctlRun, ctlPause, ctlExit};
static volatile enum ctl cbCtl;
static epicsEventId startStopEvent;
static int callbackIsInit;
/* Static data */
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
"cbLow", "cbMedium", "cbHigh"
};
#define FULL_MSG(name) "callbackRequest: " name " ring buffer full\n"
static char *fullMessage[NUM_CALLBACK_PRIORITIES] = {
FULL_MSG("cbLow"), FULL_MSG("cbMedium"), FULL_MSG("cbHigh")
};
static unsigned int threadPriority[NUM_CALLBACK_PRIORITIES] = {
epicsThreadPriorityScanLow - 1,
epicsThreadPriorityScanLow + 4,
epicsThreadPriorityScanHigh + 1
};
static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0, 1, 2};
int callbackSetQueueSize(int size)
{
if (callbackIsInit) {
fprintf(stderr, "Callback system already initialized\n");
return -1;
}
callbackQueueSize = size;
return 0;
}
int callbackParallelThreads(int count, const char *prio)
{
if (callbackIsInit) {
fprintf(stderr, "Callback system already initialized\n");
return -1;
}
if (count < 0)
count = epicsThreadGetCPUs() + count;
else if (count == 0)
count = callbackParallelThreadsDefault;
if (count < 1) count = 1;
if (!prio || *prio == 0 || strcmp(prio, "*") == 0) {
int i;
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
callbackQueue[i].threadsConfigured = count;
}
}
else {
dbMenu *pdbMenu;
int i;
if (!pdbbase) {
fprintf(stderr, "callbackParallelThreads: pdbbase not set\n");
return -1;
}
/* Find prio in menuPriority */
pdbMenu = dbFindMenu(pdbbase, "menuPriority");
if (!pdbMenu) {
fprintf(stderr, "callbackParallelThreads: No Priority menu\n");
return -1;
}
for (i = 0; i < pdbMenu->nChoice; i++) {
if (epicsStrCaseCmp(prio, pdbMenu->papChoiceValue[i]) == 0)
goto found;
}
fprintf(stderr, "callbackParallelThreads: "
"Unknown priority \"%s\"\n", prio);
return -1;
found:
callbackQueue[i].threadsConfigured = count;
}
return 0;
}
static void callbackTask(void *arg)
{
int prio = *(int*)arg;
cbQueueSet *mySet = &callbackQueue[prio];
taskwdInsert(0, NULL, NULL);
epicsEventSignal(startStopEvent);
while(!mySet->shutdown) {
void *ptr;
if (epicsRingPointerIsEmpty(mySet->queue))
epicsEventMustWait(mySet->semWakeUp);
while ((ptr = epicsRingPointerPop(mySet->queue))) {
CALLBACK *pcallback = (CALLBACK *)ptr;
if(!epicsRingPointerIsEmpty(mySet->queue))
epicsEventMustTrigger(mySet->semWakeUp);
mySet->queueOverflow = FALSE;
(*pcallback->callback)(pcallback);
}
}
if(!epicsAtomicDecrIntT(&mySet->threadsRunning))
epicsEventSignal(startStopEvent);
taskwdRemove(0);
}
void callbackStop(void)
{
int i;
if (cbCtl == ctlExit) return;
cbCtl = ctlExit;
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
callbackQueue[i].shutdown = 1;
epicsEventSignal(callbackQueue[i].semWakeUp);
}
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
while (epicsAtomicGetIntT(&mySet->threadsRunning)) {
epicsEventSignal(mySet->semWakeUp);
epicsEventWaitWithTimeout(startStopEvent, 0.1);
}
}
}
void callbackCleanup(void)
{
int i;
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
assert(epicsAtomicGetIntT(&mySet->threadsRunning)==0);
epicsEventDestroy(mySet->semWakeUp);
epicsRingPointerDelete(mySet->queue);
}
epicsTimerQueueRelease(timerQueue);
callbackIsInit = 0;
memset(callbackQueue, 0, sizeof(callbackQueue));
}
void callbackInit(void)
{
int i;
int j;
char threadName[32];
if (callbackIsInit) {
errlogMessage("Warning: callbackInit called again before callbackCleanup\n");
return;
}
callbackIsInit = 1;
if(!startStopEvent)
startStopEvent = epicsEventMustCreate(epicsEventEmpty);
cbCtl = ctlRun;
timerQueue = epicsTimerQueueAllocate(0, epicsThreadPriorityScanHigh);
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
epicsThreadId tid;
callbackQueue[i].semWakeUp = epicsEventMustCreate(epicsEventEmpty);
callbackQueue[i].queue = epicsRingPointerLockedCreate(callbackQueueSize);
if (callbackQueue[i].queue == 0)
cantProceed("epicsRingPointerLockedCreate failed for %s\n",
threadNamePrefix[i]);
callbackQueue[i].queueOverflow = FALSE;
if (callbackQueue[i].threadsConfigured == 0)
callbackQueue[i].threadsConfigured = callbackThreadsDefault;
for (j = 0; j < callbackQueue[i].threadsConfigured; j++) {
if (callbackQueue[i].threadsConfigured > 1 )
sprintf(threadName, "%s-%d", threadNamePrefix[i], j);
else
strcpy(threadName, threadNamePrefix[i]);
tid = epicsThreadCreate(threadName, threadPriority[i],
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)callbackTask, &priorityValue[i]);
if (tid == 0) {
cantProceed("Failed to spawn callback thread %s\n", threadName);
} else {
epicsEventWait(startStopEvent);
epicsAtomicIncrIntT(&callbackQueue[i].threadsRunning);
}
}
}
}
/* This routine can be called from interrupt context */
int callbackRequest(CALLBACK *pcallback)
{
int priority;
int pushOK;
cbQueueSet *mySet;
if (!pcallback) {
epicsInterruptContextMessage("callbackRequest: pcallback was NULL\n");
return S_db_notInit;
}
priority = pcallback->priority;
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
epicsInterruptContextMessage("callbackRequest: Bad priority\n");
return S_db_badChoice;
}
mySet = &callbackQueue[priority];
if (mySet->queueOverflow) return S_db_bufFull;
pushOK = epicsRingPointerPush(mySet->queue, pcallback);
if (!pushOK) {
epicsInterruptContextMessage(fullMessage[priority]);
mySet->queueOverflow = TRUE;
return S_db_bufFull;
}
epicsEventSignal(mySet->semWakeUp);
return 0;
}
static void ProcessCallback(CALLBACK *pcallback)
{
dbCommon *pRec;
callbackGetUser(pRec, pcallback);
if (!pRec) return;
dbScanLock(pRec);
(*pRec->rset->process)(pRec);
dbScanUnlock(pRec);
}
void callbackSetProcess(CALLBACK *pcallback, int Priority, void *pRec)
{
callbackSetCallback(ProcessCallback, pcallback);
callbackSetPriority(Priority, pcallback);
callbackSetUser(pRec, pcallback);
}
int callbackRequestProcessCallback(CALLBACK *pcallback,
int Priority, void *pRec)
{
callbackSetProcess(pcallback, Priority, pRec);
return callbackRequest(pcallback);
}
static void notify(void *pPrivate)
{
CALLBACK *pcallback = (CALLBACK *)pPrivate;
callbackRequest(pcallback);
}
void callbackRequestDelayed(CALLBACK *pcallback, double seconds)
{
epicsTimerId timer = (epicsTimerId)pcallback->timer;
if (timer == 0) {
timer = epicsTimerQueueCreateTimer(timerQueue, notify, pcallback);
pcallback->timer = timer;
}
epicsTimerStartDelay(timer, seconds);
}
void callbackCancelDelayed(CALLBACK *pcallback)
{
epicsTimerId timer = (epicsTimerId)pcallback->timer;
if (timer != 0) {
epicsTimerCancel(timer);
}
}
void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback,
int Priority, void *pRec, double seconds)
{
callbackSetProcess(pcallback, Priority, pRec);
callbackRequestDelayed(pcallback, seconds);
}
+80
View File
@@ -0,0 +1,80 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2013 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* includes for general purpose callback tasks */
/*
* Original Author: Marty Kraimer
* Date: 07-18-91
*/
#ifndef INCcallbackh
#define INCcallbackh 1
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* WINDOWS also has a "CALLBACK" type def
*/
#ifdef _WIN32
# ifdef CALLBACK
# undef CALLBACK
# endif /*CALLBACK*/
#endif /*_WIN32*/
#define NUM_CALLBACK_PRIORITIES 3
#define priorityLow 0
#define priorityMedium 1
#define priorityHigh 2
typedef struct callbackPvt {
void (*callback)(struct callbackPvt*);
int priority;
void *user; /*for use by callback user*/
void *timer; /*for use by callback itself*/
}CALLBACK;
typedef void (*CALLBACKFUNC)(struct callbackPvt*);
#define callbackSetCallback(PFUN, PCALLBACK) \
( (PCALLBACK)->callback = (PFUN) )
#define callbackSetPriority(PRIORITY, PCALLBACK) \
( (PCALLBACK)->priority = (PRIORITY) )
#define callbackGetPriority(PRIORITY, PCALLBACK) \
( (PRIORITY) = (PCALLBACK)->priority )
#define callbackSetUser(USER, PCALLBACK) \
( (PCALLBACK)->user = (void *) (USER) )
#define callbackGetUser(USER, PCALLBACK) \
( (USER) = (PCALLBACK)->user )
epicsShareFunc void callbackInit(void);
epicsShareFunc void callbackStop(void);
epicsShareFunc void callbackCleanup(void);
epicsShareFunc int callbackRequest(CALLBACK *pCallback);
epicsShareFunc void callbackSetProcess(
CALLBACK *pcallback, int Priority, void *pRec);
epicsShareFunc int callbackRequestProcessCallback(
CALLBACK *pCallback,int Priority, void *pRec);
epicsShareFunc void callbackRequestDelayed(
CALLBACK *pCallback,double seconds);
epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback);
epicsShareFunc void callbackRequestProcessCallbackDelayed(
CALLBACK *pCallback, int Priority, void *pRec, double seconds);
epicsShareFunc int callbackSetQueueSize(int size);
epicsShareFunc int callbackParallelThreads(int count, const char *prio);
#ifdef __cplusplus
}
#endif
#endif /*INCcallbackh*/
+681
View File
@@ -0,0 +1,681 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* für Materialien und Energie GmbH.
* Copyright (c) 2014 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@gmx.de>
*/
/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include "dbDefs.h"
#include "epicsStdio.h"
#include "epicsStdlib.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "chfPlugin.h"
#include "dbStaticLib.h"
/*
* Data for a chfPlugin
*/
typedef struct chfPlugin {
const chfPluginArgDef *opts;
size_t nopts;
epicsUInt32 *required;
const chfPluginIf *pif;
} chfPlugin;
/*
* Parser state data for a chfFilter (chfPlugin instance)
*/
typedef struct chfFilter {
const chfPlugin *plugin;
epicsUInt32 *found;
void *puser;
epicsInt16 nextParam;
} chfFilter;
/* Data types we get from the parser */
typedef enum chfPluginType {
chfPluginTypeBool,
chfPluginTypeInt,
chfPluginTypeDouble,
chfPluginTypeString
} chfPluginType;
/*
* Convert the (epicsInt32) integer value 'val' to the type named in
* 'opt->optType' and store the result at 'user + opt->offset'.
*/
static int
store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
{
epicsInt32 *ival;
int *eval;
const chfPluginEnumType *emap;
double *dval;
char *sval;
int ret;
char buff[22]; /* 2^64 = 1.8e+19, so 20 digits plus sign max */
#ifdef DEBUG_CHF
printf("Got an integer for %s (type %d): %ld\n",
opt->name, opt->optType, (long) val);
#endif
if (!opt->convert && opt->optType != chfPluginArgInt32) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
ival = (epicsInt32 *) ((char *)user + opt->dataOffset);
*ival = val;
break;
case chfPluginArgBoolean:
sval = user + opt->dataOffset;
*sval = !!val;
break;
case chfPluginArgDouble:
dval = (double*) (user + opt->dataOffset);
*dval = val;
break;
case chfPluginArgString:
sval = user + opt->dataOffset;
ret = sprintf(buff, "%ld", (long)val);
if (ret < 0 || (unsigned) ret > opt->size - 1) {
return -1;
}
strncpy(sval, buff, opt->size-1);
sval[opt->size-1]='\0';
break;
case chfPluginArgEnum:
eval = (int*) (user + opt->dataOffset);
for (emap = opt->enums; emap && emap->name; emap++) {
if (val == emap->value) {
*eval = val;
break;
}
}
if (!emap || !emap->name) {
return -1;
}
break;
case chfPluginArgInvalid:
return -1;
}
return 0;
}
/*
* Convert the (int) boolean value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
{
epicsInt32 *ival;
double *dval;
char *sval;
#ifdef DEBUG_CHF
printf("Got a boolean for %s (type %d): %d\n",
opt->name, opt->optType, val);
#endif
if (!opt->convert && opt->optType != chfPluginArgBoolean) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
ival = (epicsInt32 *) (user + opt->dataOffset);
*ival = val;
break;
case chfPluginArgBoolean:
sval = user + opt->dataOffset;
*sval = val;
break;
case chfPluginArgDouble:
dval = (double*) (user + opt->dataOffset);
*dval = !!val;
break;
case chfPluginArgString:
sval = user + opt->dataOffset;
if ((unsigned) (val ? 4 : 5) > opt->size - 1) {
return -1;
}
strncpy(sval, val ? "true" : "false", opt->size - 1);
sval[opt->size - 1] = '\0';
break;
case chfPluginArgEnum:
case chfPluginArgInvalid:
return -1;
}
return 0;
}
/*
* Convert the double value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int
store_double_value(const chfPluginArgDef *opt, void *vuser, double val)
{
char *user = vuser;
epicsInt32 *ival;
double *dval;
char *sval;
int i;
#ifdef DEBUG_CHF
printf("Got a double for %s (type %d, convert: %s): %g\n",
opt->name, opt->optType, opt->convert ? "yes" : "no", val);
#endif
if (!opt->convert && opt->optType != chfPluginArgDouble) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
if (val < INT_MIN || val > INT_MAX) {
return -1;
}
ival = (epicsInt32 *) (user + opt->dataOffset);
*ival = (epicsInt32) val;
break;
case chfPluginArgBoolean:
sval = user + opt->dataOffset;
*sval = !!val;
break;
case chfPluginArgDouble:
dval = (double*) (user + opt->dataOffset);
*dval = val;
break;
case chfPluginArgString:
sval = user + opt->dataOffset;
if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
return -1;
}
i = epicsSnprintf(sval, opt->size, "%.*g", (int) opt->size - 7, val);
if (i < 0 || (unsigned) i >= opt->size) {
return -1;
}
break;
case chfPluginArgEnum:
case chfPluginArgInvalid:
return -1;
}
return 0;
}
/*
* Convert the (char*) string value 'val' to the type named in 'opt->optType'
* and store the result at 'user + opt->offset'.
*/
static int
store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
size_t len)
{
epicsInt32 *ival;
int *eval;
const chfPluginEnumType *emap;
double *dval;
char *sval;
char *end;
size_t i;
#ifdef DEBUG_CHF
printf("Got a string for %s (type %d): %.*s\n",
opt->name, opt->optType, (int) len, val);
#endif
if (!opt->convert && opt->optType != chfPluginArgString &&
opt->optType != chfPluginArgEnum) {
return -1;
}
switch (opt->optType) {
case chfPluginArgInt32:
ival = (epicsInt32 *) (user + opt->dataOffset);
return epicsParseInt32(val, ival, 0, &end);
case chfPluginArgBoolean:
sval = user + opt->dataOffset;
if (epicsStrnCaseCmp(val, "true", len) == 0) {
*sval = 1;
} else if (epicsStrnCaseCmp(val, "false", len) == 0) {
*sval = 0;
} else {
epicsInt8 i8;
if (epicsParseInt8(val, &i8, 0, &end))
return -1;
*sval = !!i8;
}
break;
case chfPluginArgDouble:
dval = (double*) (user + opt->dataOffset);
return epicsParseDouble(val, dval, &end);
case chfPluginArgString:
i = opt->size-1 < len ? opt->size-1 : (int) len;
sval = user + opt->dataOffset;
strncpy(sval, val, i);
sval[i] = '\0';
break;
case chfPluginArgEnum:
eval = (int*) (user + opt->dataOffset);
for (emap = opt->enums; emap && emap->name; emap++) {
if (strncmp(emap->name, val, len) == 0) {
*eval = emap->value;
break;
}
}
if( !emap || !emap->name ) {
return -1;
}
break;
case chfPluginArgInvalid:
return -1;
}
return 0;
}
static void freeInstanceData(chfFilter *f)
{
free(f->found);
free(f); /* FIXME: Use a free-list */
}
/*
* chFilterIf callbacks
*/
/* First entry point when a new filter instance is created.
* All per-instance allocations happen here.
*/
static parse_result parse_start(chFilter *filter)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f;
/* Filter context */
/* FIXME: Use a free-list */
f = calloc(1, sizeof(chfFilter));
if (!f) {
errlogPrintf("chfFilterCtx calloc failed\n");
goto errfctx;
}
f->nextParam = -1;
/* Bit array to find missing required keys */
f->found = calloc( (p->nopts/32)+1, sizeof(epicsUInt32) );
if (!f->found) {
errlogPrintf("chfConfigParseStart: bit array calloc failed\n");
goto errbitarray;
}
/* Call the plugin to allocate its structure, it returns NULL on error */
if (p->pif->allocPvt) {
if ((f->puser = p->pif->allocPvt()) == NULL) {
errlogPrintf("chfConfigParseStart: plugin pvt alloc failed\n");
goto errplugin;
}
}
filter->puser = (void*) f;
return parse_continue;
errplugin:
free(f->found);
errbitarray:
free(f); /* FIXME: Use a free-list */
errfctx:
return parse_stop;
}
static void parse_abort(chFilter *filter) {
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
/* Call the plugin to tell it we're aborting */
if (p->pif->parse_error) p->pif->parse_error(f->puser);
if (p->pif->freePvt) p->pif->freePvt(f->puser);
freeInstanceData(f);
}
static parse_result parse_end(chFilter *filter)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
int i;
/* Check if all required arguments were supplied */
for(i = 0; i < (p->nopts/32)+1; i++) {
if ((f->found[i] & p->required[i]) != p->required[i]) {
if (p->pif->parse_error) p->pif->parse_error(f->puser);
if (p->pif->freePvt) p->pif->freePvt(f->puser);
freeInstanceData(f);
return parse_stop;
}
}
/* Call the plugin to tell it we're done */
if (p->pif->parse_ok) {
if (p->pif->parse_ok(f->puser)) {
if (p->pif->freePvt) p->pif->freePvt(f->puser);
freeInstanceData(f);
return parse_stop;
}
}
return parse_continue;
}
static parse_result parse_boolean(chFilter *filter, int boolVal)
{
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 ||
store_boolean_value(&opts[f->nextParam], f->puser, boolVal)) {
return parse_stop;
} else {
return parse_continue;
}
}
static parse_result parse_integer(chFilter *filter, long integerVal)
{
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if(sizeof(long)>sizeof(epicsInt32)) {
epicsInt32 temp=integerVal;
if(integerVal !=temp)
return parse_stop;
}
if (f->nextParam < 0 ||
store_integer_value(&opts[f->nextParam], f->puser, integerVal)) {
return parse_stop;
} else {
return parse_continue;
}
}
static parse_result parse_double(chFilter *filter, double doubleVal)
{
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 ||
store_double_value(&opts[f->nextParam], f->puser, doubleVal)) {
return parse_stop;
} else {
return parse_continue;
}
}
static parse_result
parse_string(chFilter *filter, const char *stringVal, size_t stringLen)
{
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
if (f->nextParam < 0 ||
store_string_value(&opts[f->nextParam], f->puser, stringVal, stringLen)) {
return parse_stop;
} else {
return parse_continue;
}
}
static parse_result parse_start_map(chFilter *filter)
{
return parse_continue;
}
static parse_result
parse_map_key(chFilter *filter, const char *key, size_t stringLen)
{
const chfPluginArgDef *cur;
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
chfFilter *f = (chfFilter*)filter->puser;
int *tag;
int i;
int j;
f->nextParam = -1;
for (cur = opts, i = 0; cur && cur->name; cur++, i++) {
if (strncmp(key, cur->name, stringLen) == 0) {
f->nextParam = i;
break;
}
}
if (f->nextParam == -1) {
return parse_stop;
}
if (opts[i].tagged) {
tag = (int*) ((char*) f->puser + opts[i].tagOffset);
*tag = opts[i].choice;
}
f->found[i/32] |= 1<<(i%32);
/* Mark tag and all other options pointing to the same data as found */
for (cur = opts, j = 0; cur && cur->name; cur++, j++) {
if ((opts[i].tagged && cur->dataOffset == opts[i].tagOffset)
|| cur->dataOffset == opts[i].dataOffset)
f->found[j/32] |= 1<<(j%32);
}
return parse_continue;
}
static parse_result parse_end_map(chFilter *filter)
{
return parse_continue;
}
static long channel_open(chFilter *filter)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channel_open)
return p->pif->channel_open(filter->chan, f->puser);
else
return 0;
}
static void
channel_register_pre(chFilter *filter, chPostEventFunc **cb_out,
void **arg_out, db_field_log *probe)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPre)
p->pif->channelRegisterPre(filter->chan, f->puser, cb_out, arg_out,
probe);
}
static void
channel_register_post(chFilter *filter, chPostEventFunc **cb_out,
void **arg_out, db_field_log *probe)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channelRegisterPost)
p->pif->channelRegisterPost(filter->chan, f->puser, cb_out, arg_out,
probe);
}
static void channel_report(chFilter *filter, int level,
const unsigned short indent)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channel_report)
p->pif->channel_report(filter->chan, f->puser, level, indent);
}
static void channel_close(chFilter *filter)
{
chfPlugin *p = (chfPlugin*) filter->plug->puser;
chfFilter *f = (chfFilter*) filter->puser;
if (p->pif->channel_close) p->pif->channel_close(filter->chan, f->puser);
if (p->pif->freePvt) p->pif->freePvt(f->puser);
free(f->found);
free(f); /* FIXME: Use a free-list */
}
static void plugin_free(void* puser)
{
chfPlugin *p=puser;
free(p->required);
free(p);
}
/*
* chFilterIf for the wrapper
* we just support a simple one-level map, and no arrays
*/
static chFilterIf wrapper_fif = {
plugin_free,
parse_start,
parse_abort,
parse_end,
NULL, /* parse_null, */
parse_boolean,
parse_integer,
parse_double,
parse_string,
parse_start_map,
parse_map_key,
parse_end_map,
NULL, /* parse_start_array, */
NULL, /* parse_end_array, */
channel_open,
channel_register_pre,
channel_register_post,
channel_report,
channel_close
};
const char*
chfPluginEnumString(const chfPluginEnumType *emap, int i, const char* def)
{
for(; emap && emap->name; emap++) {
if ( i == emap->value ) {
return emap->name;
}
}
return def;
}
int
chfPluginRegister(const char* key, const chfPluginIf *pif,
const chfPluginArgDef* opts)
{
chfPlugin *p;
size_t i;
const chfPluginArgDef *cur;
epicsUInt32 *reqd;
/* Check and count options */
for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
switch(cur->optType) {
case chfPluginArgInt32:
if (cur->size < sizeof(epicsInt32)) {
errlogPrintf("Plugin %s: %d bytes too small for epicsInt32 %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgBoolean:
if (cur->size < 1) {
errlogPrintf("Plugin %s: %d bytes too small for boolean %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgDouble:
if (cur->size < sizeof(double)) {
errlogPrintf("Plugin %s: %d bytes too small for double %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgString:
if (cur->size < sizeof(char*)) {
/* Catch if someone has given us a char* instead of a char[]
* Also means that char buffers must be >=4.
*/
errlogPrintf("Plugin %s: %d bytes too small for string %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgEnum:
if (cur->size < sizeof(int)) {
errlogPrintf("Plugin %s: %d bytes too small for enum %s\n",
key, cur->size, cur->name);
return -1;
}
break;
case chfPluginArgInvalid:
errlogPrintf("Plugin %s: storage type for %s is not defined\n",
key, cur->name);
return -1;
break;
}
}
/* Bit array used to find missing required keys */
reqd = dbCalloc((i/32)+1, sizeof(epicsUInt32));
if (!reqd) {
errlogPrintf("Plugin %s: bit array calloc failed\n", key);
return -1;
}
for (i = 0, cur = opts; cur && cur->name; i++, cur++) {
if (cur->required) reqd[i/32] |= 1 << (i%32);
}
/* Plugin data */
p = dbCalloc(1, sizeof(chfPlugin));
p->pif = pif;
p->opts = opts;
p->nopts = i;
p->required = reqd;
dbRegisterFilter(key, &wrapper_fif, p);
return 0;
}
+318
View File
@@ -0,0 +1,318 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* für Materialien und Energie GmbH.
* Copyright (c) 2014 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@gmx.de>
*/
/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
#ifndef CHFPLUGIN_H
#define CHFPLUGIN_H
#include <shareLib.h>
#include <dbDefs.h>
#include <epicsTypes.h>
#include <dbChannel.h>
struct db_field_log;
/** @file chfPlugin.h
* @brief Channel filter simplified plugins.
*
* Utility layer to allow an easier (reduced) interface for
* channel filter plugins.
*
* Parsing the configuration arguments of a channel filter plugin
* is done according to an argument description table provided by the plugin.
* The parser stores the results directly into a user supplied structure
* after appropriate type conversion.
*
* To specify the arguments, a chfPluginArgDef table must be defined
* for the user structure. This table has to be specified when the plugin registers.
*
* The plugin is responsible to register an init function using
* epicsExportRegistrar() and the accompanying registrar() directive in the dbd,
* and call chfPluginRegister() from within the init function.
*
* For example:
*
* typedef struct myStruct {
* ... other stuff
* char mode;
* epicsInt32 ival;
* double dval;
* epicsInt32 ival2;
* int enumval;
* char strval[20];
* char boolval;
* } myStruct;
*
* static const
* chfPluginEnumType colorEnum[] = { {"Red",1}, {"Green",2}, {"Blue",3}, {NULL,0} };
*
* static const
* chfPluginDef myStructDef[] = {
* chfTagInt32(myStruct, ival, "Integer" , ival2, 3, 0, 0),
* chfInt32 (myStruct, ival2, "Second" , 1, 0),
* chfDouble (myStruct, dval, "Double" , 1, 0),
* chfString (myStruct, strval , "String" , 1, 0),
* chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
* chfBoolean (myStruct, boolval, "Bool" , 1, 0),
* chfPluginEnd
* };
*
* Note: The 4th argument specifies the parameter to be required (1) or optional (0),
* the 5th whether converting to the required type is allowed (1), or
* type mismatches are an error (0).
* Note: The "Tag" version has two additional arguments. the 4th arg specifies the tag
* field (integer type) inside the structure to be set, the 5th arg specifies the
* value to set the tag field to. Arguments 6 and 7 specify "required" and
* "conversion" as described above.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Channel filter simplified plugin interface.
*
* The routines in this structure must be implemented by each filter plugin.
*/
typedef struct chfPluginIf {
/* Memory management */
/** @brief Allocate private resources.
*
* <em>Called before parsing starts.</em>
* The plugin should allocate its per-instance structures,
* returning a pointer to them or NULL requesting an abort of the operation.
*
* allocPvt may be set to NULL, if no resource allocation is needed.
*
* @return Pointer to private structure, NULL if operation is to be aborted.
*/
void * (* allocPvt) (void);
/** @brief Free private resources.
*
* <em>Called as part of abort or shutdown.</em>
* The plugin should release any resources allocated for this filter;
* no further calls through this interface will be made.
*
* freePvt may be set to NULL, if no resources need to be released.
*
* @param pvt Pointer to private structure.
*/
void (* freePvt) (void *pvt);
/* Parameter parsing results */
/** @brief A parsing error occurred.
*
* <em>Called after parsing failed with an error.</em>
*
* @param pvt Pointer to private structure.
*/
void (* parse_error) (void *pvt);
/** @brief Configuration has been parsed successfully.
*
* <em>Called after parsing has finished ok.</em>
* The plugin may check the validity of the parsed data,
* returning -1 to request an abort of the operation.
*
* @param pvt Pointer to private structure.
* @return 0 for success, -1 if operation is to be aborted.
*/
int (* parse_ok) (void *pvt);
/* Channel operations */
/** @brief Open channel.
*
* <em>Called as part of the channel connection setup.</em>
*
* @param chan dbChannel for which the connection is being made.
* @param pvt Pointer to private structure.
* @return 0 for success, -1 if operation is to be aborted.
*/
long (* channel_open) (dbChannel *chan, void *pvt);
/** @brief Register callbacks for pre-event-queue operation.
*
* <em>Called as part of the channel connection setup.</em>
*
* This function is called to establish the stack of plugins that an event
* is passed through between the database and the event queue.
*
* The plugin must set pe_out to point to its own post-event callback in order
* to be called when a data update is sent from the database towards the
* event queue.
*
* The plugin may find out the type of data it will receive by looking at 'probe'.
* If the plugin will change the data type and/or size, it must update 'probe'
* accordingly.
*
* @param chan dbChannel for which the connection is being made.
* @param pvt Pointer to private structure.
* @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
* this plugin).
* @param arg_out Argument that must be supplied when calling
* this plugin's post-event callback.
*/
void (* channelRegisterPre) (dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out,
db_field_log *probe);
/** @brief Register callbacks for post-event-queue operation.
*
* <em>Called as part of the channel connection setup.</em>
*
* This function is called to establish the stack of plugins that an event
* is passed through between the event queue and the final user (CA server or
* database access).
*
* The plugin must set pe_out to point to its own post-event callback in order
* to be called when a data update is sent from the event queue towards the
* final user.
*
* The plugin may find out the type of data it will receive by looking at 'probe'.
* If the plugin will change the data type and/or size, it must update 'probe'
* accordingly.
*
* @param chan dbChannel for which the connection is being made.
* @param pvt Pointer to private structure.
* @param cb_out Pointer to this plugin's post-event callback (NULL to bypass
* this plugin).
* @param arg_out Argument that must be supplied when calling
* this plugin's post-event callback.
*/
void (* channelRegisterPost) (dbChannel *chan, void *pvt,
chPostEventFunc **cb_out, void **arg_out,
db_field_log *probe);
/** @brief Channel report request.
*
* <em>Called as part of show... routines.</em>
*
* @param chan dbChannel for which the report is requested.
* @param pvt Pointer to private structure.
* @param level Interest level.
* @param indent Number of spaces to print before each output line.
*/
void (* channel_report) (dbChannel *chan, void *pvt, int level, const unsigned short indent);
/** @brief Channel close request.
*
* <em>Called as part of connection shutdown.</em>
* @param chan dbChannel for which the connection is being shut down.
* @param pvt Pointer to private structure.
*/
void (* channel_close) (dbChannel *chan, void *pvt);
} chfPluginIf;
typedef enum chfPluginArg {
chfPluginArgInvalid=0,
chfPluginArgBoolean,
chfPluginArgInt32,
chfPluginArgDouble,
chfPluginArgString,
chfPluginArgEnum
} chfPluginArg;
typedef struct chfPluginEnumType {
const char *name;
const int value;
} chfPluginEnumType;
typedef struct chfPluginArgDef {
const char * name;
chfPluginArg optType;
unsigned int required:1;
unsigned int convert:1;
unsigned int tagged:1;
epicsUInt32 tagOffset;
epicsUInt32 choice;
epicsUInt32 dataOffset;
epicsUInt32 size;
const chfPluginEnumType *enums;
} chfPluginArgDef;
/* Simple arguments */
#define chfInt32(Struct, Member, Name, Req, Conv) \
{Name, chfPluginArgInt32, Req, Conv, 0, 0, 0, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfBoolean(Struct, Member, Name, Req, Conv) \
{Name, chfPluginArgBoolean, Req, Conv, 0, 0, 0, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfDouble(Struct, Member, Name, Req, Conv) \
{Name, chfPluginArgDouble, Req, Conv, 0, 0, 0, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfString(Struct, Member, Name, Req, Conv) \
{Name, chfPluginArgString, Req, Conv, 0, 0, 0, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfEnum(Struct, Member, Name, Req, Conv, Enums) \
{Name, chfPluginArgEnum, Req, Conv, 0, 0, 0, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
/* Tagged arguments */
#define chfTagInt32(Struct, Member, Name, Tag, Choice, Req, Conv) \
{Name, chfPluginArgInt32, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfTagBoolean(Struct, Member, Name, Tag, Choice, Req, Conv) \
{Name, chfPluginArgBoolean, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfTagDouble(Struct, Member, Name, Tag, Choice, Req, Conv) \
{Name, chfPluginArgDouble, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfTagString(Struct, Member, Name, Tag, Choice, Req, Conv) \
{Name, chfPluginArgString, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
#define chfTagEnum(Struct, Member, Name, Tag, Choice, Req, Conv, Enums) \
{Name, chfPluginArgEnum, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
#define chfPluginArgEnd {0}
/* Extra output when parsing and converting */
#define CHFPLUGINDEBUG 1
/** @brief Return the string associated with Enum index 'i'.
*
* @param Enums A null-terminated array of string/integer pairs.
* @param i An Enum index.
* @param def String to be returned when 'i' isn't a valid Enum index.
* @return The string associated with 'i'.
*/
epicsShareFunc const char* chfPluginEnumString(const chfPluginEnumType *Enums, int i, const char* def);
/** @brief Register a plugin.
*
* @param key The plugin name key that clients will use.
* @param pif Pointer to the plugin's interface.
* @param opts Pointer to the configuration argument description table.
*/
epicsShareFunc int chfPluginRegister(const char* key, const chfPluginIf *pif, const chfPluginArgDef* opts);
#ifdef __cplusplus
}
#endif
#endif // CHFPLUGIN_H
+202
View File
@@ -0,0 +1,202 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* cvtBpt.c - Convert using breakpoint table
*
* Author: Marty Kraimer
* Date: 04OCT95
* This is adaptation of old bldCvtTable
*/
#include "epicsPrint.h"
#define epicsExportSharedSymbols
#include "cvtTable.h"
#include "dbAccess.h"
#include "dbBase.h"
#include "dbStaticLib.h"
static brkTable *findBrkTable(short linr)
{
dbMenu *pdbMenu;
pdbMenu = dbFindMenu(pdbbase,"menuConvert");
if (!pdbMenu) {
epicsPrintf("findBrkTable: menuConvert not loaded!\n");
return NULL;
}
if (linr < 0 || linr >= pdbMenu->nChoice) {
epicsPrintf("findBrkTable: linr=%d but menuConvert only has %d choices\n",
linr,pdbMenu->nChoice);
return NULL;
}
return dbFindBrkTable(pdbbase,pdbMenu->papChoiceValue[linr]);
}
/* Used by both ao and ai record types */
long cvtRawToEngBpt(double *pval, short linr, short init,
void **ppbrk, short *plbrk)
{
double val = *pval;
long status = 0;
brkTable *pbrkTable;
brkInt *pInt, *nInt;
short lbrk;
int number;
if (linr < 2)
return -1;
if (init || *ppbrk == NULL) {
pbrkTable = findBrkTable(linr);
if (!pbrkTable)
return S_dbLib_badField;
*ppbrk = (void *)pbrkTable;
*plbrk = 0;
} else
pbrkTable = (brkTable *)*ppbrk;
number = pbrkTable->number;
lbrk = *plbrk;
/* Limit index to the size of the table */
if (lbrk < 0)
lbrk = 0;
else if (lbrk > number-2)
lbrk = number-2;
pInt = & pbrkTable->paBrkInt[lbrk];
nInt = pInt + 1;
if (nInt->raw > pInt->raw) {
/* raw values increase down the table */
while (val > nInt->raw) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val < pInt->raw) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
} else {
/* raw values decrease down the table */
while (val <= nInt->raw) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while(val > pInt->raw) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
}
*plbrk = lbrk;
*pval = pInt->eng + (val - pInt->raw) * pInt->slope;
return status;
}
/* Used by the ao record type */
long cvtEngToRawBpt(double *pval, short linr, short init,
void **ppbrk, short *plbrk)
{
double val = *pval;
long status = 0;
brkTable *pbrkTable;
brkInt *pInt, *nInt;
short lbrk;
int number;
if (linr < 2)
return -1;
if (init || *ppbrk == NULL) { /*must find breakpoint table*/
pbrkTable = findBrkTable(linr);
if (!pbrkTable)
return S_dbLib_badField;
*ppbrk = (void *)pbrkTable;
/* start at the beginning */
*plbrk = 0;
} else
pbrkTable = (brkTable *)*ppbrk;
number = pbrkTable->number;
lbrk = *plbrk;
/* Limit index to the size of the table */
if (lbrk < 0)
lbrk = 0;
else if (lbrk > number-2)
lbrk = number-2;
pInt = & pbrkTable->paBrkInt[lbrk];
nInt = pInt + 1;
if (nInt->eng > pInt->eng) {
/* eng values increase down the table */
while (val > nInt->eng) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val < pInt->eng) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
} else {
/* eng values decrease down the table */
while (val <= nInt->eng) {
lbrk++;
pInt = nInt++;
if (lbrk > number-2) {
status = 1;
break;
}
}
while (val > pInt->eng) {
if (lbrk <= 0) {
status = 1;
break;
}
lbrk--;
nInt = pInt--;
}
}
*plbrk = lbrk;
*pval = pInt->raw + (val - pInt->eng) / pInt->slope;
return status;
}
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbAccess.h */
#ifndef INCdbAccessh
#define INCdbAccessh
#include "dbDefs.h"
#include "epicsTime.h"
#include "caeventmask.h"
#include "dbFldTypes.h"
#include "link.h"
#include "dbBase.h"
#include "shareLib.h"
#include "dbAddr.h"
#include "dbLock.h"
#include "dbAccessDefs.h"
#include "dbLink.h"
#include "dbCa.h"
#include "dbCommon.h"
#include "db_field_log.h"
#endif /*INCdbAccessh*/
+252
View File
@@ -0,0 +1,252 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbAccessDefs.h */
#ifndef INCdbAccessDefsh
#define INCdbAccessDefsh
#ifdef epicsExportSharedSymbols
# define INCLdb_accessh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbBase.h"
#include "dbAddr.h"
#include "recSup.h"
#ifdef INCLdb_accessh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
epicsShareExtern struct dbBase *pdbbase;
epicsShareExtern volatile int interruptAccept;
/* The database field and request types are defined in dbFldTypes.h*/
/* Data Base Request Options */
#define DBR_STATUS 0x00000001
#define DBR_UNITS 0x00000002
#define DBR_PRECISION 0x00000004
#define DBR_TIME 0x00000008
#define DBR_ENUM_STRS 0x00000010
#define DBR_GR_LONG 0x00000020
#define DBR_GR_DOUBLE 0x00000040
#define DBR_CTRL_LONG 0x00000080
#define DBR_CTRL_DOUBLE 0x00000100
#define DBR_AL_LONG 0x00000200
#define DBR_AL_DOUBLE 0x00000400
/**********************************************************************
* The next page contains macros for defining requests.
* As an example the following defines a buffer to accept an array
* of 10 float values + DBR_STATUS and DBR_TIME options
*
* struct {
* DBRstatus
* DBRtime
* epicsFloat32 value[10]
* } buffer;
*
* IMPORTANT!! The DBRoptions must be given in the order that they
* appear in the Data Base Request Options #defines
*
* The associated dbGetField call is:
*
* long options,number_elements;
* ...
* options = DBR_STATUS|DBR_TIME;
* number_elements = 10;
* rtnval=dbGetField(paddr,DBR_FLOAT,&buffer,&options,&number_elements);
*
* When dbGetField returns:
* rtnval is error status (0 means success)
* options has a bit set for each option that was accepted
* number_elements is actual number of elements obtained
*
* The individual items can be refered to by the expressions::
*
* buffer.status
* buffer.severity
* buffer.err_status
* buffer.epoch_seconds
* buffer.nano_seconds
* buffer.value[i]
*
* The following is also a valid declaration:
*
* typedef struct {
* DBRstatus
* DBRtime
* epicsFloat32 value[10]
* } MYBUFFER;
*
* With this definition you can give definitions such as the following:
*
* MYBUFFER *pbuf1;
* MYBUFFER buf;
*************************************************************************/
/* Macros for defining each option */
#define DBRstatus \
epicsUInt16 status; /* alarm status */\
epicsUInt16 severity; /* alarm severity*/\
epicsUInt16 acks; /* alarm ack severity*/\
epicsUInt16 ackt; /* Acknowledge transient alarms?*/
#define DB_UNITS_SIZE 16
#define DBRunits \
char units[DB_UNITS_SIZE]; /* units */
#define DBRprecision union { \
long dp; /* number of decimal places*/\
double unused; /* for alignment */\
} precision;
/* precision.dp must be long to match the pointer arguments to
* RSET->get_precision() and recGblGetPrec(), which it's
* too late to change now. DBRprecision must be padded to
* maintain 8-byte alignment. */
#define DBRtime \
epicsTimeStamp time; /* time stamp*/
#define DBRenumStrs \
epicsUInt32 no_str; /* number of strings*/\
epicsInt32 padenumStrs; /*padding to force 8 byte align*/\
char strs[DB_MAX_CHOICES][MAX_STRING_SIZE]; /* string values */
#define DBRgrLong \
epicsInt32 upper_disp_limit; /*upper limit of graph*/\
epicsInt32 lower_disp_limit; /*lower limit of graph*/
#define DBRgrDouble \
epicsFloat64 upper_disp_limit; /*upper limit of graph*/\
epicsFloat64 lower_disp_limit; /*lower limit of graph*/
#define DBRctrlLong \
epicsInt32 upper_ctrl_limit; /*upper limit of graph*/\
epicsInt32 lower_ctrl_limit; /*lower limit of graph*/
#define DBRctrlDouble \
epicsFloat64 upper_ctrl_limit; /*upper limit of graph*/\
epicsFloat64 lower_ctrl_limit; /*lower limit of graph*/
#define DBRalLong \
epicsInt32 upper_alarm_limit;\
epicsInt32 upper_warning_limit;\
epicsInt32 lower_warning_limit;\
epicsInt32 lower_alarm_limit;
#define DBRalDouble \
epicsFloat64 upper_alarm_limit;\
epicsFloat64 upper_warning_limit;\
epicsFloat64 lower_warning_limit;\
epicsFloat64 lower_alarm_limit;
/* structures for each option type */
struct dbr_status {DBRstatus};
struct dbr_units {DBRunits};
struct dbr_precision {DBRprecision};
struct dbr_time {DBRtime};
struct dbr_enumStrs {DBRenumStrs};
struct dbr_grLong {DBRgrLong};
struct dbr_grDouble {DBRgrDouble};
struct dbr_ctrlLong {DBRctrlLong};
struct dbr_ctrlDouble {DBRctrlDouble};
struct dbr_alLong {DBRalLong};
struct dbr_alDouble {DBRalDouble};
/* sizes for each option structure */
#define dbr_status_size sizeof(struct dbr_status)
#define dbr_units_size sizeof(struct dbr_units)
#define dbr_precision_size sizeof(struct dbr_precision)
#define dbr_time_size sizeof(struct dbr_time)
#define dbr_enumStrs_size sizeof(struct dbr_enumStrs)
#define dbr_grLong_size sizeof(struct dbr_grLong)
#define dbr_grDouble_size sizeof(struct dbr_grDouble)
#define dbr_ctrlLong_size sizeof(struct dbr_ctrlLong)
#define dbr_ctrlDouble_size sizeof(struct dbr_ctrlDouble)
#define dbr_alLong_size sizeof(struct dbr_alLong)
#define dbr_alDouble_size sizeof(struct dbr_alDouble)
#ifndef INCerrMdefh
#include "errMdef.h"
#endif
#define S_db_notFound (M_dbAccess| 1) /*Process Variable Not Found*/
#define S_db_badDbrtype (M_dbAccess| 3) /*Illegal Database Request Type*/
#define S_db_noMod (M_dbAccess| 5) /*Attempt to modify noMod field*/
#define S_db_badLset (M_dbAccess| 7) /*Illegal Lock Set*/
#define S_db_precision (M_dbAccess| 9) /*get precision failed */
#define S_db_onlyOne (M_dbAccess|11) /*Only one element allowed*/
#define S_db_badChoice (M_dbAccess|13) /*Illegal choice*/
#define S_db_badField (M_dbAccess|15) /*Illegal field value*/
#define S_db_lsetLogic (M_dbAccess|17) /*Logic error generating lock sets*/
#define S_db_noLSET (M_dbAccess|21) /*No link support table or entry*/
#define S_db_noRSET (M_dbAccess|31) /*missing record support entry table*/
#define S_db_noSupport (M_dbAccess|33) /*RSET or DSXT routine not defined*/
#define S_db_BadSub (M_dbAccess|35) /*Subroutine not found*/
/*!!!! Do not change next line without changing src/rsrv/server.h!!!!!!!!*/
#define S_db_Pending (M_dbAccess|37) /*Request is pending*/
#define S_db_Blocked (M_dbAccess|39) /*Request is Blocked*/
#define S_db_putDisabled (M_dbAccess|41) /*putFields are disabled*/
#define S_db_badHWaddr (M_dbAccess|43) /*Hardware link type not on INP/OUT*/
#define S_db_bkptSet (M_dbAccess|53) /*Breakpoint already set*/
#define S_db_bkptNotSet (M_dbAccess|55) /*No breakpoint set in record*/
#define S_db_notStopped (M_dbAccess|57) /*Record not stopped*/
#define S_db_errArg (M_dbAccess|59) /*Error in argument*/
#define S_db_bkptLogic (M_dbAccess|61) /*Logic error in breakpoint routine*/
#define S_db_cntSpwn (M_dbAccess|63) /*Cannot spawn dbContTask*/
#define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/
#define S_db_noMemory (M_dbAccess|66) /*unable to allocate data structure from pool*/
#define S_db_notInit (M_dbAccess|67) /*Not initialized*/
#define S_db_bufFull (M_dbAccess|68) /*Buffer full*/
epicsShareFunc long dbPutSpecial(struct dbAddr *paddr,int pass);
epicsShareFunc rset * dbGetRset(const struct dbAddr *paddr);
epicsShareFunc long dbPutAttribute(
const char *recordTypename,const char *name,const char*value);
epicsShareFunc int dbIsValueField(const struct dbFldDes *pdbFldDes);
epicsShareFunc int dbGetFieldIndex(const struct dbAddr *paddr);
epicsShareFunc long dbScanPassive(
struct dbCommon *pfrom,struct dbCommon *pto);
epicsShareFunc long dbProcess(struct dbCommon *precord);
epicsShareFunc long dbNameToAddr(
const char *pname,struct dbAddr *);
epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset);
epicsShareFunc long dbGetField(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
epicsShareFunc long dbGet(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
epicsShareFunc long dbPutField(
struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
epicsShareFunc long dbPut(
struct dbAddr *,short dbrType,const void *pbuffer,long nRequest);
typedef void(*SPC_ASCALLBACK)(struct dbCommon *);
/*dbSpcAsRegisterCallback called by access security */
epicsShareFunc void dbSpcAsRegisterCallback(SPC_ASCALLBACK func);
epicsShareFunc long dbBufferSize(
short dbrType,long options,long nRequest);
epicsShareFunc long dbValueSize(short dbrType);
/* Hook Routine */
typedef void (*DB_LOAD_RECORDS_HOOK_ROUTINE)(const char* filename,
const char* substitutions);
epicsShareExtern DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook;
epicsShareFunc int dbLoadDatabase(
const char *filename, const char *path, const char *substitutions);
epicsShareFunc int dbLoadRecords(
const char* filename, const char* substitutions);
#ifdef __cplusplus
}
#endif
#endif /*INCdbAccessDefsh*/
+30
View File
@@ -0,0 +1,30 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef dbAddrh
#define dbAddrh
struct dbCommon;
struct dbFldDes;
typedef struct dbAddr {
struct dbCommon *precord; /* address of record */
void *pfield; /* address of field */
struct dbFldDes *pfldDes; /* address of struct fldDes */
long no_elements; /* number of elements (arrays) */
short field_type; /* type of database field */
short field_size; /* size of the field being accessed */
short special; /* special processing */
short dbr_field_type; /* field type as seen by database request*/
/* DBR_STRING,...,DBR_ENUM,DBR_NOACCESS */
} dbAddr;
typedef dbAddr DBADDR;
#endif /* dbAddrh */
+970
View File
@@ -0,0 +1,970 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbBkpt.c */
/*
* Author: Matthew Needes
* Date: 8-30-93
*/
/*
* Database Breakpoint Manipulation and User Interface
*
* USER COMMANDS
* dbb(record_name) Set a breakpoint in a record
* dbd(record_name) Delete a record's breakpoint
* dbc(record_name) Resume record processing
* dbs(record_name) Step through record processing through
* IO links, forward process links, etc.
* dbstat() Display status of stopped records in lock sets.
* dbap(record_name) Toggle automatic print after processing.
* dbp(record_name) Print out fields from record currently stopped.
* dbprc(record_name) Processes a record once without printing it.
* (Unless autoprint is on)
*
* INTERNAL FUNCTIONS
* dbBkpt() Process breakpoints, called by dbProcess().
* dbPrint() Prints record if autoprint enabled.
* dbBkptCont() The task that continues and steps through
* records that are stopped at a breakpoint.
*/
/* #define BKPT_DIAG */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "alarm.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "errlog.h"
#include "errMdef.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbBkpt.h"
#include "dbCommon.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "dbLock.h"
#include "dbScan.h"
#include "dbTest.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
#include "special.h"
/* private routines */
static void dbBkptCont(dbCommon *precord);
static long FIND_CONT_NODE(
const char *record_name,
struct LS_LIST **ppnode,
struct dbCommon **pprecord);
/*
* Breakpoints are used as a debugging instrument to suspend the
* processing of database records. Once suspended, record
* processing may continue if either a continue (dbc()) or a
* step (dbs()) command is then issued. The current record's
* contents may be printed either with dbp(), or immediately
* after processing (use dbap() to toggle the BKPT_PRINT bit).
*
* dbb() and dbd() add a breakpoint to a record or delete one
* from a record. dbstat() prints out comprehensive breakpoint
* status information.
*
* Breakpoints may be set on a per lockset basis. When a
* breakpoint is set in a lockset, a new task is created. A
* separate task gets created for _every_ lockset containing
* a breakpoint. Thus multiple locksets may be debugged
* simultaneously. The breakpoint handler then schedules future
* processing in that lockset to this task. The separate task is
* used so that locksets that do not have breakpoints are isolated
* from locksets that do. This allows the processing of other
* locksets to continue uninterupted, even if they exist on the same
* scan list as a lockset containing a breakpoint.
*
* An entrypoint is the first record that gets processed in a lockset.
* This type of record is the basis for subsequent recursive executions
* of dbProcess(). The breakpoint handler monitors and schedules
* these entrypoints to the breakpoint tasks.
*
* Two hooks have been inserted in dbProcess() to manage breakpoints,
* dbBkpt() and dbPrint(). The former does two things:
*
* 1. Schedule entrypoints with the breakpoint task.
* 2. Suspend record processing when a breakpoint is detected.
*
* 1 occurs only if dbProcess() is called outside of the breakpoint
* task. Number 2 only occurs when dbProcess() is called from
* _within_ the breakpoint task's context. Number 1 is used for
* detection and scheduling, while 2 is used for suspending the task.
*
* The dbPrint() hook is used to print out a record's contents immediately
* _after_ a record has been processed.
*
* The dbBkptCont, or breakpoint task, pends on a semaphore that gets
* released whenever new entrypoints are scheduled for it. When
* released, this task then runs down its entrypoint queue and
* processes each entrypoint in turn. In this context, dbProcess
* will execute the dbBkpt() hook in mode 2, allowing this task to
* be suspended whenever a breakpoint is detected.
*
* NOTE: This is not a very "real-time" implementation (even for those
* locksets not containing a breakpoint). I may fix this later.
*
* Final comment: The scary thing is, I don't think this can be done
* more simply...
*
*/
/*
* Flag used by dbProcess() to determine if there are
* any breakpoints. This is so that there is only
* a single comparison in the critical path during
* normal record execution, i.e. when there aren't
* any breakpoints set.
*/
long lset_stack_count = 0;
/*
* Stack--in which each entry represents a different
* lock set with either breakpoints and/or stopped
* execution. (Breakpoints may be disabled even
* though execution is stopped). The order of the
* list is maintained so that the entry on the top
* of stack is used as a default for dbc() and dbs().
* The semaphore is used to prevent conflicts while
* operating with this stack.
*/
static ELLLIST lset_stack = ELLLIST_INIT;
static epicsMutexId bkpt_stack_sem = 0;
/*
* Stores the last lockset continued or stepped from.
* dbs() and dbc() will print a message if the current
* lockset to be continued from differs from this
* variable.
*/
static unsigned long last_lset = 0;
/*
* FIND_LOCKSET() finds the stack entry
* whose l_num field matches precord's
* lset field. The node that is found
* is returned in "pnode."
*/
#define FIND_LOCKSET(precord, pnode) \
pnode = (struct LS_LIST *) ellFirst(&lset_stack); \
while ((pnode) != NULL) { \
if (pnode->l_num == dbLockGetLockId(precord)) break; \
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode); \
} \
/*
* FIND_QUEUE_ENTRY() matches entries in an
* entry point queue. pep_queue is the queue
* being searched, pqe is the pointer to the
* queue entry found, and precord is the record
* being searched for in *pep_queue.
*/
#define FIND_QUEUE_ENTRY(pep_queue, pqe, precord) \
pqe = (struct EP_LIST *) ellFirst(pep_queue); \
while ((pqe) != NULL) { \
if ((pqe)->entrypoint == (precord)) break; \
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe); \
} \
/*
* Fills out pnode and precord structures for dbc() and dbs()
* MUST LOCK OUT STACK BEFORE ENTRY
*/
static long FIND_CONT_NODE(
const char *record_name,
struct LS_LIST **ppnode,
struct dbCommon **pprecord)
{
struct dbAddr addr;
struct LS_LIST *pnode;
struct dbCommon *precord = NULL;
long status = 0;
if (record_name == NULL) {
/*
* Search through stack, taking the first entry that
* is currently stopped at a breakpoint.
*/
pnode = (struct LS_LIST *) ellFirst(&lset_stack);
while (pnode != NULL) {
if (pnode->precord != NULL) {
precord = pnode->precord;
break;
}
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode);
}
if (pnode == NULL) {
printf(" BKPT> No records are currently stopped\n");
return(S_db_notStopped);
}
}
else {
/*
* Convert name to address
*/
status = dbNameToAddr(record_name, &addr);
if (status == S_db_notFound)
printf(" BKPT> Record %s not found\n", record_name);
if (status != 0)
return(status);
precord = addr.precord;
FIND_LOCKSET(precord, pnode);
if (pnode == NULL || pnode->precord == NULL) {
printf(" BKPT> Currently not stopped in this lockset\n");
return(S_db_notStopped);
}
}
*pprecord = precord;
*ppnode = pnode;
return(0);
}
/*
* Initialise the breakpoint stack
*/
void dbBkptInit(void)
{
if (! bkpt_stack_sem) {
bkpt_stack_sem = epicsMutexMustCreate();
lset_stack_count = 0;
}
}
/*
* Add breakpoint to a lock set
* 1. Convert name to address and check breakpoint mask.
* 2. Lock database.
* 3. If empty, initialize lock set stack and its semaphore.
* 4. Take that semaphore.
* 5. Find lockset in the list. If it doesn't exist, create it.
* 6. Turn on breakpoint field in record.
* 7. Add breakpoint to list of breakpoints in structure.
* 8. Spawn continuation task if it isn't already running.
*/
long dbb(const char *record_name)
{
struct dbAddr addr;
struct LS_LIST *pnode;
struct BP_LIST *pbl;
struct dbCommon *precord;
long status;
/*
* Convert name to address
*/
status = dbNameToAddr(record_name, &addr);
if (status == S_db_notFound)
printf(" BKPT> Record %s not found\n", record_name);
if (status != 0) return(status);
precord = addr.precord;
if (precord->bkpt & BKPT_ON_MASK) {
printf(" BKPT> Breakpoint already set in this record\n");
return(S_db_bkptSet);
}
dbScanLock(precord);
/*
* Add lock set to the stack of lock sets that
* contain breakpoints and/or stopped records.
*/
epicsMutexMustLock(bkpt_stack_sem);
FIND_LOCKSET(precord, pnode);
if (pnode == NULL) {
/* lockset not found, create node, add to end of list */
pnode = (struct LS_LIST *) malloc(sizeof(struct LS_LIST));
if (pnode == NULL) {
printf(" BKPT> Out of memory\n");
dbScanUnlock(precord);
epicsMutexUnlock(bkpt_stack_sem);
return(1);
}
pnode->precord = NULL;
/* initialize breakpoint list */
ellInit(&pnode->bp_list);
/* initialize entry point queue */
ellInit(&pnode->ep_queue);
/* create execution semaphore */
pnode->ex_sem = epicsEventCreate(epicsEventEmpty);
if (pnode->ex_sem == NULL) {
printf(" BKPT> Out of memory\n");
dbScanUnlock(precord);
epicsMutexUnlock(bkpt_stack_sem);
return(1);
}
pnode->taskid = 0;
pnode->step = 0;
pnode->l_num = dbLockGetLockId(precord);
ellAdd(&lset_stack, (ELLNODE *)pnode);
++lset_stack_count;
}
/*
* Add record to breakpoint list
*/
pbl = (struct BP_LIST *) malloc(sizeof(struct BP_LIST));
if (pbl == NULL) {
printf(" BKPT> Out of memory\n");
dbScanUnlock(precord);
epicsMutexUnlock(bkpt_stack_sem);
return(1);
}
pbl->precord = precord;
ellAdd(&pnode->bp_list, (ELLNODE *)pbl);
/*
* Turn on breakpoint field in record
*/
precord->bkpt |= BKPT_ON_MASK;
if (! pnode->taskid) {
#ifdef BKPT_DIAG
printf(" BKPT> Spawning task: %s\n", precord->name);
#endif
/*
* Spawn continuation task
*/
pnode->taskid = epicsThreadCreate("bkptCont",epicsThreadPriorityScanLow-1,
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)dbBkptCont,precord);
if (pnode->taskid == 0) {
printf(" BKPT> Cannot spawn task to process record\n");
pnode->taskid = 0;
dbScanUnlock(precord);
epicsMutexUnlock(bkpt_stack_sem);
return(1);
}
}
epicsMutexUnlock(bkpt_stack_sem);
dbScanUnlock(precord);
return(0);
}
/*
* Remove breakpoint from a record
* 1. Convert name to address and check breakpoint mask.
* 2. Lock database and take stack semaphore.
* 3. Find structure for record's lockset (in stack).
* 4. Find and delete record from breakpoint list.
* 5. Turn off break point field.
* 6. Give up semaphore to "signal" bkptCont task to quit.
*/
long dbd(const char *record_name)
{
struct dbAddr addr;
struct LS_LIST *pnode;
struct BP_LIST *pbl;
struct dbCommon *precord;
long status;
/*
* Convert name to address
*/
status = dbNameToAddr(record_name, &addr);
if (status == S_db_notFound)
printf(" BKPT> Record %s not found\n", record_name);
if (status != 0) return(status);
precord = addr.precord;
if (!(precord->bkpt & BKPT_ON_MASK)) {
printf(" BKPT> No breakpoint set in this record\n");
return(S_db_bkptNotSet);
}
dbScanLock(precord);
epicsMutexMustLock(bkpt_stack_sem);
FIND_LOCKSET(precord, pnode);
if (pnode == NULL) {
/* not found, error ! */
printf(" BKPT> Logic Error in dbd()\n");
precord->bkpt &= BKPT_OFF_MASK;
epicsMutexUnlock(bkpt_stack_sem);
dbScanUnlock(precord);
return(S_db_bkptLogic);
}
/*
* Remove record from breakpoint list
*/
/* find record in list */
pbl = (struct BP_LIST *) ellFirst(&pnode->bp_list);
while (pbl != NULL) {
if (pbl->precord == precord) {
ellDelete(&pnode->bp_list, (ELLNODE *)pbl);
free(pbl);
break;
}
pbl = (struct BP_LIST *) ellNext((ELLNODE *)pbl);
}
if (pbl == NULL) {
printf(" BKPT> Logic Error in dbd()\n");
precord->bkpt &= BKPT_OFF_MASK;
epicsMutexUnlock(bkpt_stack_sem);
dbScanUnlock(precord);
return(S_db_bkptLogic);
}
/*
* Turn off breakpoint field in record
*/
precord->bkpt &= BKPT_OFF_MASK;
/*
* If there are no more breakpoints, give up semaphore
* to cause the bkptCont task to quit.
*/
if (ellCount(&pnode->bp_list) == 0)
epicsEventSignal(pnode->ex_sem);
epicsMutexUnlock(bkpt_stack_sem);
dbScanUnlock(precord);
return(0);
}
/*
* Continue processing in a lock set
* 1. Find top node in the lockset stack.
* 2. Turn off stepping mode.
* 2. Resume dbBkptCont.
*/
long dbc(const char *record_name)
{
struct LS_LIST *pnode;
struct dbCommon *precord = NULL;
long status = 0;
epicsMutexMustLock(bkpt_stack_sem);
status = FIND_CONT_NODE(record_name, &pnode, &precord);
if (status) {
epicsMutexUnlock(bkpt_stack_sem);
return(status);
}
if (record_name == NULL && last_lset != pnode->l_num)
printf(" BKPT> Continuing: %s\n", pnode->precord->name);
last_lset = pnode->l_num;
/*
* Turn off stepping mode
*/
pnode->step = 0;
/*
* Resume dbBkptCont() until dbProcess() is executed
* for a record with a breakpoint. This occurs
* because stepping mode has been switched off.
*/
epicsThreadResume(pnode->taskid);
epicsMutexUnlock(bkpt_stack_sem);
return(0);
}
/*
* Step through record processing
* 1. Find top node in lockset stack.
* 2. Resume dbBkptCont.
*/
long dbs(const char *record_name)
{
struct LS_LIST *pnode;
struct dbCommon *precord = NULL;
long status = 0;
epicsMutexMustLock(bkpt_stack_sem);
status = FIND_CONT_NODE(record_name, &pnode, &precord);
if (status) {
epicsMutexUnlock(bkpt_stack_sem);
return(status);
}
if (last_lset != pnode->l_num && record_name == NULL)
printf(" BKPT> Stepping: %s\n", pnode->precord->name);
last_lset = pnode->l_num;
epicsThreadResume(pnode->taskid);
epicsMutexUnlock(bkpt_stack_sem);
return(0);
}
/*
* Task for continuing record processing
* 1. Find lockset in stack for precord.
* DO 2-3 while breakpoints exist in the lockset.
* 2. Wait on execution semaphore ...
* 3. Run through every entrypoint in queue, processing
* those that are scheduled.
* 4. Free resources for lockset, and exit task.
*/
static void dbBkptCont(dbCommon *precord)
{
struct LS_LIST *pnode;
struct EP_LIST *pqe = NULL;
/*
* Reset breakpoint, process record, and
* reset bkpt field in record
*/
epicsMutexMustLock(bkpt_stack_sem);
FIND_LOCKSET(precord, pnode);
if (pnode == NULL) {
printf(" BKPT> Logic error in dbBkptCont()\n");
return;
}
/*
* For every entrypoint scheduled, process. Run process
* until there are no more breakpoints remaining in a
* lock set.
*/
do {
/* Give up semaphore before waiting to run ... */
epicsMutexUnlock(bkpt_stack_sem);
/* Wait to run */
epicsEventMustWait(pnode->ex_sem);
/* Bkpt stack must still be stable ! */
epicsMutexMustLock(bkpt_stack_sem);
pqe = (struct EP_LIST *) ellFirst(&pnode->ep_queue);
/* Run through entrypoint queue */
while (pqe != NULL) {
/* check if entrypoint is currently scheduled */
if (pqe->sched) {
/* save current entrypoint */
pnode->current_ep = pqe->entrypoint;
/* lock the lockset, process record, unlock */
dbScanLock(precord);
dbProcess(pqe->entrypoint);
dbScanUnlock(precord);
/* reset schedule and stepping flag - Do this AFTER processing */
pqe->sched = 0;
pnode->step = 0;
}
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe);
}
/* Reset precord. (Since no records are at a breakpoint) */
pnode->precord = NULL;
} while (ellCount(&pnode->bp_list) != 0);
/* remove node from lockset stack */
ellDelete(&lset_stack, (ELLNODE *)pnode);
--lset_stack_count;
/* free entrypoint queue */
ellFree(&pnode->ep_queue);
/* remove execution semaphore */
epicsEventDestroy(pnode->ex_sem);
printf("\n BKPT> End debug of lockset %lu\n-> ", pnode->l_num);
/* free list node */
free(pnode);
epicsMutexUnlock(bkpt_stack_sem);
}
/*
* Process breakpoint
* Returns a zero if dbProcess() is to execute
* record support, a one if dbProcess() is to
* skip over record support. See dbProcess().
*
* 1. See if there is at least a breakpoint set somewhere
* in precord's lockset. If not, return immediately.
* 2. Check the disable flag.
* 3. Add entry points to the queue for future stepping and
* schedule new entrypoints for the continuation task.
* 4. Check the pact flag.
* 5. Check to see if there is a breakpoint set in a record, and
* if so, turn on stepping mode.
* 6. If stepping mode is set, stop and report the breakpoint.
*/
int dbBkpt(dbCommon *precord)
{
struct LS_LIST *pnode;
struct EP_LIST *pqe;
/*
* It is crucial that operations in dbBkpt() execute
* in the correct order or certain features in the
* breakpoint handler will not work as expected.
*/
/*
* Take and give a semaphore to check for breakpoints
* every time a record is processed. Slow. Thank
* goodness breakpoint checking is turned off during
* normal operation.
*/
epicsMutexMustLock(bkpt_stack_sem);
FIND_LOCKSET(precord, pnode);
epicsMutexUnlock(bkpt_stack_sem);
if (pnode == NULL) {
/* no breakpoints in precord's lockset */
return(0);
}
/* Check disable flag */
dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
if (precord->disa == precord->disv) {
/*
* Do not process breakpoints if the record is disabled,
* but allow disable alarms. Alarms will be raised
* in dbProcess() because returning 0 allows dbProcess()
* to continue. However processing will be prevented
* because disa and disv will be examined again in
* dbProcess(). Note that checking for pact will occur
* before checking for disa and disv in dbProcess().
*/
return(0);
}
/*
* Queue entry points for future stepping. The taskid comparison
* is used to determine if the source of processing is the
* continuation task or an external source. If it is an external
* source, queue its execution, but dump out of dbProcess without
* calling record support.
*/
if (pnode->taskid && (epicsThreadGetIdSelf() != pnode->taskid)) {
/* CONTINUE TASK CANNOT ENTER HERE */
/*
* Add an entry point to queue, if it does
* not already exist.
*/
FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord);
if (pqe == NULL) {
pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST));
if (pqe == NULL)
return(1);
pqe->entrypoint = precord;
pqe->count = 1;
epicsTimeGetCurrent(&pqe->time);
pqe->sched = 0;
#ifdef BKPT_DIAG
printf(" BKPT> Adding entrypoint %s to queue\n", precord->name);
#endif
/*
* Take semaphore, wait on continuation task
*/
epicsMutexMustLock(bkpt_stack_sem);
/* Add entry to queue */
ellAdd(&pnode->ep_queue, (ELLNODE *)pqe);
epicsMutexUnlock(bkpt_stack_sem);
}
else {
if (pqe->count < MAX_EP_COUNT)
pqe->count++;
}
/* check pact */
if (! precord->pact) {
/* schedule if pact not set */
pqe->sched = 1;
/*
* Release the semaphore, letting the continuation
* task begin execution of the new entrypoint.
*/
epicsEventSignal(pnode->ex_sem);
}
return(1);
}
/*
* Don't mess with breakpoints if pact set! Skip
* over rest of dbProcess() since we don't want
* alarms going off. The pact flag is checked
* AFTER entry point queuing so that the record
* timing feature will work properly.
*/
if (precord->pact)
return(1);
/* Turn on stepping mode if a breakpoint is found */
if (precord->bkpt & BKPT_ON_MASK) {
pnode->step = 1;
#ifdef BKPT_DIAG
printf(" BKPT> Bkpt detected: %s\n", precord->name);
#endif
}
/*
* If we are currently stepping through the lockset,
* suspend task.
*/
if (pnode->step) {
printf("\n BKPT> Stopped at: %s within Entrypoint: %s\n-> ",
precord->name, pnode->current_ep->name);
pnode->precord = precord;
/* Move current lockset to top of stack */
ellDelete(&lset_stack, (ELLNODE *)pnode);
ellInsert(&lset_stack, NULL, (ELLNODE *)pnode);
/*
* Unlock database while the task suspends itself. This
* is done so that dbb() dbd() dbc() dbs() may be used
* when the task is suspended. Scan tasks that also
* use the scan lock feature will not be hung during
* a breakpoint, so that records in other locksets will
* continue to be processed. Cross your fingers, this
* might actually work !
*/
epicsMutexUnlock(bkpt_stack_sem);
dbScanUnlock(precord);
epicsThreadSuspendSelf();
dbScanLock(precord);
epicsMutexMustLock(bkpt_stack_sem);
}
return(0);
}
/* print record after processing */
void dbPrint(dbCommon *precord )
{
struct LS_LIST *pnode;
if (! (precord->bkpt & BKPT_PRINT_MASK))
return;
FIND_LOCKSET(precord, pnode);
/* do not print if lockset does not currently contain breakpoints */
if (pnode == NULL)
return;
printf("\n");
dbpr(precord->name, 2);
printf("-> ");
}
/* print stopped record */
long dbp(const char *record_name, int interest_level)
{
struct LS_LIST *pnode;
struct dbCommon *precord = NULL;
int status;
epicsMutexMustLock(bkpt_stack_sem);
/* find pnode and precord pointers */
status = FIND_CONT_NODE(record_name, &pnode, &precord);
if (status) {
epicsMutexUnlock(bkpt_stack_sem);
return(status);
}
/* print out record's fields */
dbpr(precord->name, (interest_level == 0) ? 2 : interest_level);
epicsMutexUnlock(bkpt_stack_sem);
return(0);
}
/* toggle printing after processing a certain record */
long dbap(const char *record_name)
{
struct dbAddr addr;
struct dbCommon *precord;
long status;
/*
* Convert name to address
*/
status = dbNameToAddr(record_name, &addr);
if (status == S_db_notFound)
printf(" BKPT> Record %s not found\n", record_name);
if (status != 0) return(status);
precord = addr.precord;
/*
* Toggle print after process field in record
*/
if (precord->bkpt & BKPT_PRINT_MASK) {
printf(" BKPT> Auto print off for record %s\n", precord->name);
precord->bkpt &= BKPT_PRINT_OFF_MASK;
}
else {
printf(" BKPT> Auto print on for record %s\n", precord->name);
precord->bkpt |= BKPT_PRINT_MASK;
}
return(0);
}
/* print list of stopped records, and breakpoints set in locksets */
long dbstat(void)
{
struct LS_LIST *pnode;
struct BP_LIST *pbl;
struct EP_LIST *pqe;
epicsTimeStamp time;
epicsMutexMustLock(bkpt_stack_sem);
epicsTimeGetCurrent(&time);
/*
* Traverse list, reporting stopped records
*/
pnode = (struct LS_LIST *) ellFirst(&lset_stack);
while (pnode != NULL) {
if (pnode->precord != NULL) {
printf("LSet: %lu Stopped at: %-28.28s #B: %5.5d T: %p\n",
pnode->l_num, pnode->precord->name, ellCount(&pnode->bp_list), pnode->taskid);
/* for each entrypoint detected, print out entrypoint statistics */
pqe = (struct EP_LIST *) ellFirst(&pnode->ep_queue);
while (pqe != NULL) {
double diff = epicsTimeDiffInSeconds(&time,&pqe->time);
if (diff) {
printf(" Entrypoint: %-28.28s #C: %5.5lu C/S: %7.1f\n",
pqe->entrypoint->name, pqe->count,diff);
}
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe);
}
}
else {
printf("LSet: %lu #B: %5.5d T: %p\n",
pnode->l_num, ellCount(&pnode->bp_list), pnode->taskid);
}
/*
* Print out breakpoints set in the lock set
*/
pbl = (struct BP_LIST *) ellFirst(&pnode->bp_list);
while (pbl != NULL) {
printf(" Breakpoint: %-28.28s", pbl->precord->name);
/* display auto print flag */
if (pbl->precord->bkpt & BKPT_PRINT_MASK)
printf(" (ap)\n");
else
printf("\n");
pbl = (struct BP_LIST *) ellNext((ELLNODE *)pbl);
}
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode);
}
epicsMutexUnlock(bkpt_stack_sem);
return(0);
}
/*
* Process a record without printing it.
*/
long dbprc(char *record_name)
{
struct dbAddr addr;
struct dbCommon *precord;
long status;
/*
* Convert name to address
*/
status = dbNameToAddr(record_name, &addr);
if (status == S_db_notFound)
printf(" BKPT> Record %s not found\n", record_name);
if (status != 0) return(status);
precord = addr.precord;
/* lock lockset, process record, unlock lockset */
dbScanLock(precord);
status = dbProcess(precord);
dbScanUnlock(precord);
return(status);
}
#ifdef BKPT_DIAG
/* Reset breakpoints */
int dbreset()
{
epicsMutexUnlock(bkpt_stack_sem);
return(0);
}
#endif
+103
View File
@@ -0,0 +1,103 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbBkpt.h */
/*
* Author: Matthew Needes
* Date: 8-30-93
*/
#ifndef INCdbBkptsh
#define INCdbBkptsh 1
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Structure containing a list of set breakpoints
* in a lockset
*/
struct BP_LIST {
ELLNODE *next_list;
ELLNODE *prev_list;
struct dbCommon *precord;
};
/*
* Structure containing queue of entrypoints
* detected for a lockset.
*/
struct EP_LIST {
ELLNODE *next_list;
ELLNODE *prev_list;
struct dbCommon *entrypoint; /* pointer to entry point in lockset */
unsigned long count; /* number of times record processed */
epicsTimeStamp time; /* time record first logged */
char sched; /* schedule record for next dbContTask() pass */
};
/*
* Structure for stack of lock sets that
* currently contain breakpoints. (uses ellLib)
*/
struct LS_LIST {
ELLNODE *next_list;
ELLNODE *prev_list;
struct dbCommon *precord;/* points to where execution is currently stopped */
struct dbCommon *current_ep; /* current entrypoint */
ELLLIST bp_list; /* list of records containing breakpoints in a lockset */
ELLLIST ep_queue; /* queue of entrypoints found so far */
epicsEventId ex_sem; /* semaphore for execution queue */
epicsThreadId taskid; /* saved taskid for the task in stepping mode */
int step; /* one if currently "stepping," else zero */
unsigned long l_num; /* lockset number */
};
/* Values for BKPT (breakpoint) field in record */
/* 1st bit = 0 if breakpoint is not set, */
/* 1 if breakpoint set */
/* 2nd bit = 0 if no printing after processing */
/* 1 if print after processing set */
/* Breakpoint Masks */
#define BKPT_ON_MASK 0x001
#define BKPT_OFF_MASK 0x0FE
#define BKPT_PRINT_MASK 0x002
#define BKPT_PRINT_OFF_MASK 0x0FD
#define MAX_EP_COUNT 99999
epicsShareFunc void dbBkptInit(void);
epicsShareFunc long dbb(const char *recordname);
epicsShareFunc long dbd(const char *recordname);
epicsShareFunc long dbc(const char *recordname);
epicsShareFunc long dbs(const char *recordname);
epicsShareFunc long dbstat(void);
epicsShareFunc long dbp(
const char *record_name, int interest_level);
epicsShareFunc long dbap(const char *record_name);
epicsShareFunc int dbBkpt(struct dbCommon *precord);
epicsShareFunc void dbPrint(struct dbCommon *precord);
epicsShareFunc long dbprc(char *record_name);
extern long lset_stack_count;
#ifdef __cplusplus
}
#endif
#endif
+239
View File
@@ -0,0 +1,239 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* NOTES:
* 1) This interface is preliminary and will change in the future
*/
#ifndef dbCACh
#define dbCACh
#ifdef epicsExportSharedSymbols
# define dbCACh_restore_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "stdlib.h"
#include <memory> // std::auto_ptr
#include "tsDLList.h"
#include "tsFreeList.h"
#include "resourceLib.h"
#include "cacIO.h"
#include "compilerDependencies.h"
#ifdef dbCACh_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "db_access.h"
#include "dbNotify.h"
#include "dbEvent.h"
#include "dbChannel.h"
#include "dbLock.h"
#include "dbCommon.h"
#include "db_convert.h"
#include "resourceLib.h"
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType notifyPutType );
extern "C" void putNotifyCompletion ( processNotify *ppn );
class dbContext;
class dbChannelIO;
class dbPutNotifyBlocker;
class dbSubscriptionIO;
class dbBaseIO
: public chronIntIdRes < dbBaseIO > {
public:
virtual dbSubscriptionIO * isSubscription () = 0;
virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0;
virtual void show ( unsigned level ) const = 0;
dbBaseIO ();
dbBaseIO ( const dbBaseIO & );
dbBaseIO & operator = ( const dbBaseIO & );
protected:
virtual ~dbBaseIO() {}
};
extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbChannel *dbch,
int eventsRemaining, struct db_field_log *pfl );
class dbSubscriptionIO :
public tsDLNode < dbSubscriptionIO >,
public dbBaseIO {
public:
dbSubscriptionIO (
epicsGuard < epicsMutex > &, epicsMutex &,
dbContext &, dbChannelIO &, struct dbChannel *, cacStateNotify &,
unsigned type, unsigned long count, unsigned mask, dbEventCtx );
void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & );
void unsubscribe ( CallbackGuard &, epicsGuard < epicsMutex > & );
void channelDeleteException ( CallbackGuard &, epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & ))
private:
epicsMutex & mutex;
unsigned long count;
cacStateNotify & notify;
dbChannelIO & chan;
dbEventSubscription es;
unsigned type;
unsigned id;
dbSubscriptionIO * isSubscription ();
friend void dbSubscriptionEventCallback (
void * pPrivate, struct dbChannel * dbch,
int eventsRemaining, struct db_field_log * pfl );
dbSubscriptionIO ( const dbSubscriptionIO & );
dbSubscriptionIO & operator = ( const dbSubscriptionIO & );
virtual ~dbSubscriptionIO ();
void operator delete ( void * );
};
class dbContext;
class dbContextPrivateListOfIO {
public:
dbContextPrivateListOfIO ();
~dbContextPrivateListOfIO ();
private:
tsDLList < dbSubscriptionIO > eventq;
dbPutNotifyBlocker * pBlocker;
friend class dbContext;
dbContextPrivateListOfIO ( const dbContextPrivateListOfIO & );
dbContextPrivateListOfIO & operator = ( const dbContextPrivateListOfIO & );
};
class dbContextReadNotifyCacheAllocator {
public:
dbContextReadNotifyCacheAllocator ();
~dbContextReadNotifyCacheAllocator ();
char * alloc ( unsigned long size );
void free ( char * pFree );
void show ( unsigned level ) const;
private:
struct cacheElem_t {
size_t size;
struct cacheElem_t * pNext;
char buf[1];
};
unsigned long _readNotifyCacheSize;
cacheElem_t * _pReadNotifyCache;
void reclaimAllCacheEntries ();
dbContextReadNotifyCacheAllocator ( const dbContextReadNotifyCacheAllocator & );
dbContextReadNotifyCacheAllocator & operator = ( const dbContextReadNotifyCacheAllocator & );
};
class dbContextReadNotifyCache {
public:
dbContextReadNotifyCache ( epicsMutex & );
void callReadNotify ( epicsGuard < epicsMutex > &,
struct dbChannel * dbch, unsigned type, unsigned long count,
cacReadNotify & notify );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
private:
dbContextReadNotifyCacheAllocator _allocator;
epicsMutex & _mutex;
dbContextReadNotifyCache ( const dbContextReadNotifyCache & );
dbContextReadNotifyCache & operator = ( const dbContextReadNotifyCache & );
};
class dbContext : public cacContext {
public:
dbContext ( epicsMutex & cbMutex, epicsMutex & mutex,
cacContextNotify & notify );
virtual ~dbContext ();
void destroyChannel ( CallbackGuard &,epicsGuard < epicsMutex > &, dbChannelIO & );
void callReadNotify ( epicsGuard < epicsMutex > &,
struct dbChannel * dbch, unsigned type, unsigned long count,
cacReadNotify & notify );
void callStateNotify ( struct dbChannel * dbch, unsigned type, unsigned long count,
const struct db_field_log * pfl, cacStateNotify & notify );
void subscribe (
epicsGuard < epicsMutex > &,
struct dbChannel * dbch, dbChannelIO & chan,
unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notify, cacChannel::ioid * pId );
void initiatePutNotify (
epicsGuard < epicsMutex > &, dbChannelIO &, struct dbChannel *,
unsigned type, unsigned long count, const void * pValue,
cacWriteNotify & notify, cacChannel::ioid * pId );
void show ( unsigned level ) const;
void showAllIO ( const dbChannelIO & chan, unsigned level ) const;
void destroyAllIO ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > &, dbChannelIO & chan );
void ioCancel ( CallbackGuard &, epicsGuard < epicsMutex > &,
dbChannelIO & chan, const cacChannel::ioid &id );
void ioShow ( epicsGuard < epicsMutex > &,
const cacChannel::ioid & id, unsigned level ) const;
private:
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > dbPutNotifyBlockerFreeList;
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > dbSubscriptionIOFreeList;
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > dbChannelIOFreeList;
chronIntIdResTable < dbBaseIO > ioTable;
dbContextReadNotifyCache readNotifyCache;
dbEventCtx ctx;
unsigned long stateNotifyCacheSize;
epicsMutex & mutex;
epicsMutex & cbMutex;
cacContextNotify & notify;
std::auto_ptr < cacContext > pNetContext;
char * pStateNotifyCache;
bool isolated;
cacChannel & createChannel (
epicsGuard < epicsMutex > &,
const char * pChannelName, cacChannelNotify &,
cacChannel::priLev );
void flush (
epicsGuard < epicsMutex > & );
unsigned circuitCount (
epicsGuard < epicsMutex > & ) const;
void selfTest (
epicsGuard < epicsMutex > & ) const;
unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const;
void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
dbContext ( const dbContext & );
dbContext & operator = ( const dbContext & );
};
inline dbContextPrivateListOfIO::dbContextPrivateListOfIO () :
pBlocker ( 0 )
{
}
inline dbContextPrivateListOfIO::~dbContextPrivateListOfIO ()
{
assert ( ! this->pBlocker );
}
inline void dbContext::callReadNotify (
epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
unsigned type, unsigned long count, cacReadNotify & notifyIn )
{
guard.assertIdenticalMutex ( this-> mutex );
this->readNotifyCache.callReadNotify ( guard, dbch, type, count, notifyIn );
}
#endif // dbCACh
File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
/*************************************************************************\
* Copyright (c) 2015 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbCa.h */
#ifndef INCdbCah
#define INCdbCah
#include "dbLink.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*dbCaCallback)(void *userPvt);
epicsShareFunc void dbCaCallbackProcess(void *usrPvt);
epicsShareFunc void dbCaLinkInit(void); /* internal initialization for iocBuild() */
epicsShareFunc void dbCaLinkInitIsolated(void); /* internal initialization for iocBuildIsolated() */
epicsShareFunc void dbCaRun(void);
epicsShareFunc void dbCaPause(void);
epicsShareFunc void dbCaShutdown(void);
struct dbLocker;
epicsShareFunc void dbCaAddLinkCallback(struct link *plink,
dbCaCallback connect, dbCaCallback monitor, void *userPvt);
epicsShareFunc long dbCaAddLink(struct dbLocker *locker, struct link *plink, short dbfType);
epicsShareFunc void dbCaRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc long dbCaGetLink(struct link *plink,
short dbrType, void *pbuffer, long *nRequest);
epicsShareFunc long dbCaGetAttributes(const struct link *plink,
dbCaCallback callback, void *userPvt);
epicsShareFunc long dbCaPutLinkCallback(struct link *plink,
short dbrType, const void *pbuffer,long nRequest,
dbCaCallback callback, void *userPvt);
epicsShareFunc long dbCaPutLink(struct link *plink,short dbrType,
const void *pbuffer,long nRequest);
extern struct ca_client_context * dbCaClientContext;
#ifdef EPICS_DBCA_PRIVATE_API
epicsShareFunc void dbCaSync(void);
epicsShareFunc unsigned long dbCaGetUpdateCount(struct link *plink);
#endif
/* These macros are for backwards compatibility */
#define dbCaIsLinkConnected(link) \
dbIsLinkConnected(link)
#define dbCaGetLinkDBFtype(link) \
dbGetLinkDBFtype(link)
#define dbCaGetNelements(link, nelements) \
dbGetNelements(link, nelements)
#define dbCaGetSevr(link, sevr) \
dbGetAlarm(link, NULL, sevr)
#define dbCaGetAlarm(link, stat, sevr) \
dbGetAlarm(link, stat, sevr)
#define dbCaGetTimeStamp(link, pstamp) \
dbGetTimeStamp(link, pstamp)
#define dbCaGetControlLimits(link, low, high) \
dbGetControlLimits(link, low, high)
#define dbCaGetGraphicLimits(link, low, high) \
dbGetGraphicLimits(link, low, high)
#define dbCaGetAlarmLimits(link, lolo, low, high, hihi) \
dbGetAlarmLimits(link, lolo, low, high, hihi)
#define dbCaGetPrecision(link, prec) \
dbGetPrecision(link, prec)
#define dbCaGetUnits(link, units, unitSize) \
dbGetUnits(link, units, unitSize)
#define dbCaScanFwdLink(link) \
dbScanFwdLink(link)
#ifdef __cplusplus
}
#endif
#endif /*INCdbCah*/
+96
View File
@@ -0,0 +1,96 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbCaPvt.h
*
* Original Authors: Bob Dalesio, Marty Kraimer
*
*/
#ifndef INC_dbCaPvt_H
#define INC_dbCaPvt_H
#include "dbCa.h"
#include "ellLib.h"
#include "epicsMutex.h"
#include "epicsTypes.h"
#include "link.h"
/* link_action mask */
#define CA_CLEAR_CHANNEL 0x1
#define CA_CONNECT 0x2
#define CA_WRITE_NATIVE 0x4
#define CA_WRITE_STRING 0x8
#define CA_MONITOR_NATIVE 0x10
#define CA_MONITOR_STRING 0x20
#define CA_GET_ATTRIBUTES 0x40
#define CA_SYNC 0x1000
/* write type */
#define CA_PUT 0x1
#define CA_PUT_CALLBACK 0x2
typedef struct caLink
{
ELLNODE node;
int refcount;
epicsMutexId lock;
struct link *plink;
char *pvname;
chid chid;
short link_action;
/* The following have new values after each data event*/
epicsEnum16 sevr;
epicsEnum16 stat;
epicsTimeStamp timeStamp;
/* The following have values after connection*/
short dbrType;
size_t elementSize; /* size of one element in pgetNative */
unsigned long nelements; /* PVs max array size */
unsigned long usedelements; /* currently used in pgetNative */
unsigned long putnelements; /* currently used in pputNative */
char hasReadAccess;
char hasWriteAccess;
char isConnected;
char gotFirstConnection;
/* The following are for dbCaAddLinkCallback */
dbCaCallback connect;
dbCaCallback monitor;
void *userPvt;
/* The following are for write request */
short putType;
dbCaCallback putCallback;
void *putUserPvt;
/* The following are for access to additional attributes*/
char gotAttributes;
dbCaCallback getAttributes;
void *getAttributesPvt;
/* The following have values after getAttribEventCallback*/
double controlLimits[2];
double displayLimits[2];
double alarmLimits[4];
short precision;
char units[MAX_UNITS_SIZE]; /* units of value */
/* The following are for handling data*/
void *pgetNative;
char *pgetString;
void *pputNative;
char *pputString;
char gotInNative;
char gotInString;
char gotOutNative;
char gotOutString;
char newOutNative;
char newOutString;
unsigned char scanningOnce;
/* The following are for dbcar*/
unsigned long nDisconnect;
unsigned long nNoWrite; /*only modified by dbCaPutLink*/
unsigned long nUpdate;
}caLink;
#endif /* INC_dbCaPvt_H */
+206
View File
@@ -0,0 +1,206 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbCaTest.c */
/****************************************************************
*
* Author: Marty Kraimer
* Date: 10APR96
*
****************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "dbDefs.h"
#include "epicsEvent.h"
#include "epicsPrint.h"
#include "epicsStdio.h"
#define epicsExportSharedSymbols
#include "dbStaticLib.h"
#undef epicsExportSharedSymbols
/*definitions needed because of old vs new database access*/
#undef DBR_SHORT
#undef DBR_PUT_ACKT
#undef DBR_PUT_ACKS
#undef VALID_DB_REQ
#undef INVALID_DB_REQ
/*end of conflicting definitions*/
#include "cadef.h"
/*define DB_CONVERT_GBLSOURCE because db_access.c does not include db_access.h*/
#define DB_CONVERT_GBLSOURCE
#define epicsExportSharedSymbols
#include "db_access.h"
#include "db_access_routines.h"
#include "dbCa.h"
#include "dbCaPvt.h"
#include "dbCaTest.h"
#include "dbCommon.h"
#include "db_convert.h"
#include "dbLock.h"
#include "link.h"
long dbcar(char *precordname, int level)
{
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
dbCommon *precord;
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
DBLINK *plink;
int ncalinks=0;
int nconnected=0;
int noReadAccess=0;
int noWriteAccess=0;
unsigned long nDisconnect=0;
unsigned long nNoWrite=0;
caLink *pca;
int j;
if (!precordname || precordname[0] == '\0' || !strcmp(precordname, "*")) {
precordname = NULL;
printf("CA links in all records\n\n");
} else {
printf("CA links in record named '%s'\n\n", precordname);
}
dbInitEntry(pdbbase,pdbentry);
status = dbFirstRecordType(pdbentry);
while (!status) {
status = dbFirstRecord(pdbentry);
while (!status) {
if (precordname ?
!strcmp(precordname, dbGetRecordName(pdbentry)) :
!dbIsAlias(pdbentry)) {
pdbRecordType = pdbentry->precordType;
precord = (dbCommon *)pdbentry->precnode->precord;
dbScanLock(precord);
for (j=0; j<pdbRecordType->no_links; j++) {
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if (plink->type == CA_LINK) {
ncalinks++;
pca = (caLink *)plink->value.pv_link.pvt;
if (pca
&& pca->chid
&& (ca_field_type(pca->chid) != TYPENOTCONN)) {
nconnected++;
nDisconnect += pca->nDisconnect;
nNoWrite += pca->nNoWrite;
if (!ca_read_access(pca->chid)) noReadAccess++;
if (!ca_write_access(pca->chid)) noWriteAccess++;
if (level>1) {
int rw = ca_read_access(pca->chid) |
ca_write_access(pca->chid) << 1;
static const char *rights[4] = {
"No Access", "Read Only",
"Write Only", "Read/Write"
};
int mask = plink->value.pv_link.pvlMask;
printf("%28s.%-4s ==> %-28s (%lu, %lu)\n",
precord->name,
pdbFldDes->name,
plink->value.pv_link.pvname,
pca->nDisconnect,
pca->nNoWrite);
printf("%21s [%s%s%s%s] host %s, %s\n", "",
mask & pvlOptInpNative ? "IN" : " ",
mask & pvlOptInpString ? "IS" : " ",
mask & pvlOptOutNative ? "ON" : " ",
mask & pvlOptOutString ? "OS" : " ",
ca_host_name(pca->chid),
rights[rw]);
}
} else {
if (level>0) {
printf("%28s.%-4s --> %-28s (%lu, %lu)\n",
precord->name,
pdbFldDes->name,
plink->value.pv_link.pvname,
pca ? pca->nDisconnect : 0,
pca ? pca->nNoWrite : 0);
}
}
}
}
dbScanUnlock(precord);
if (precordname) goto done;
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
done:
if ((level > 1 && nconnected > 0) ||
(level > 0 && ncalinks != nconnected)) printf("\n");
printf("Total %d CA link%s; ",
ncalinks, (ncalinks != 1) ? "s" : "");
printf("%d connected, %d not connected.\n",
nconnected, (ncalinks - nconnected));
printf(" %d can't read, %d can't write.",
noReadAccess, noWriteAccess);
printf(" (%lu disconnects, %lu writes prohibited)\n\n",
nDisconnect, nNoWrite);
dbFinishEntry(pdbentry);
if ( level > 2 && dbCaClientContext != 0 ) {
ca_context_status ( dbCaClientContext, level - 2 );
}
return(0);
}
void dbcaStats(int *pchans, int *pdiscon)
{
DBENTRY dbentry;
DBENTRY *pdbentry = &dbentry;
long status;
DBLINK *plink;
long ncalinks = 0;
long nconnected = 0;
dbInitEntry(pdbbase,pdbentry);
status = dbFirstRecordType(pdbentry);
while (!status) {
dbRecordType *pdbRecordType = pdbentry->precordType;
status = dbFirstRecord(pdbentry);
while (!status) {
dbCommon *precord = (dbCommon *)pdbentry->precnode->precord;
int j;
if (!dbIsAlias(pdbentry)) {
for (j=0; j<pdbRecordType->no_links; j++) {
int i = pdbRecordType->link_ind[j];
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[i];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if (plink->type == CA_LINK) {
ncalinks++;
if (dbCaIsLinkConnected(plink)) {
nconnected++;
}
}
}
}
status = dbNextRecord(pdbentry);
}
status = dbNextRecordType(pdbentry);
}
dbFinishEntry(pdbentry);
if (pchans) *pchans = ncalinks;
if (pdiscon) *pdiscon = ncalinks - nconnected;
}
+26
View File
@@ -0,0 +1,26 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_dbCaTest_H
#define INC_dbCaTest_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc long dbcar(char *recordname,int level);
epicsShareFunc void dbcaStats(int *pchans, int *pdiscon);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbCaTest_H */
+826
View File
@@ -0,0 +1,826 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include "cantProceed.h"
#include "epicsAssert.h"
#include "epicsString.h"
#include "errlog.h"
#include "freeList.h"
#include "gpHash.h"
#include "yajl_parse.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbBase.h"
#include "dbChannel.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "dbLock.h"
#include "dbStaticLib.h"
#include "link.h"
#include "recSup.h"
#include "special.h"
typedef struct parseContext {
dbChannel *chan;
chFilter *filter;
int depth;
} parseContext;
#define CALLIF(rtn) !rtn ? parse_stop : rtn
static void *dbChannelFreeList;
static void *chFilterFreeList;
static void *dbchStringFreeList;
void dbChannelExit(void)
{
freeListCleanup(dbChannelFreeList);
freeListCleanup(chFilterFreeList);
freeListCleanup(dbchStringFreeList);
dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
}
void dbChannelInit (void)
{
if(dbChannelFreeList)
return;
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
}
static void chf_value(parseContext *parser, parse_result *presult)
{
chFilter *filter = parser->filter;
if (*presult == parse_stop || parser->depth > 0)
return;
parser->filter = NULL;
if (filter->plug->fif->parse_end(filter) == parse_continue) {
ellAdd(&parser->chan->filters, &filter->list_node);
} else {
freeListFree(chFilterFreeList, filter);
*presult = parse_stop;
}
}
static int chf_null(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_null)(filter );
chf_value(parser, &result);
return result;
}
static int chf_boolean(void * ctx, int boolVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_boolean)(filter , boolVal);
chf_value(parser, &result);
return result;
}
static int chf_integer(void * ctx, long long integerVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_integer)(filter , integerVal);
chf_value(parser, &result);
return result;
}
static int chf_double(void * ctx, double doubleVal)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_double)(filter , doubleVal);
chf_value(parser, &result);
return result;
}
static int chf_string(void * ctx, const unsigned char * stringVal,
size_t stringLen)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_string)(filter , (const char *) stringVal, stringLen);
chf_value(parser, &result);
return result;
}
static int chf_start_map(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
if (!filter) {
assert(parser->depth == 0);
return parse_continue; /* Opening '{' */
}
++parser->depth;
return CALLIF(filter->plug->fif->parse_start_map)(filter );
}
static int chf_map_key(void * ctx, const unsigned char * key,
size_t stringLen)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
const chFilterPlugin *plug;
parse_result result;
if (filter) {
assert(parser->depth > 0);
return CALLIF(filter->plug->fif->parse_map_key)(filter , (const char *) key, stringLen);
}
assert(parser->depth == 0);
plug = dbFindFilter((const char *) key, stringLen);
if (!plug) {
errlogPrintf("dbChannelCreate: Channel filter '%.*s' not found\n",
(int) stringLen, key);
return parse_stop;
}
filter = freeListCalloc(chFilterFreeList);
if (!filter) {
errlogPrintf("dbChannelCreate: Out of memory\n");
return parse_stop;
}
filter->chan = parser->chan;
filter->plug = plug;
filter->puser = NULL;
result = plug->fif->parse_start(filter);
if (result == parse_continue) {
parser->filter = filter;
} else {
freeListFree(chFilterFreeList, filter);
}
return result;
}
static int chf_end_map(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
if (!filter) {
assert(parser->depth == 0);
return parse_continue; /* Final closing '}' */
}
assert(parser->depth > 0);
result = CALLIF(filter->plug->fif->parse_end_map)(filter );
--parser->depth;
chf_value(parser, &result);
return result;
}
static int chf_start_array(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
assert(filter);
++parser->depth;
return CALLIF(filter->plug->fif->parse_start_array)(filter );
}
static int chf_end_array(void * ctx)
{
parseContext *parser = (parseContext *) ctx;
chFilter *filter = parser->filter;
parse_result result;
assert(filter);
result = CALLIF(filter->plug->fif->parse_end_array)(filter );
--parser->depth;
chf_value(parser, &result);
return result;
}
static const yajl_callbacks chf_callbacks =
{ chf_null, chf_boolean, chf_integer, chf_double, NULL, chf_string,
chf_start_map, chf_map_key, chf_end_map, chf_start_array, chf_end_array };
static void * chf_malloc(void *ctx, size_t sz)
{
return malloc(sz);
}
static void * chf_realloc(void *ctx, void *ptr, size_t sz)
{
return realloc(ptr, sz);
}
static void chf_free(void *ctx, void *ptr)
{
free(ptr);
}
static yajl_alloc_funcs chf_alloc =
{ chf_malloc, chf_realloc, chf_free };
static long chf_parse(dbChannel *chan, const char **pjson)
{
parseContext parser =
{ chan, NULL, 0 };
yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_alloc, &parser);
const char *json = *pjson;
size_t jlen = strlen(json), ylen;
yajl_status ys;
long status;
if (!yh)
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
ylen = yajl_get_bytes_consumed(yh);
if (ys == yajl_status_ok)
ys = yajl_complete_parse(yh);
switch (ys) {
case yajl_status_ok:
*pjson += ylen;
status = 0;
break;
case yajl_status_error: {
unsigned char *err;
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
printf("dbChannelCreate: %s\n", err);
yajl_free_error(yh, err);
} /* fall through */
default:
status = S_db_notFound;
}
if (parser.filter) {
assert(status);
parser.filter->plug->fif->parse_abort(parser.filter);
freeListFree(chFilterFreeList, parser.filter);
}
yajl_free(yh);
return status;
}
static long pvNameLookup(DBENTRY *pdbe, const char **ppname)
{
long status;
dbInitEntry(pdbbase, pdbe);
status = dbFindRecordPart(pdbe, ppname);
if (status)
return status;
if (**ppname == '.')
++*ppname;
status = dbFindFieldPart(pdbe, ppname);
if (status == S_dbLib_fieldNotFound)
status = dbGetAttributePart(pdbe, ppname);
return status;
}
long dbChannelTest(const char *name)
{
DBENTRY dbEntry;
long status;
if (!name || !*name || !pdbbase)
return S_db_notFound;
status = pvNameLookup(&dbEntry, &name);
dbFinishEntry(&dbEntry);
return status;
}
#define TRY(Func, Arg) \
if (Func) { \
result = Func Arg; \
if (result != parse_continue) goto failure; \
}
static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppnext) {
epicsInt32 start = 0;
epicsInt32 end = -1;
epicsInt32 incr = 1;
epicsInt32 l;
char *pnext;
ptrdiff_t exist;
chFilter *filter;
const chFilterPlugin *plug;
parse_result result;
long status = 0;
/* If no number is present, strtol() returns 0 and sets pnext=pname,
else pnext points to the first char after the number */
pname++;
l = strtol(pname, &pnext, 0);
exist = pnext - pname;
if (exist) start = l;
pname = pnext;
if (*pname == ']' && exist) {
end = start;
goto insertplug;
}
if (*pname != ':') {
status = S_dbLib_fieldNotFound;
goto finish;
}
pname++;
l = strtol(pname, &pnext, 0);
exist = pnext - pname;
pname = pnext;
if (*pname == ']') {
if (exist) end = l;
goto insertplug;
}
if (exist) incr = l;
if (*pname != ':') {
status = S_dbLib_fieldNotFound;
goto finish;
}
pname++;
l = strtol(pname, &pnext, 0);
exist = pnext - pname;
if (exist) end = l;
pname = pnext;
if (*pname != ']') {
status = S_dbLib_fieldNotFound;
goto finish;
}
insertplug:
pname++;
*ppnext = pname;
plug = dbFindFilter("arr", 3);
if (!plug) {
status = S_dbLib_fieldNotFound;
goto finish;
}
filter = freeListCalloc(chFilterFreeList);
if (!filter) {
status = S_db_noMemory;
goto finish;
}
filter->chan = chan;
filter->plug = plug;
filter->puser = NULL;
TRY(filter->plug->fif->parse_start, (filter));
TRY(filter->plug->fif->parse_start_map, (filter));
if (start != 0) {
TRY(filter->plug->fif->parse_map_key, (filter, "s", 1));
TRY(filter->plug->fif->parse_integer, (filter, start));
}
if (incr != 1) {
TRY(filter->plug->fif->parse_map_key, (filter, "i", 1));
TRY(filter->plug->fif->parse_integer, (filter, incr));
}
if (end != -1) {
TRY(filter->plug->fif->parse_map_key, (filter, "e", 1));
TRY(filter->plug->fif->parse_integer, (filter, end));
}
TRY(filter->plug->fif->parse_end_map, (filter));
TRY(filter->plug->fif->parse_end, (filter));
ellAdd(&chan->filters, &filter->list_node);
return 0;
failure:
freeListFree(chFilterFreeList, filter);
status = S_dbLib_fieldNotFound;
finish:
return status;
}
/* Stolen from dbAccess.c: */
static short mapDBFToDBR[DBF_NTYPES] =
{
/* DBF_STRING => */DBR_STRING,
/* DBF_CHAR => */DBR_CHAR,
/* DBF_UCHAR => */DBR_UCHAR,
/* DBF_SHORT => */DBR_SHORT,
/* DBF_USHORT => */DBR_USHORT,
/* DBF_LONG => */DBR_LONG,
/* DBF_ULONG => */DBR_ULONG,
/* DBF_INT64 => */DBR_INT64,
/* DBF_UINT64 => */DBR_UINT64,
/* DBF_FLOAT => */DBR_FLOAT,
/* DBF_DOUBLE => */DBR_DOUBLE,
/* DBF_ENUM, => */DBR_ENUM,
/* DBF_MENU, => */DBR_ENUM,
/* DBF_DEVICE => */DBR_ENUM,
/* DBF_INLINK => */DBR_STRING,
/* DBF_OUTLINK => */DBR_STRING,
/* DBF_FWDLINK => */DBR_STRING,
/* DBF_NOACCESS => */DBR_NOACCESS };
dbChannel * dbChannelCreate(const char *name)
{
const char *pname = name;
DBENTRY dbEntry;
dbChannel *chan = NULL;
char *cname;
dbAddr *paddr;
dbFldDes *pflddes;
long status;
short dbfType;
if (!name || !*name || !pdbbase)
return NULL;
status = pvNameLookup(&dbEntry, &pname);
if (status)
goto finish;
chan = freeListCalloc(dbChannelFreeList);
if (!chan)
goto finish;
cname = malloc(strlen(name) + 1);
if (!cname)
goto finish;
strcpy(cname, name);
chan->name = cname;
ellInit(&chan->filters);
ellInit(&chan->pre_chain);
ellInit(&chan->post_chain);
paddr = &chan->addr;
pflddes = dbEntry.pflddes;
dbfType = pflddes->field_type;
paddr->precord = dbEntry.precnode->precord;
paddr->pfield = dbEntry.pfield;
paddr->pfldDes = pflddes;
paddr->no_elements = 1;
paddr->field_type = dbfType;
paddr->field_size = pflddes->size;
paddr->special = pflddes->special;
paddr->dbr_field_type = mapDBFToDBR[dbfType];
if (paddr->special == SPC_DBADDR) {
rset *prset = dbGetRset(paddr);
/* Let record type modify paddr */
if (prset && prset->cvt_dbaddr) {
status = prset->cvt_dbaddr(paddr);
if (status)
goto finish;
dbfType = paddr->field_type;
}
}
/* Handle field modifiers */
if (*pname) {
if (*pname == '$') {
/* Some field types can be accessed as char arrays */
if (dbfType == DBF_STRING) {
paddr->no_elements = paddr->field_size;
paddr->field_type = DBF_CHAR;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
/* Clients see a char array, but keep original dbfType */
paddr->no_elements = PVLINK_STRINGSZ;
paddr->field_size = 1;
paddr->dbr_field_type = DBR_CHAR;
} else {
status = S_dbLib_fieldNotFound;
goto finish;
}
pname++;
}
if (*pname == '[') {
status = parseArrayRange(chan, pname, &pname);
if (status) goto finish;
}
/* JSON may follow */
if (*pname == '{') {
status = chf_parse(chan, &pname);
if (status) goto finish;
}
/* Make sure there's nothing else */
if (*pname) {
status = S_dbLib_fieldNotFound;
goto finish;
}
}
finish:
if (status && chan) {
dbChannelDelete(chan);
chan = NULL;
}
dbFinishEntry(&dbEntry);
return chan;
}
db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn) {
chFilter *filter;
ELLNODE *node;
db_field_log *pLog = pLogIn;
for (node = ellFirst(&chan->pre_chain); node && pLog; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, pre_node);
pLog = filter->pre_func(filter->pre_arg, chan, pLog);
}
return pLog;
}
db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn) {
chFilter *filter;
ELLNODE *node;
db_field_log *pLog = pLogIn;
for (node = ellFirst(&chan->post_chain); node && pLog; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, post_node);
pLog = filter->post_func(filter->post_arg, chan, pLog);
}
return pLog;
}
long dbChannelOpen(dbChannel *chan)
{
chFilter *filter;
chPostEventFunc *func;
void *arg;
long status;
ELLNODE *node;
db_field_log probe;
db_field_log p;
for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, list_node);
/* Call channel_open */
status = 0;
if (filter->plug->fif->channel_open)
status = filter->plug->fif->channel_open(filter);
if (status) return status;
}
/* Set up type probe */
probe.type = dbfl_type_val;
probe.ctx = dbfl_context_read;
probe.field_type = dbChannelExportType(chan);
probe.no_elements = dbChannelElements(chan);
probe.field_size = dbChannelFieldSize(chan);
p = probe;
/*
* Build up the pre- and post-event-queue filter chains
* Separate loops because the probe must reach the filters in the right order.
*/
for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, list_node);
func = NULL;
arg = NULL;
if (filter->plug->fif->channel_register_pre) {
filter->plug->fif->channel_register_pre(filter, &func, &arg, &p);
if (func) {
ellAdd(&chan->pre_chain, &filter->pre_node);
filter->pre_func = func;
filter->pre_arg = arg;
probe = p;
}
}
}
for (node = ellFirst(&chan->filters); node; node = ellNext(node)) {
filter = CONTAINER(node, chFilter, list_node);
func = NULL;
arg = NULL;
if (filter->plug->fif->channel_register_post) {
filter->plug->fif->channel_register_post(filter, &func, &arg, &p);
if (func) {
ellAdd(&chan->post_chain, &filter->post_node);
filter->post_func = func;
filter->post_arg = arg;
probe = p;
}
}
}
/* Save probe results */
chan->final_no_elements = probe.no_elements;
chan->final_field_size = probe.field_size;
chan->final_type = probe.field_type;
return 0;
}
/* Only use dbChannelGet() if the record is already locked. */
long dbChannelGet(dbChannel *chan, short type, void *pbuffer,
long *options, long *nRequest, void *pfl)
{
return dbGet(&chan->addr, type, pbuffer, options, nRequest, pfl);
}
long dbChannelGetField(dbChannel *chan, short dbrType, void *pbuffer,
long *options, long *nRequest, void *pfl)
{
dbCommon *precord = chan->addr.precord;
long status = 0;
dbScanLock(precord);
status = dbChannelGet(chan, dbrType, pbuffer, options, nRequest, pfl);
dbScanUnlock(precord);
return status;
}
/* Only use dbChannelPut() if the record is already locked.
* This routine doesn't work on link fields, ignores DISP, and
* doesn't trigger record processing on PROC or pp(TRUE).
*/
long dbChannelPut(dbChannel *chan, short type, const void *pbuffer,
long nRequest)
{
return dbPut(&chan->addr, type, pbuffer, nRequest);
}
long dbChannelPutField(dbChannel *chan, short type, const void *pbuffer,
long nRequest)
{
return dbPutField(&chan->addr, type, pbuffer, nRequest);
}
void dbChannelShow(dbChannel *chan, int level, const unsigned short indent)
{
long elems = chan->addr.no_elements;
long felems = chan->final_no_elements;
int count = ellCount(&chan->filters);
int pre = ellCount(&chan->pre_chain);
int post = ellCount(&chan->post_chain);
printf("%*sChannel: '%s'\n", indent, "", chan->name);
if (level > 0) {
printf("%*sfield_type=%s (%d bytes), dbr_type=%s, %ld element%s",
indent + 4, "",
dbGetFieldTypeString(chan->addr.field_type),
chan->addr.field_size,
dbGetFieldTypeString(chan->addr.dbr_field_type),
elems, elems == 1 ? "" : "s");
if (count)
printf("\n%*s%d filter%s (%d pre eventq, %d post eventq)\n",
indent + 4, "", count, count == 1 ? "" : "s", pre, post);
else
printf(", no filters\n");
if (level > 1)
dbChannelFilterShow(chan, level - 2, indent + 8);
if (count) {
printf("%*sfinal field_type=%s (%dB), %ld element%s\n", indent + 4, "",
dbGetFieldTypeString(chan->final_type),
chan->final_field_size,
felems, felems == 1 ? "" : "s");
}
}
}
void dbChannelFilterShow(dbChannel *chan, int level, const unsigned short indent)
{
chFilter *filter = (chFilter *) ellFirst(&chan->filters);
while (filter) {
filter->plug->fif->channel_report(filter, level, indent);
filter = (chFilter *) ellNext(&filter->list_node);
}
}
void dbChannelDelete(dbChannel *chan)
{
chFilter *filter;
/* Close filters in reverse order */
while ((filter = (chFilter *) ellPop(&chan->filters))) {
filter->plug->fif->channel_close(filter);
freeListFree(chFilterFreeList, filter);
}
free((char *) chan->name);
freeListFree(dbChannelFreeList, chan);
}
static void freeArray(db_field_log *pfl) {
if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
freeListFree(dbchStringFreeList, pfl->u.r.field);
} else {
free(pfl->u.r.field);
}
}
void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
{
void *p;
struct dbCommon *prec = dbChannelRecord(chan);
if (pfl->type != dbfl_type_rec) return;
pfl->type = dbfl_type_ref;
pfl->stat = prec->stat;
pfl->sevr = prec->sevr;
pfl->time = prec->time;
pfl->field_type = chan->addr.field_type;
pfl->no_elements = chan->addr.no_elements;
pfl->field_size = chan->addr.field_size;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = pvt;
if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
p = freeListCalloc(dbchStringFreeList);
} else {
p = calloc(pfl->no_elements, pfl->field_size);
}
if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
pfl->u.r.field = p;
}
/* FIXME: Do these belong in a different file? */
void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser)
{
GPHENTRY *pgph;
chFilterPlugin *pfilt;
if (!pdbbase) {
printf("dbRegisterFilter: pdbbase not set!\n");
return;
}
pgph = gphFind(pdbbase->pgpHash, name, &pdbbase->filterList);
if (pgph)
return;
pfilt = dbCalloc(1, sizeof(chFilterPlugin));
pfilt->name = epicsStrDup(name);
pfilt->fif = fif;
pfilt->puser = puser;
ellAdd(&pdbbase->filterList, &pfilt->node);
pgph = gphAdd(pdbbase->pgpHash, pfilt->name, &pdbbase->filterList);
if (!pgph) {
free((void *) pfilt->name);
free(pfilt);
printf("dbRegisterFilter: gphAdd failed\n");
return;
}
pgph->userPvt = pfilt;
}
const chFilterPlugin * dbFindFilter(const char *name, size_t len)
{
GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len,
&pdbbase->filterList);
if (!pgph)
return NULL;
return (chFilterPlugin *) pgph->userPvt;
}
+233
View File
@@ -0,0 +1,233 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#ifndef INC_dbChannel_H
#define INC_dbChannel_H
#include "dbDefs.h"
#include "dbAddr.h"
#include "ellLib.h"
#include "epicsTypes.h"
#include "errMdef.h"
#include "shareLib.h"
#include "db_field_log.h"
#include "dbEvent.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* event subscription
*/
typedef struct evSubscrip {
ELLNODE node;
struct dbChannel *chan;
EVENTFUNC *user_sub;
void *user_arg;
struct event_que *ev_que;
db_field_log **pLastLog;
unsigned long npend; /* n times this event is on the queue */
unsigned long nreplace; /* n times replacing event on the queue */
unsigned char select;
char useValque;
char callBackInProgress;
char enabled;
} evSubscrip;
typedef struct chFilter chFilter;
/* A dbChannel points to a record field, and can have multiple filters */
typedef struct dbChannel {
const char *name;
dbAddr addr; /* address structure for record/field */
long final_no_elements; /* final number of elements (arrays) */
short final_field_size; /* final size of element */
short final_type; /* final type of database field */
ELLLIST filters; /* list of filters as created from JSON */
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
ELLLIST post_chain; /* list of filters to be called post-event-queue */
} dbChannel;
/* Prototype for the channel event function that is called in filter stacks
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
* If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying
* data out of the associated record.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
* then return NULL.
*/
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
/* Return values from chFilterIf->parse_* routines: */
typedef enum {
parse_stop, parse_continue
} parse_result;
/* These routines must be implemented by each filter plug-in */
typedef struct chFilterIf {
/* cleanup pointer passed to dbRegisterFilter().
* Called during DB shutdown
*/
void (* priv_free)(void *puser);
/* Parsing event handlers: */
parse_result (* parse_start)(chFilter *filter);
/* If parse_start() returns parse_continue for a filter, one of
* parse_abort() or parse_end() will later be called for that same
* filter.
*/
void (* parse_abort)(chFilter *filter);
/* If parse_abort() is called it should release any memory allocated
* for this filter; no further parse_...() calls will be made;
*/
parse_result (* parse_end)(chFilter *filter);
/* If parse_end() returns parse_stop it should have released any
* memory allocated for this filter; no further parse_...() calls will
* be made in this case.
*/
parse_result (* parse_null)(chFilter *filter);
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
parse_result (* parse_integer)(chFilter *filter, long integerVal);
parse_result (* parse_double)(chFilter *filter, double doubleVal);
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
size_t stringLen); /* NB: stringVal is not zero-terminated: */
parse_result (* parse_start_map)(chFilter *filter);
parse_result (* parse_map_key)(chFilter *filter, const char *key,
size_t stringLen); /* NB: key is not zero-terminated: */
parse_result (* parse_end_map)(chFilter *filter);
parse_result (* parse_start_array)(chFilter *filter);
parse_result (* parse_end_array)(chFilter *filter);
/* Channel operations: */
long (* channel_open)(chFilter *filter);
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
void (* channel_close)(chFilter *filter);
} chFilterIf;
/* A chFilterPlugin holds data for a filter plugin */
typedef struct chFilterPlugin {
ELLNODE node;
const char *name;
const chFilterIf *fif;
void *puser;
} chFilterPlugin;
/* A chFilter holds data for a single filter instance */
struct chFilter {
ELLNODE list_node;
ELLNODE pre_node;
ELLNODE post_node;
dbChannel *chan;
const chFilterPlugin *plug;
chPostEventFunc *pre_func;
void *pre_arg;
chPostEventFunc *post_func;
void *post_arg;
void *puser;
};
struct dbCommon;
struct dbFldDes;
epicsShareFunc void dbChannelInit (void);
epicsShareFunc void dbChannelExit(void);
epicsShareFunc long dbChannelTest(const char *name);
epicsShareFunc dbChannel * dbChannelCreate(const char *name);
epicsShareFunc long dbChannelOpen(dbChannel *chan);
/*Following is also defined in db_convert.h*/
epicsShareExtern unsigned short dbDBRnewToDBRold[];
/* In the following macros pChan is dbChannel* */
/* evaluates to const char* */
#define dbChannelName(pChan) ((pChan)->name)
/* evaluates to struct dbCommon* */
#define dbChannelRecord(pChan) ((pChan)->addr.precord)
/* evaluates to struct dbFldDes* */
#define dbChannelFldDes(pChan) ((pChan)->addr.pfldDes)
/* evaluates to long */
#define dbChannelElements(pChan) ((pChan)->addr.no_elements)
/* evaluates to short */
#define dbChannelFieldType(pChan) ((pChan)->addr.field_type)
/* evaluates to short */
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
/* evaluates to short */
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
/* evaluates to short */
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
/* evaluates to long */
#define dbChannelFinalElements(pChan) ((pChan)->final_no_elements)
/* evaluates to short */
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
/* evaluates to short */
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
/* evaluates to short */
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)
/* evaluates to short */
#define dbChannelSpecial(pChan) ((pChan)->addr.special)
/* Channel filters do not get to interpose here since there are many
* places where the field pointer is compared with the address of a
* specific record field, so they can't modify the pointer value.
*/
/* evaluates to void* */
#define dbChannelField(pChan) ((pChan)->addr.pfield)
epicsShareFunc long dbChannelGet(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
epicsShareFunc long dbChannelGetField(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
epicsShareFunc long dbChannelPut(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
epicsShareFunc long dbChannelPutField(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
epicsShareFunc void dbChannelShow(dbChannel *chan, int level,
const unsigned short indent);
epicsShareFunc void dbChannelFilterShow(dbChannel *chan, int level,
const unsigned short indent);
epicsShareFunc void dbChannelDelete(dbChannel *chan);
epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbChannel_H */
+237
View File
@@ -0,0 +1,237 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <string>
#include <stdexcept>
#include <limits.h>
#include "tsFreeList.h"
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "db_access.h"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "db_access_routines.h"
#include "dbCAC.h"
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
dbChannelIO::dbChannelIO (
epicsMutex & mutexIn, cacChannelNotify & notify,
dbChannel * dbchIn, dbContext & serviceIO ) :
cacChannel ( notify ), mutex ( mutexIn ), serviceIO ( serviceIO ),
dbch ( dbchIn )
{
}
void dbChannelIO::initiateConnect ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->notify().connectNotify ( guard );
}
dbChannelIO::~dbChannelIO ()
{
}
void dbChannelIO::destructor ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyAllIO ( cbGuard, guard, *this );
dbChannelDelete ( this->dbch );
this->~dbChannelIO ();
}
void dbChannelIO::destroy (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.destroyChannel ( cbGuard, guard, *this );
// don't access this pointer after above call because
// object no longer exists
}
cacChannel::ioStatus dbChannelIO::read (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, cacReadNotify & notify, ioid * )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.callReadNotify ( guard, this->dbch,
type, count, notify );
return iosSynch;
}
void dbChannelIO::write (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, const void *pValue )
{
epicsGuardRelease < epicsMutex > unguard ( guard );
if ( count > LONG_MAX ) {
throw outOfBounds();
}
int status = dbChannel_put ( this->dbch, type, pValue,
static_cast <long> (count) );
if ( status ) {
throw std::logic_error (
"db_put_field() completed unsuccessfully" );
}
}
cacChannel::ioStatus dbChannelIO::write (
epicsGuard < epicsMutex > & guard, unsigned type,
unsigned long count, const void * pValue,
cacWriteNotify & notify, ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
if ( count > LONG_MAX ) {
throw outOfBounds();
}
this->serviceIO.initiatePutNotify (
guard, *this, this->dbch,
type, count, pValue, notify, pId );
return iosAsynch;
}
void dbChannelIO::subscribe (
epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
unsigned mask, cacStateNotify & notify, ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.subscribe (
guard, this->dbch, *this,
type, count, mask, notify, pId );
}
void dbChannelIO::ioCancel (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & id )
{
mutualExclusionGuard.assertIdenticalMutex ( this->mutex );
this->serviceIO.ioCancel ( cbGuard, mutualExclusionGuard, *this, id );
}
void dbChannelIO::ioShow (
epicsGuard < epicsMutex > & guard,
const ioid & id, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.ioShow ( guard, id, level );
}
void dbChannelIO::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
printf ("channel at %p attached to local database record %s\n",
static_cast <const void *> ( this ),
dbChannelRecord ( this->dbch ) -> name );
if ( level > 0u ) {
printf ( " type %s, element count %li, field at %p\n",
dbf_type_to_text ( dbChannelExportCAType ( this->dbch ) ),
dbChannelElements ( this->dbch ),
dbChannelField ( this->dbch ) );
if ( level > 1u ) {
dbChannelFilterShow ( this->dbch, level - 2u, 8 );
this->serviceIO.show ( level - 2u );
this->serviceIO.showAllIO ( *this, level - 2u );
}
}
}
unsigned long dbChannelIO::nativeElementCount (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
long elements = dbChannelElements ( this->dbch );
if ( elements >= 0u ) {
return static_cast < unsigned long > ( elements );
}
return 0u;
}
// hopefully to be eventually phased out
const char * dbChannelIO::pName (
epicsGuard < epicsMutex > & guard ) const throw ()
{
guard.assertIdenticalMutex ( this->mutex );
return dbChannelName ( this->dbch );
}
unsigned dbChannelIO::getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw ()
{
const char *name = dbChannelName ( this->dbch );
size_t len = strlen ( name );
strncpy ( pBuf, name, bufLen );
if (len < bufLen)
return (unsigned) len;
pBuf[--bufLen] = '\0';
return bufLen;
}
short dbChannelIO::nativeType (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return dbChannelExportCAType( this->dbch );
}
void * dbChannelIO::operator new ( size_t size,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
void dbChannelIO::operator delete ( void *pCadaver,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
void dbChannelIO::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}
void dbChannelIO::flush (
epicsGuard < epicsMutex > & )
{
}
unsigned dbChannelIO::requestMessageBytesPending (
epicsGuard < epicsMutex > & )
{
return 0u;
}
+124
View File
@@ -0,0 +1,124 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* NOTES:
* 1) This interface is preliminary and will change in the future
*/
#ifndef dbChannelIOh
#define dbChannelIOh
#ifdef epicsExportSharedSymbols
# define dbChannelIOh_restore_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "compilerDependencies.h"
#ifdef dbChannelIOh_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
#endif
class dbChannelIO : public cacChannel, public dbContextPrivateListOfIO {
public:
dbChannelIO (
epicsMutex &, cacChannelNotify &,
dbChannel *, dbContext & );
void destructor (
CallbackGuard &,
epicsGuard < epicsMutex > & );
void destroy (
CallbackGuard &,
epicsGuard < epicsMutex > & mutualExclusionGuard );
void callReadNotify (
epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
cacReadNotify & notify );
void callStateNotify (
unsigned type, unsigned long count,
const struct db_field_log * pfl, cacStateNotify & notify );
void show (
epicsGuard < epicsMutex > &, unsigned level ) const;
unsigned getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw ();
const char * pName (
epicsGuard < epicsMutex > & ) const throw ();
void * operator new ( size_t size,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbChannelIO, 256, epicsMutexNOOP > & ))
protected:
~dbChannelIO ();
private:
epicsMutex & mutex;
dbContext & serviceIO;
dbChannel * dbch;
void initiateConnect (
epicsGuard < epicsMutex > & );
unsigned requestMessageBytesPending (
epicsGuard < epicsMutex > & );
void flush (
epicsGuard < epicsMutex > & );
ioStatus read (
epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
cacReadNotify &, ioid * );
void write (
epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
const void * pvalue );
ioStatus write (
epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
const void * pvalue, cacWriteNotify &, ioid * );
void subscribe (
epicsGuard < epicsMutex > &,
unsigned type, unsigned long count,
unsigned mask, cacStateNotify &notify, ioid * );
void ioCancel (
CallbackGuard &,
epicsGuard < epicsMutex > &,
const ioid & );
void ioShow (
epicsGuard < epicsMutex > &,
const ioid &, unsigned level ) const;
short nativeType (
epicsGuard < epicsMutex > & ) const;
unsigned long nativeElementCount (
epicsGuard < epicsMutex > & ) const;
dbChannelIO ( const dbChannelIO & );
dbChannelIO & operator = ( const dbChannelIO & );
void operator delete ( void * );
};
inline void dbChannelIO::callReadNotify (
epicsGuard < epicsMutex > & guard, unsigned type, unsigned long count,
cacReadNotify & notify )
{
guard.assertIdenticalMutex ( this->mutex );
this->serviceIO.callReadNotify ( guard, this->dbch, type, count, notify );
}
inline void dbChannelIO::callStateNotify ( unsigned type, unsigned long count,
const struct db_field_log *pfl, cacStateNotify &notify )
{
this->serviceIO.callStateNotify ( this->dbch, type, count, pfl, notify );
}
#endif // dbChannelIOh
+118
View File
@@ -0,0 +1,118 @@
#ifndef DBCHANNELNOOP_H
#define DBCHANNELNOOP_H
#include <string.h>
#include <string>
#include "cacIO.h"
#include "caerr.h"
/** @brief A channel which never connects
*
* Used when dbCa is placed in isolated mode for unittests
*/
class dbChannelNOOP : public cacChannel
{
std::string myname;
public:
dbChannelNOOP(const char *name, cacChannelNotify &notify)
:cacChannel(notify)
,myname(name)
{}
virtual void destroy (
CallbackGuard & /*callbackGuard*/,
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
{
delete this; // goodbye cruel world
}
virtual unsigned getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw ()
{
const char* name = myname.c_str();
if(bufLen>myname.size()+1) {
bufLen=myname.size()+1;
}
memcpy(pBuf, name, bufLen);
pBuf[--bufLen] = '\0';
return bufLen;
}
// !! deprecated, avoid use !!
virtual const char * pName (
epicsGuard < epicsMutex > & guard ) const throw ()
{return myname.c_str();}
virtual void show (
epicsGuard < epicsMutex > &,
unsigned level ) const
{}
virtual void initiateConnect (
epicsGuard < epicsMutex > & )
{}
virtual unsigned requestMessageBytesPending (
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
{return 0;}
virtual void flush (
epicsGuard < epicsMutex > & /*mutualExclusionGuard*/ )
{}
virtual ioStatus read (
epicsGuard < epicsMutex > &mut,
unsigned type, arrayElementCount count,
cacReadNotify &notify, ioid * = 0 )
{
notify.exception(mut, ECA_NORDACCESS, "dbChannelNOOP", type, count);
return iosSynch;
}
virtual void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue )
{}
virtual ioStatus write (
epicsGuard < epicsMutex > &mut,
unsigned type, arrayElementCount count,
const void */*pValue*/, cacWriteNotify & notify, ioid * = 0 )
{
notify.exception(mut, ECA_NOWTACCESS, "dbChannelNOOP", type, count);
return iosSynch;
}
virtual void subscribe (
epicsGuard < epicsMutex > &mut, unsigned type,
arrayElementCount count, unsigned /*mask*/, cacStateNotify & notify,
ioid * = 0 )
{
// should never subscribe
notify.exception(mut, ECA_BADMASK, "dbChannelNOOP", type, count);
}
virtual void ioCancel (
CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & )
{}
virtual void ioShow (
epicsGuard < epicsMutex > &,
const ioid &, unsigned level ) const
{}
virtual short nativeType (
epicsGuard < epicsMutex > & ) const
{return 0;} // DBR_STRING
virtual arrayElementCount nativeElementCount (
epicsGuard < epicsMutex > & ) const
{return 1;}
};
#endif // DBCHANNELNOOP_H
+267
View File
@@ -0,0 +1,267 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
%#include "epicsTypes.h"
%#include "link.h"
field(NAME,DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
prompt("Disable")
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
field(MLOK,DBF_NOACCESS) {
prompt("Monitor lock")
special(SPC_NOMOD)
interest(4)
extra("epicsMutexId mlok")
}
%#include "ellLib.h"
field(MLIS,DBF_NOACCESS) {
prompt("Monitor List")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST mlis")
}
field(BKLNK,DBF_NOACCESS) {
prompt("Backwards link tracking")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST bklnk")
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
pp(TRUE)
interest(3)
}
field(STAT,DBF_MENU) {
prompt("Alarm Status")
special(SPC_NOMOD)
menu(menuAlarmStat)
initial("UDF")
}
field(SEVR,DBF_MENU) {
prompt("Alarm Severity")
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmStat)
}
field(NSEV,DBF_MENU) {
prompt("New Alarm Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
initial("YES")
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
field(LCNT,DBF_UCHAR) {
prompt("Lock Count")
special(SPC_NOMOD)
interest(2)
}
field(PACT,DBF_UCHAR) {
prompt("Record active")
special(SPC_NOMOD)
interest(1)
}
field(PUTF,DBF_UCHAR) {
prompt("dbPutField process")
special(SPC_NOMOD)
interest(1)
}
field(RPRO,DBF_UCHAR) {
prompt("Reprocess ")
special(SPC_NOMOD)
interest(1)
}
field(ASP,DBF_NOACCESS) {
prompt("Access Security Pvt")
special(SPC_NOMOD)
interest(4)
extra("struct asgMember *asp")
}
field(PPN,DBF_NOACCESS) {
prompt("pprocessNotify")
special(SPC_NOMOD)
interest(4)
extra("struct processNotify *ppn")
}
field(PPNR,DBF_NOACCESS) {
prompt("pprocessNotifyRecord")
special(SPC_NOMOD)
interest(4)
extra("struct processNotifyRecord *ppnr")
}
field(SPVT,DBF_NOACCESS) {
prompt("Scan Private")
special(SPC_NOMOD)
interest(4)
extra("struct scan_element *spvt")
}
field(RSET,DBF_NOACCESS) {
prompt("Address of RSET")
special(SPC_NOMOD)
interest(4)
extra("struct typed_rset *rset")
}
field(DSET,DBF_NOACCESS) {
prompt("DSET address")
special(SPC_NOMOD)
interest(4)
extra("struct dset *dset")
}
field(DPVT,DBF_NOACCESS) {
prompt("Device Private")
special(SPC_NOMOD)
interest(4)
extra("void *dpvt")
}
field(RDES,DBF_NOACCESS) {
prompt("Address of dbRecordType")
special(SPC_NOMOD)
interest(4)
extra("struct dbRecordType *rdes")
}
field(LSET,DBF_NOACCESS) {
prompt("Lock Set")
special(SPC_NOMOD)
interest(4)
extra("struct lockRecord *lset")
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
}
field(TPRO,DBF_UCHAR) {
prompt("Trace Processing")
}
field(BKPT,DBF_NOACCESS) {
prompt("Break Point")
special(SPC_NOMOD)
interest(1)
extra("char bkpt")
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
}
%#include "epicsTime.h"
field(TIME,DBF_NOACCESS) {
prompt("Time")
special(SPC_NOMOD)
interest(2)
extra("epicsTimeStamp time")
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
interest(1)
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef DBCOMMONPVT_H
#define DBCOMMONPVT_H
#include "dbCommon.h"
/** Base internal additional information for every record
*/
typedef struct dbCommonPvt {
struct dbRecordNode *recnode;
struct dbCommon common;
} dbCommonPvt;
#endif // DBCOMMONPVT_H
@@ -0,0 +1,12 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(dbCommon) {
include "dbCommon.dbd"
}
+234
View File
@@ -0,0 +1,234 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConstLink.c
*
* Original Authors: Bob Dalesio, Marty Kraimer
* Current Author: Andrew Johnson
*/
#include <stdio.h>
#include <string.h>
#include "dbDefs.h"
#include "epicsStdlib.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbCommon.h"
#include "dbConstLink.h"
#include "dbConvertJSON.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "link.h"
/**************************** Convert functions ****************************/
/* The difference between these and dbFastConvert is that constants
* may contain hex numbers, whereas database conversions can't.
*/
/* Copy to STRING */
static long cvt_st_st(const char *from, void *pfield, const dbAddr *paddr)
{
char *to = pfield;
size_t size;
if (paddr && paddr->field_size < MAX_STRING_SIZE) {
size = paddr->field_size - 1;
} else {
size = MAX_STRING_SIZE - 1;
}
strncpy(to, from, size);
to[size] = 0;
return 0;
}
/* Most integer conversions are identical */
#define cvt_st_int(TYPE) static long \
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
epics##TYPE *to = pfield; \
char *end; \
\
if (*from == 0) { \
*to = 0; \
return 0; \
} \
return epicsParse##TYPE(from, to, 0, &end); \
}
/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */
cvt_st_int(Int8)
cvt_st_int(UInt8)
cvt_st_int(Int16)
cvt_st_int(UInt16)
cvt_st_int(Int32)
/* Conversion for ULONG is different... */
static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
{
epicsUInt32 *to = pfield;
char *end;
long status;
if (*from == 0) {
*to = 0;
return 0;
}
status = epicsParseUInt32(from, to, 0, &end);
if (status == S_stdlib_noConversion ||
(!status && (*end == '.' || *end == 'e' || *end == 'E'))) {
/*
* Convert via double so numbers like 1.0e3 convert properly.
* db_access pretends ULONG fields are DOUBLE.
*/
double dval;
status = epicsParseFloat64(from, &dval, &end);
if (!status &&
dval >=0 &&
dval <= ULONG_MAX)
*to = dval;
}
return status;
}
/* Instanciate for INT64 and UINT64 */
cvt_st_int(Int64)
cvt_st_int(UInt64)
/* Float conversions are identical */
#define cvt_st_float(TYPE) static long \
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
epics##TYPE *to = pfield; \
char *end; \
\
if (*from == 0) { \
*to = 0; \
return 0; \
} \
return epicsParse##TYPE(from, to, &end); \
}
/* Instanciate for FLOAT32 and FLOAT64 */
cvt_st_float(Float32)
cvt_st_float(Float64)
static long (*convert[DBF_DOUBLE+1])(const char *, void *, const dbAddr *) = {
cvt_st_st,
cvt_st_Int8, cvt_st_UInt8,
cvt_st_Int16, cvt_st_UInt16,
cvt_st_Int32, cvt_st_UInt32,
cvt_st_Int64, cvt_st_UInt64,
cvt_st_Float32, cvt_st_Float64
};
/***************************** Constant Links *****************************/
/* Forward definition */
static lset dbConst_lset;
void dbConstInitLink(struct link *plink)
{
plink->lset = &dbConst_lset;
}
void dbConstAddLink(struct link *plink)
{
plink->lset = &dbConst_lset;
}
/**************************** Member functions ****************************/
static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
{
const char *pstr = plink->value.constantStr;
size_t len;
if (!pstr)
return S_db_badField;
len = strlen(pstr);
/* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
if (*pstr == '[' && pstr[len-1] == ']') {
/* Convert from JSON array */
long nReq = 1;
return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
}
return convert[dbrType](pstr, pbuffer, NULL);
}
static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const char *pstr = plink->value.constantStr;
if (!pstr)
return S_db_badField;
return dbLSConvertJSON(pstr, pbuffer, size, plen);
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
const char *pstr = plink->value.constantStr;
if (!pstr)
return S_db_badField;
/* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
}
static long dbConstGetNelements(const struct link *plink, long *nelements)
{
*nelements = 0;
return 0;
}
static long dbConstGetValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
if (pnRequest)
*pnRequest = 0;
return 0;
}
static long dbConstPutValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
return 0;
}
static lset dbConst_lset = {
1, 0, /* Constant, not Volatile */
NULL, NULL,
dbConstLoadScalar,
dbConstLoadLS,
dbConstLoadArray,
NULL,
NULL, dbConstGetNelements,
dbConstGetValue,
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL,
dbConstPutValue, NULL,
NULL, NULL
};
+34
View File
@@ -0,0 +1,34 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConstLink.h
*
* Created on: April 3rd, 2016
* Author: Andrew Johnson
*/
#ifndef INC_dbConstLink_H
#define INC_dbConstLink_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct link;
epicsShareFunc void dbConstInitLink(struct link *plink);
epicsShareFunc void dbConstAddLink(struct link *plink);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbConstLink_H */
+435
View File
@@ -0,0 +1,435 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <limits.h>
#include "epicsMutex.h"
#include "tsFreeList.h"
#include "cadef.h" // this can be eliminated when the callbacks use the new interface
#include "db_access.h" // should be eliminated here in the future
#include "caerr.h" // should be eliminated here in the future
#include "epicsEvent.h"
#include "epicsThread.h"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "db_access_routines.h"
#include "dbCAC.h"
#include "dbChannel.h"
#include "dbChannelIO.h"
#include "dbChannelNOOP.h"
#include "dbPutNotifyBlocker.h"
class dbService : public cacService {
public:
~dbService () {}
cacContext & contextCreate (
epicsMutex & mutualExclusion,
epicsMutex & callbackControl,
cacContextNotify & );
};
static dbService dbs;
cacContext & dbService::contextCreate (
epicsMutex & mutualExclusion,
epicsMutex & callbackControl,
cacContextNotify & notify )
{
return * new dbContext ( callbackControl,
mutualExclusion, notify );
}
extern "C" int dbServiceIsolate;
int dbServiceIsolate = 0;
extern "C" void dbServiceIOInit ()
{
static int init=0;
if(!init) {
caInstallDefaultService ( dbs );
init=1;
}
}
dbBaseIO::dbBaseIO () {}
dbContext::dbContext ( epicsMutex & cbMutexIn,
epicsMutex & mutexIn, cacContextNotify & notifyIn ) :
readNotifyCache ( mutexIn ), ctx ( 0 ),
stateNotifyCacheSize ( 0 ), mutex ( mutexIn ), cbMutex ( cbMutexIn ),
notify ( notifyIn ), pNetContext ( 0 ), pStateNotifyCache ( 0 ),
isolated(dbServiceIsolate)
{
}
dbContext::~dbContext ()
{
delete [] this->pStateNotifyCache;
if ( this->ctx ) {
db_close_events ( this->ctx );
}
}
cacChannel & dbContext::createChannel (
epicsGuard < epicsMutex > & guard, const char * pName,
cacChannelNotify & notifyIn, cacChannel::priLev priority )
{
guard.assertIdenticalMutex ( this->mutex );
dbChannel *dbch = dbChannel_create ( pName );
if ( ! dbch ) {
if ( isolated ) {
return *new dbChannelNOOP(pName, notifyIn);
} else if ( ! this->pNetContext.get() ) {
this->pNetContext.reset (
& this->notify.createNetworkContext (
this->mutex, this->cbMutex ) );
}
return this->pNetContext->createChannel (
guard, pName, notifyIn, priority );
}
if ( ! ca_preemtive_callback_is_enabled () ) {
dbChannelDelete ( dbch );
errlogPrintf (
"dbContext: preemptive callback required for direct in\n"
"memory interfacing of CA channels to the DB.\n" );
throw cacChannel::unsupportedByService ();
}
try {
return * new ( this->dbChannelIOFreeList )
dbChannelIO ( this->mutex, notifyIn, dbch, *this );
}
catch (...) {
dbChannelDelete ( dbch );
throw;
}
}
void dbContext::destroyChannel (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard,
dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard );
this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker = 0;
}
chan.destructor ( cbGuard, guard );
this->dbChannelIOFreeList.release ( & chan );
}
void dbContext::callStateNotify ( struct dbChannel * dbch,
unsigned type, unsigned long count,
const struct db_field_log * pfl,
cacStateNotify & notifyIn )
{
long realcount = (count==0)?dbChannelElements(dbch):count;
unsigned long size = dbr_size_n ( type, realcount );
if ( type > INT_MAX ) {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.exception ( guard, ECA_BADTYPE,
"type code out of range (high side)",
type, count );
return;
}
if ( count > INT_MAX ) {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
}
// no need to lock this because state notify is
// called from only one event queue consumer thread
if ( this->stateNotifyCacheSize < size) {
char * pTmp = new char [size];
delete [] this->pStateNotifyCache;
this->pStateNotifyCache = pTmp;
this->stateNotifyCacheSize = size;
}
void *pvfl = (void *) pfl;
int status;
if(count==0) /* fetch actual number of elements (dynamic array) */
status = dbChannel_get_count( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, &realcount, pvfl );
else /* fetch requested number of elements, truncated or zero padded */
status = dbChannel_get( dbch, static_cast <int> ( type ),
this->pStateNotifyCache, realcount, pvfl );
if ( status ) {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.exception ( guard, ECA_GETFAIL,
"dbChannel_get() completed unsuccessfully", type, count );
}
else {
epicsGuard < epicsMutex > guard ( this->mutex );
notifyIn.current ( guard, type, realcount, this->pStateNotifyCache );
}
}
extern "C" void cacAttachClientCtx ( void * pPrivate )
{
int status = ca_attach_context ( (ca_client_context *) pPrivate );
assert ( status == ECA_NORMAL );
}
void dbContext::subscribe (
epicsGuard < epicsMutex > & guard,
struct dbChannel * dbch, dbChannelIO & chan,
unsigned type, unsigned long count, unsigned mask,
cacStateNotify & notifyIn, cacChannel::ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
/*
* the database uses type "int" to store these parameters
*/
if ( type > INT_MAX ) {
throw cacChannel::badType();
}
if ( count > INT_MAX ) {
throw cacChannel::outOfBounds();
}
if ( ! this->ctx ) {
dbEventCtx tmpctx = 0;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
tmpctx = db_init_events ();
if ( ! tmpctx ) {
throw std::bad_alloc ();
}
unsigned selfPriority = epicsThreadGetPrioritySelf ();
unsigned above;
epicsThreadBooleanStatus tbs =
epicsThreadLowestPriorityLevelAbove ( selfPriority, &above );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
above = selfPriority;
}
int status = db_start_events ( tmpctx, "CAC-event",
cacAttachClientCtx, ca_current_context (), above );
if ( status ) {
db_close_events ( tmpctx );
throw std::bad_alloc ();
}
}
if ( this->ctx ) {
// another thread tried to simultaneously setup
// the event system
db_close_events ( tmpctx );
}
else {
this->ctx = tmpctx;
}
}
dbSubscriptionIO & subscr =
* new ( this->dbSubscriptionIOFreeList )
dbSubscriptionIO ( guard, this->mutex, *this, chan,
dbch, notifyIn, type, count, mask, this->ctx );
chan.dbContextPrivateListOfIO::eventq.add ( subscr );
this->ioTable.idAssignAdd ( subscr );
if ( pId ) {
*pId = subscr.getId ();
}
}
void dbContext::initiatePutNotify (
epicsGuard < epicsMutex > & guard,
dbChannelIO & chan, struct dbChannel * dbch,
unsigned type, unsigned long count, const void * pValue,
cacWriteNotify & notifyIn, cacChannel::ioid * pId )
{
guard.assertIdenticalMutex ( this->mutex );
if ( ! chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker =
new ( this->dbPutNotifyBlockerFreeList )
dbPutNotifyBlocker ( this->mutex );
this->ioTable.idAssignAdd ( *chan.dbContextPrivateListOfIO::pBlocker );
}
chan.dbContextPrivateListOfIO::pBlocker->initiatePutNotify (
guard, notifyIn, dbch, type, count, pValue );
if ( pId ) {
*pId = chan.dbContextPrivateListOfIO::pBlocker->getId ();
}
}
void dbContext::destroyAllIO (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard,
dbChannelIO & chan )
{
guard.assertIdenticalMutex ( this->mutex );
dbSubscriptionIO * pIO;
tsDLList < dbSubscriptionIO > tmp;
while ( ( pIO = chan.dbContextPrivateListOfIO::eventq.get() ) ) {
this->ioTable.remove ( *pIO );
tmp.add ( *pIO );
}
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
this->ioTable.remove ( *chan.dbContextPrivateListOfIO::pBlocker );
}
while ( ( pIO = tmp.get() ) ) {
// This prevents a db event callback from coming
// through after the notify IO is deleted
pIO->unsubscribe ( cbGuard, guard );
// If they call ioCancel() here it will be ignored
// because the IO has been unregistered above.
pIO->channelDeleteException ( cbGuard, guard );
pIO->destructor ( cbGuard, guard );
this->dbSubscriptionIOFreeList.release ( pIO );
}
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->destructor ( cbGuard, guard );
this->dbPutNotifyBlockerFreeList.release ( chan.dbContextPrivateListOfIO::pBlocker );
chan.dbContextPrivateListOfIO::pBlocker = 0;
}
}
void dbContext::ioCancel (
CallbackGuard & cbGuard, epicsGuard < epicsMutex > & guard,
dbChannelIO & chan, const cacChannel::ioid &id )
{
guard.assertIdenticalMutex ( this->mutex );
dbBaseIO * pIO = this->ioTable.remove ( id );
if ( pIO ) {
dbSubscriptionIO *pSIO = pIO->isSubscription ();
if ( pSIO ) {
chan.dbContextPrivateListOfIO::eventq.remove ( *pSIO );
pSIO->unsubscribe ( cbGuard, guard );
pSIO->channelDeleteException ( cbGuard, guard );
pSIO->destructor ( cbGuard, guard );
this->dbSubscriptionIOFreeList.release ( pSIO );
}
else if ( pIO == chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->cancel ( cbGuard, guard );
}
else {
errlogPrintf ( "dbContext::ioCancel() unrecognized IO was probably leaked or not canceled\n" );
}
}
}
void dbContext::ioShow (
epicsGuard < epicsMutex > & guard, const cacChannel::ioid &id,
unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
const dbBaseIO * pIO = this->ioTable.lookup ( id );
if ( pIO ) {
pIO->show ( guard, level );
}
}
void dbContext::showAllIO ( const dbChannelIO & chan, unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
tsDLIterConst < dbSubscriptionIO > pItem =
chan.dbContextPrivateListOfIO::eventq.firstIter ();
while ( pItem.valid () ) {
pItem->show ( guard, level );
pItem++;
}
if ( chan.dbContextPrivateListOfIO::pBlocker ) {
chan.dbContextPrivateListOfIO::pBlocker->show ( guard, level );
}
}
void dbContext::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void dbContext::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
printf ( "dbContext at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
printf ( "\tevent call back cache location %p, and its size %lu\n",
static_cast <void *> ( this->pStateNotifyCache ), this->stateNotifyCacheSize );
this->readNotifyCache.show ( guard, level - 1 );
}
if ( level > 1u ) {
this->mutex.show ( level - 2u );
}
if ( this->pNetContext.get() ) {
this->pNetContext.get()->show ( guard, level );
}
}
void dbContext::flush (
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pNetContext.get() ) {
this->pNetContext.get()->flush ( guard );
}
}
unsigned dbContext::circuitCount (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pNetContext.get() ) {
return this->pNetContext.get()->circuitCount ( guard );
}
else {
return 0u;
}
}
void dbContext::selfTest (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
this->ioTable.verify ();
if ( this->pNetContext.get() ) {
this->pNetContext.get()->selfTest ( guard );
}
}
unsigned dbContext::beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pNetContext.get() ) {
return this->pNetContext.get()->beaconAnomaliesSinceProgramStart ( guard );
}
else {
return 0u;
}
}
@@ -0,0 +1,180 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Auther Jeff Hill
*/
#include <stdlib.h>
#include "epicsMutex.h"
#include "dbDefs.h"
#include "cadef.h" // this can be eliminated when the callbacks use the new interface
#include "db_access.h" // should be eliminated here in the future
#define epicsExportSharedSymbols
#include "db_access_routines.h"
#include "dbCAC.h"
#include "epicsAssert.h"
dbContextReadNotifyCache::dbContextReadNotifyCache ( epicsMutex & mutexIn ) :
_mutex ( mutexIn )
{
}
class privateAutoDestroyPtr {
public:
privateAutoDestroyPtr (
dbContextReadNotifyCacheAllocator & allocator, unsigned long size ) :
_allocator ( allocator ), _p ( allocator.alloc ( size ) ) {}
~privateAutoDestroyPtr () { _allocator.free ( _p ); }
char * get () const { return _p; }
private:
dbContextReadNotifyCacheAllocator & _allocator;
char * _p;
privateAutoDestroyPtr ( const privateAutoDestroyPtr & );
privateAutoDestroyPtr & operator = ( const privateAutoDestroyPtr & );
};
// extra effort taken here to not hold the lock when calling the callback
void dbContextReadNotifyCache::callReadNotify (
epicsGuard < epicsMutex > & guard, struct dbChannel * dbch,
unsigned type, unsigned long count, cacReadNotify & notify )
{
guard.assertIdenticalMutex ( _mutex );
if ( type > INT_MAX ) {
notify.exception ( guard, ECA_BADTYPE,
"type code out of range (high side)",
type, count );
return;
}
const long maxcount = dbChannelElements(dbch);
if ( maxcount < 0 ) {
notify.exception ( guard, ECA_BADCOUNT,
"database has negetive element count",
type, count);
return;
} else if ( count > (unsigned long)maxcount ) {
notify.exception ( guard, ECA_BADCOUNT,
"element count out of range (high side)",
type, count);
return;
}
long realcount = (count==0)?maxcount:count;
unsigned long size = dbr_size_n ( type, realcount );
privateAutoDestroyPtr ptr ( _allocator, size );
int status;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
if ( count==0 )
status = dbChannel_get_count ( dbch, (int)type, ptr.get(), &realcount, 0);
else
status = dbChannel_get ( dbch, (int)type, ptr.get (), realcount, 0 );
}
if ( status ) {
notify.exception ( guard, ECA_GETFAIL,
"db_get_field() completed unsuccessfuly",
type, count );
}
else {
notify.completion (
guard, type, realcount, ptr.get () );
}
}
void dbContextReadNotifyCache::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( _mutex );
printf ( "dbContextReadNotifyCache\n" );
if ( level > 0 ) {
this->_allocator.show ( level - 1 );
}
}
dbContextReadNotifyCacheAllocator::dbContextReadNotifyCacheAllocator () :
_readNotifyCacheSize ( 0 ), _pReadNotifyCache ( 0 )
{
}
dbContextReadNotifyCacheAllocator::~dbContextReadNotifyCacheAllocator ()
{
this->reclaimAllCacheEntries ();
}
void dbContextReadNotifyCacheAllocator::reclaimAllCacheEntries ()
{
while ( _pReadNotifyCache ) {
cacheElem_t * pNext = _pReadNotifyCache->pNext;
assert(_pReadNotifyCache->size == _readNotifyCacheSize);
::free(_pReadNotifyCache);
_pReadNotifyCache = pNext;
}
}
char * dbContextReadNotifyCacheAllocator::alloc ( unsigned long size )
{
if ( size > _readNotifyCacheSize ) {
this->reclaimAllCacheEntries ();
_readNotifyCacheSize = size;
}
cacheElem_t * pAlloc = _pReadNotifyCache;
if ( pAlloc ) {
assert(pAlloc->size == _readNotifyCacheSize);
_pReadNotifyCache = pAlloc->pNext;
}
else {
pAlloc = (cacheElem_t*)calloc(1, sizeof(cacheElem_t)+_readNotifyCacheSize);
if(!pAlloc) throw std::bad_alloc();
pAlloc->size = _readNotifyCacheSize;
}
return pAlloc->buf;
}
void dbContextReadNotifyCacheAllocator::free ( char * pFree )
{
cacheElem_t * pAlloc = (cacheElem_t*)(pFree - offsetof(cacheElem_t, buf));
if (pAlloc->size == _readNotifyCacheSize) {
pAlloc->pNext = _pReadNotifyCache;
_pReadNotifyCache = pAlloc;
} else {
::free(pAlloc);
}
}
void dbContextReadNotifyCacheAllocator::show ( unsigned level ) const
{
printf ( "dbContextReadNotifyCacheAlocator\n" );
if ( level > 0 ) {
size_t count =0;
cacheElem_t * pNext = _pReadNotifyCache;
while ( pNext ) {
assert(pNext->size == _readNotifyCacheSize);
pNext = _pReadNotifyCache->pNext;
count++;
}
printf ( "\tcount %lu and size %lu\n",
static_cast < unsigned long > ( count ),
_readNotifyCacheSize );
}
}
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvert.h */
#ifndef INCdbConverth
#define INCdbConverth
#include "dbFldTypes.h"
#include "dbAddr.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef long (*GETCONVERTFUNC)(const DBADDR *paddr, void *pbuffer,
long nRequest, long no_elements, long offset);
typedef long (*PUTCONVERTFUNC)(DBADDR *paddr, const void *pbuffer,
long nRequest, long no_elements, long offset);
epicsShareExtern GETCONVERTFUNC dbGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1];
epicsShareExtern PUTCONVERTFUNC dbPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1];
#ifdef __cplusplus
}
#endif
#endif /*INCdbConverth*/
@@ -0,0 +1,29 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvertFast.h */
#ifndef INCdbConvertFasth
#define INCdbConvertFasth
#include "dbFldTypes.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareExtern long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])();
epicsShareExtern long (*dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1])();
#ifdef __cplusplus
}
#endif
#endif /*INCdbConvertFasth*/
+252
View File
@@ -0,0 +1,252 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvertJSON.c */
#include <string.h>
#include <stdio.h>
#include "dbDefs.h"
#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
typedef long (*FASTCONVERT)();
typedef struct parseContext {
int depth;
short dbrType;
short dbrSize;
char *pdest;
int elems;
} parseContext;
static int dbcj_null(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_boolean(void *ctx, int val) {
return 0; /* Illegal */
}
static int dbcj_integer(void *ctx, long long num) {
parseContext *parser = (parseContext *) ctx;
epicsInt64 val64 = num;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType];
if (parser->elems > 0) {
conv(&val64, parser->pdest, NULL);
parser->pdest += parser->dbrSize;
parser->elems--;
}
return 1;
}
static int dblsj_integer(void *ctx, long long num) {
return 0; /* Illegal */
}
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
if (parser->elems > 0) {
conv(&num, parser->pdest, NULL);
parser->pdest += parser->dbrSize;
parser->elems--;
}
return 1;
}
static int dblsj_double(void *ctx, double num) {
return 0; /* Illegal */
}
static int dbcj_string(void *ctx, const unsigned char *val, size_t len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
/* Not attempting to handle char-array fields here, they need more
* metadata about the field than we have available at the moment.
*/
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
return 0; /* Illegal */
}
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
len = parser->dbrSize - 1;
strncpy(pdest, (const char *) val, len);
pdest[len] = 0;
parser->pdest += parser->dbrSize;
parser->elems--;
}
return 1;
}
static int dblsj_string(void *ctx, const unsigned char *val, size_t len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
return 0; /* Illegal */
}
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
len = parser->dbrSize - 1;
strncpy(pdest, (const char *) val, len);
pdest[len] = 0;
parser->pdest = pdest + len;
parser->elems = 0;
}
return 1;
}
static int dbcj_start_map(void *ctx) {
errlogPrintf("dbConvertJSON: Map type not supported\n");
return 0; /* Illegal */
}
static int dbcj_map_key(void *ctx, const unsigned char *key, size_t len) {
return 0; /* Illegal */
}
static int dbcj_end_map(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
if (++parser->depth > 1)
errlogPrintf("dbConvertJSON: Embedded arrays not supported\n");
return (parser->depth == 1);
}
static int dbcj_end_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
parser->depth--;
return (parser->depth == 0);
}
static yajl_callbacks dbcj_callbacks = {
dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
};
long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *pnRequest)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
long status;
parser->depth = 0;
parser->dbrType = dbrType;
parser->dbrSize = dbValueSize(dbrType);
parser->pdest = pdest;
parser->elems = *pnRequest;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dbcj_callbacks, &dbcj_alloc, parser);
if (!yh)
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_ok)
ys = yajl_complete_parse(yh);
switch (ys) {
case yajl_status_ok:
*pnRequest -= parser->elems;
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbConvertJSON: %s\n", err);
yajl_free_error(yh, err);
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
return status;
}
static yajl_callbacks dblsj_callbacks = {
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
};
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
epicsUInt32 *plen)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
long status;
if (!size) {
*plen = 0;
return 0;
}
parser->depth = 0;
parser->dbrType = DBF_STRING;
parser->dbrSize = size;
parser->pdest = pdest;
parser->elems = 1;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dblsj_callbacks, &dbcj_alloc, parser);
if (!yh)
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
switch (ys) {
case yajl_status_ok:
*plen = (char *) parser->pdest - pdest + 1;
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
yajl_free_error(yh, err);
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
return status;
}
@@ -0,0 +1,28 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvertJSON.h */
#ifndef INC_dbConvertJSON_H
#define INC_dbConvertJSON_H
#include <shareLib.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This name should probably be changed to inclue "array" */
epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *psize);
epicsShareFunc long dbLSConvertJSON(const char *json, char *pdest,
epicsUInt32 size, epicsUInt32 *plen);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbConvertJSON_H */
+358
View File
@@ -0,0 +1,358 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbDbLink.c
*
* Original Authors: Bob Dalesio, Marty Kraimer
* Current Author: Andrew Johnson
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "cantProceed.h"
#include "cvtFast.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsTime.h"
#include "errlog.h"
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbBkpt.h"
#include "dbCommon.h"
#include "dbConvertFast.h"
#include "dbConvert.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "dbLockPvt.h"
#include "dbNotify.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "devSup.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
#include "special.h"
/***************************** Database Links *****************************/
/* Forward definition */
static lset dbDb_lset;
long dbDbInitLink(struct link *plink, short dbfType)
{
DBADDR dbaddr;
long status;
DBADDR *pdbAddr;
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
if (status)
return status;
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
*pdbAddr = dbaddr; /* structure copy */
plink->value.pv_link.pvt = pdbAddr;
ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
/* merging into the same lockset is deferred to the caller.
* cf. initPVLinks()
*/
dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
return 0;
}
void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
DBADDR *ptarget)
{
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
plink->value.pv_link.pvt = ptarget;
ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
/* target record is already locked in dbPutFieldLink() */
dbLockSetMerge(locker, plink->precord, ptarget->precord);
}
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
{
DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
plink->type = PV_LINK;
/* locker is NULL when an isolated IOC is closing its links */
if (locker) {
plink->value.pv_link.pvt = 0;
plink->value.pv_link.getCvt = 0;
plink->value.pv_link.pvlMask = 0;
plink->value.pv_link.lastGetdbrType = 0;
ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
}
free(pdbAddr);
}
static int dbDbIsConnected(const struct link *plink)
{
return TRUE;
}
static int dbDbGetDBFtype(const struct link *plink)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
return paddr->field_type;
}
static long dbDbGetElements(const struct link *plink, long *nelements)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
*nelements = paddr->no_elements;
return 0;
}
static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
DBADDR *paddr = ppv_link->pvt;
dbCommon *precord = plink->precord;
long status;
/* scan passive records if link is process passive */
if (ppv_link->pvlMask & pvlOptPP) {
unsigned char pact = precord->pact;
precord->pact = TRUE;
status = dbScanPassive(precord, paddr->precord);
precord->pact = pact;
if (status)
return status;
}
if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
} else {
unsigned short dbfType = paddr->field_type;
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
return S_db_badDbrtype;
if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
&& paddr->special != SPC_DBADDR
&& paddr->special != SPC_ATTRIBUTE) {
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
} else {
ppv_link->getCvt = NULL;
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
}
ppv_link->lastGetdbrType = dbrType;
}
if (!status && precord != paddr->precord)
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
plink->precord, paddr->precord->stat, paddr->precord->sevr);
return status;
}
static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
struct buffer {
DBRctrlDouble
double value;
} buffer;
long options = DBR_CTRL_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
if (status)
return status;
*low = buffer.lower_ctrl_limit;
*high = buffer.upper_ctrl_limit;
return 0;
}
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
double *high)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
struct buffer {
DBRgrDouble
double value;
} buffer;
long options = DBR_GR_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
NULL);
if (status)
return status;
*low = buffer.lower_disp_limit;
*high = buffer.upper_disp_limit;
return 0;
}
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
struct buffer {
DBRalDouble
double value;
} buffer;
long options = DBR_AL_DOUBLE;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status)
return status;
*lolo = buffer.lower_alarm_limit;
*low = buffer.lower_warning_limit;
*high = buffer.upper_warning_limit;
*hihi = buffer.upper_alarm_limit;
return 0;
}
static long dbDbGetPrecision(const struct link *plink, short *precision)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
struct buffer {
DBRprecision
double value;
} buffer;
long options = DBR_PRECISION;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status)
return status;
*precision = (short) buffer.precision.dp;
return 0;
}
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
struct buffer {
DBRunits
double value;
} buffer;
long options = DBR_UNITS;
long number_elements = 0;
long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements,
0);
if (status)
return status;
strncpy(units, buffer.units, unitsSize);
return 0;
}
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
if (status)
*status = paddr->precord->stat;
if (severity)
*severity = paddr->precord->sevr;
return 0;
}
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
*pstamp = paddr->precord->time;
return 0;
}
static long dbDbPutValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
struct dbCommon *psrce = plink->precord;
DBADDR *paddr = (DBADDR *) ppv_link->pvt;
dbCommon *pdest = paddr->precord;
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
psrce->nsev);
if (status)
return status;
if (paddr->pfield == (void *) &pdest->proc ||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
/* if dbPutField caused asyn record to process */
/* ask for reprocessing*/
if (pdest->putf) {
pdest->rpro = TRUE;
} else { /* process dest record with source's PACT true */
unsigned char pact;
if (psrce && psrce->ppn)
dbNotifyAdd(psrce, pdest);
pact = psrce->pact;
psrce->pact = TRUE;
status = dbProcess(pdest);
psrce->pact = pact;
}
}
return status;
}
static void dbDbScanFwdLink(struct link *plink)
{
dbCommon *precord = plink->precord;
dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
dbScanPassive(precord, paddr->precord);
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
{
return rtn(plink, priv);
}
static lset dbDb_lset = {
0, 0, /* not Constant, not Volatile */
NULL, dbDbRemoveLink,
NULL, NULL, NULL,
dbDbIsConnected,
dbDbGetDBFtype, dbDbGetElements,
dbDbGetValue,
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
dbDbGetPrecision, dbDbGetUnits,
dbDbGetAlarm, dbDbGetTimeStamp,
dbDbPutValue, NULL,
dbDbScanFwdLink, doLocked
};
+35
View File
@@ -0,0 +1,35 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbDbLink.h
*
* Created on: April 3rd, 2016
* Author: Andrew Johnson
*/
#ifndef INC_dbDbLink_H
#define INC_dbDbLink_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct link;
struct dbLocker;
epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
short dbfType, DBADDR *ptarget);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbDbLink_H */
File diff suppressed because it is too large Load Diff
+94
View File
@@ -0,0 +1,94 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Jeffrey O. Hill <johill@lanl.gov>
*
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#ifndef INCLdbEventh
#define INCLdbEventh
#ifdef epicsExportSharedSymbols
# undef epicsExportSharedSymbols
# define INCLdbEventhExporting
#endif
#include "epicsThread.h"
#ifdef INCLdbEventhExporting
# define epicsExportSharedSymbols
#endif
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct dbChannel;
struct db_field_log;
struct evSubscrip;
epicsShareFunc int db_event_list (
const char *name, unsigned level);
epicsShareFunc int dbel (
const char *name, unsigned level);
epicsShareFunc int db_post_events (
void *pRecord, void *pField, unsigned caEventMask );
typedef void * dbEventCtx;
typedef void EXTRALABORFUNC (void *extralabor_arg);
epicsShareFunc dbEventCtx db_init_events (void);
epicsShareFunc int db_start_events (
dbEventCtx ctx, const char *taskname, void (*init_func)(void *),
void *init_func_arg, unsigned osiPriority );
epicsShareFunc void db_close_events (dbEventCtx ctx);
epicsShareFunc void db_event_flow_ctrl_mode_on (dbEventCtx ctx);
epicsShareFunc void db_event_flow_ctrl_mode_off (dbEventCtx ctx);
epicsShareFunc int db_add_extra_labor_event (
dbEventCtx ctx, EXTRALABORFUNC *func, void *arg);
epicsShareFunc void db_flush_extra_labor_event (dbEventCtx);
epicsShareFunc int db_post_extra_labor (dbEventCtx ctx);
epicsShareFunc void db_event_change_priority ( dbEventCtx ctx, unsigned epicsPriority );
#ifdef EPICS_PRIVATE_API
epicsShareFunc void db_cleanup_events(void);
#endif
typedef void EVENTFUNC (void *user_arg, struct dbChannel *chan,
int eventsRemaining, struct db_field_log *pfl);
typedef void * dbEventSubscription;
epicsShareFunc dbEventSubscription db_add_event (
dbEventCtx ctx, struct dbChannel *chan,
EVENTFUNC *user_sub, void *user_arg, unsigned select);
epicsShareFunc void db_cancel_event (dbEventSubscription es);
epicsShareFunc void db_post_single_event (dbEventSubscription es);
epicsShareFunc void db_event_enable (dbEventSubscription es);
epicsShareFunc void db_event_disable (dbEventSubscription es);
epicsShareFunc struct db_field_log* db_create_event_log (struct evSubscrip *pevent);
epicsShareFunc struct db_field_log* db_create_read_log (struct dbChannel *chan);
epicsShareFunc void db_delete_field_log (struct db_field_log *pfl);
#define DB_EVENT_OK 0
#define DB_EVENT_ERROR (-1)
#ifdef __cplusplus
}
#endif
#endif /*INCLdbEventh*/
@@ -0,0 +1,85 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*
* based on dbConvert.c
* written by: Bob Dalesio, Marty Kraimer
*/
#include <string.h>
#include "epicsTypes.h"
#define epicsExportSharedSymbols
#include "dbAddr.h"
#include "dbExtractArray.h"
void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,
long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
char *psrc = (char *) paddr->pfield;
long nUpperPart;
int i;
short srcSize = paddr->field_size;
short dstSize = srcSize;
char isString = (paddr->field_type == DBF_STRING);
if (nRequest > no_elements) nRequest = no_elements;
if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;
if (increment == 1 && dstSize == srcSize) {
nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;
memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart);
if (nRequest > nUpperPart)
memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart));
if (isString)
for (i = 1; i <= nRequest; i++)
pdst[dstSize*i-1] = '\0';
} else {
for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) {
offset %= no_elements;
memcpy(pdst, &psrc[offset*srcSize], dstSize);
if (isString) pdst[dstSize-1] = '\0';
}
}
}
void dbExtractArrayFromBuf(const void *pfrom, void *pto,
short field_size, short field_type,
long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
char *psrc = (char *) pfrom;
int i;
short srcSize = field_size;
short dstSize = srcSize;
char isString = (field_type == DBF_STRING);
if (nRequest > no_elements) nRequest = no_elements;
if (offset > no_elements - 1) offset = no_elements - 1;
if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1;
if (increment == 1) {
memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest);
if (isString)
for (i = 1; i <= nRequest; i++)
pdst[dstSize*i] = '\0';
} else {
for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) {
memcpy(pdst, &psrc[offset*srcSize], dstSize);
if (isString) pdst[dstSize] = '\0';
}
}
}
@@ -0,0 +1,34 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_dbExtractArray_H
#define INC_dbExtractArray_H
#include "dbFldTypes.h"
#include "dbAddr.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto,
long nRequest, long no_elements, long offset, long increment);
epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto,
short field_size, short field_type,
long nRequest, long no_elements, long offset, long increment);
#ifdef __cplusplus
}
#endif
#endif // INC_dbExtractArray_H
File diff suppressed because it is too large Load Diff
+453
View File
@@ -0,0 +1,453 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "iocsh.h"
#define epicsExportSharedSymbols
#include "callback.h"
#include "dbAccess.h"
#include "dbBkpt.h"
#include "dbCaTest.h"
#include "dbEvent.h"
#include "dbIocRegister.h"
#include "dbJLink.h"
#include "dbLock.h"
#include "dbNotify.h"
#include "dbScan.h"
#include "dbServer.h"
#include "dbState.h"
#include "db_test.h"
#include "dbTest.h"
epicsShareExtern int callbackParallelThreadsDefault;
/* dbLoadDatabase */
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadDatabaseArg1 = { "path",iocshArgString};
static const iocshArg dbLoadDatabaseArg2 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadDatabaseArgs[3] =
{
&dbLoadDatabaseArg0,&dbLoadDatabaseArg1,&dbLoadDatabaseArg2
};
static const iocshFuncDef dbLoadDatabaseFuncDef =
{"dbLoadDatabase",3,dbLoadDatabaseArgs};
static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
{
dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval);
}
/* dbLoadRecords */
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadRecordsArg1 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoadRecordsArg1};
static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs};
static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
{
dbLoadRecords(args[0].sval,args[1].sval);
}
/* dbb */
static const iocshArg dbbArg0 = { "record name",iocshArgString};
static const iocshArg * const dbbArgs[1] = {&dbbArg0};
static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs};
static void dbbCallFunc(const iocshArgBuf *args) { dbb(args[0].sval);}
/* dbd */
static const iocshArg dbdArg0 = { "record name",iocshArgString};
static const iocshArg * const dbdArgs[1] = {&dbdArg0};
static const iocshFuncDef dbdFuncDef = {"dbd",1,dbdArgs};
static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);}
/* dbc */
static const iocshArg dbcArg0 = { "record name",iocshArgString};
static const iocshArg * const dbcArgs[1] = {&dbcArg0};
static const iocshFuncDef dbcFuncDef = {"dbc",1,dbcArgs};
static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);}
/* dbs */
static const iocshArg dbsArg0 = { "record name",iocshArgString};
static const iocshArg * const dbsArgs[1] = {&dbsArg0};
static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs};
static void dbsCallFunc(const iocshArgBuf *args) { dbs(args[0].sval);}
/* dbstat */
static const iocshFuncDef dbstatFuncDef = {"dbstat",0};
static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();}
/* dbp */
static const iocshArg dbpArg0 = { "record name",iocshArgString};
static const iocshArg dbpArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbpArgs[2] = {&dbpArg0,&dbpArg1};
static const iocshFuncDef dbpFuncDef = {"dbp",2,dbpArgs};
static void dbpCallFunc(const iocshArgBuf *args)
{ dbp(args[0].sval,args[1].ival);}
/* dbap */
static const iocshArg dbapArg0 = { "record name",iocshArgString};
static const iocshArg * const dbapArgs[1] = {&dbapArg0};
static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs};
static void dbapCallFunc(const iocshArgBuf *args) { dbap(args[0].sval);}
/* dbsr */
static const iocshArg dbsrArg0 = { "interest level",iocshArgInt};
static const iocshArg * const dbsrArgs[1] = {&dbsrArg0};
static const iocshFuncDef dbsrFuncDef = {"dbsr",1,dbsrArgs};
static void dbsrCallFunc(const iocshArgBuf *args) { dbsr(args[0].ival);}
/* dbcar */
static const iocshArg dbcarArg0 = { "record name",iocshArgString};
static const iocshArg dbcarArg1 = { "level",iocshArgInt};
static const iocshArg * const dbcarArgs[2] = {&dbcarArg0,&dbcarArg1};
static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs};
static void dbcarCallFunc(const iocshArgBuf *args)
{
dbcar(args[0].sval,args[1].ival);
}
/* dbjlr */
static const iocshArg dbjlrArg0 = { "record name",iocshArgString};
static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs};
static void dbjlrCallFunc(const iocshArgBuf *args)
{
dbjlr(args[0].sval,args[1].ival);
}
/* dbel */
static const iocshArg dbelArg0 = { "record name",iocshArgString};
static const iocshArg dbelArg1 = { "level",iocshArgInt};
static const iocshArg * const dbelArgs[2] = {&dbelArg0,&dbelArg1};
static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs};
static void dbelCallFunc(const iocshArgBuf *args)
{
dbel(args[0].sval, args[1].ival);
}
/* dba */
static const iocshArg dbaArg0 = { "record name",iocshArgString};
static const iocshArg * const dbaArgs[1] = {&dbaArg0};
static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs};
static void dbaCallFunc(const iocshArgBuf *args) { dba(args[0].sval);}
/* dbl */
static const iocshArg dblArg0 = { "record type",iocshArgString};
static const iocshArg dblArg1 = { "fields",iocshArgString};
static const iocshArg * const dblArgs[] = {&dblArg0,&dblArg1};
static const iocshFuncDef dblFuncDef = {"dbl",2,dblArgs};
static void dblCallFunc(const iocshArgBuf *args)
{
dbl(args[0].sval,args[1].sval);
}
/* dbnr */
static const iocshArg dbnrArg0 = { "verbose",iocshArgInt};
static const iocshArg * const dbnrArgs[1] = {&dbnrArg0};
static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs};
static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);}
/* dbla */
static const iocshArg dblaArg0 = { "pattern",iocshArgString};
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs};
static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);}
/* dbgrep */
static const iocshArg dbgrepArg0 = { "pattern",iocshArgString};
static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0};
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs};
static void dbgrepCallFunc(const iocshArgBuf *args) { dbgrep(args[0].sval);}
/* dbgf */
static const iocshArg dbgfArg0 = { "record name",iocshArgString};
static const iocshArg * const dbgfArgs[1] = {&dbgfArg0};
static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs};
static void dbgfCallFunc(const iocshArgBuf *args) { dbgf(args[0].sval);}
/* dbpf */
static const iocshArg dbpfArg0 = { "record name",iocshArgString};
static const iocshArg dbpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbpfArgs[2] = {&dbpfArg0,&dbpfArg1};
static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs};
static void dbpfCallFunc(const iocshArgBuf *args)
{ dbpf(args[0].sval,args[1].sval);}
/* dbpr */
static const iocshArg dbprArg0 = { "record name",iocshArgString};
static const iocshArg dbprArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbprArgs[2] = {&dbprArg0,&dbprArg1};
static const iocshFuncDef dbprFuncDef = {"dbpr",2,dbprArgs};
static void dbprCallFunc(const iocshArgBuf *args)
{ dbpr(args[0].sval,args[1].ival);}
/* dbtr */
static const iocshArg dbtrArg0 = { "record name",iocshArgString};
static const iocshArg * const dbtrArgs[1] = {&dbtrArg0};
static const iocshFuncDef dbtrFuncDef = {"dbtr",1,dbtrArgs};
static void dbtrCallFunc(const iocshArgBuf *args) { dbtr(args[0].sval);}
/* dbtgf */
static const iocshArg dbtgfArg0 = { "record name",iocshArgString};
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs};
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
/* dbtpf */
static const iocshArg dbtpfArg0 = { "record name",iocshArgString};
static const iocshArg dbtpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpfArgs[2] = {&dbtpfArg0,&dbtpfArg1};
static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs};
static void dbtpfCallFunc(const iocshArgBuf *args)
{ dbtpf(args[0].sval,args[1].sval);}
/* dbior */
static const iocshArg dbiorArg0 = { "driver name",iocshArgString};
static const iocshArg dbiorArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbiorArgs[] = {&dbiorArg0,&dbiorArg1};
static const iocshFuncDef dbiorFuncDef = {"dbior",2,dbiorArgs};
static void dbiorCallFunc(const iocshArgBuf *args)
{ dbior(args[0].sval,args[1].ival);}
/* dbhcr */
static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0};
static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();}
/* gft */
static const iocshArg gftArg0 = { "record name",iocshArgString};
static const iocshArg * const gftArgs[1] = {&gftArg0};
static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs};
static void gftCallFunc(const iocshArgBuf *args) { gft(args[0].sval);}
/* pft */
static const iocshArg pftArg0 = { "record name",iocshArgString};
static const iocshArg pftArg1 = { "value",iocshArgString};
static const iocshArg * const pftArgs[2] = {&pftArg0,&pftArg1};
static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs};
static void pftCallFunc(const iocshArgBuf *args)
{ pft(args[0].sval,args[1].sval);}
/* dbtpn */
static const iocshArg dbtpnArg0 = { "record name",iocshArgString};
static const iocshArg dbtpnArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs};
static void dbtpnCallFunc(const iocshArgBuf *args)
{ dbtpn(args[0].sval,args[1].sval);}
/* dbNotifyDump */
static const iocshFuncDef dbNotifyDumpFuncDef = {"dbNotifyDump",0,0};
static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { dbNotifyDump();}
/* dbPutAttribute */
static const iocshArg dbPutAttrArg0 = { "record type",iocshArgString};
static const iocshArg dbPutAttrArg1 = { "attribute name",iocshArgString};
static const iocshArg dbPutAttrArg2 = { "value",iocshArgString};
static const iocshArg * const dbPutAttrArgs[] =
{&dbPutAttrArg0, &dbPutAttrArg1, &dbPutAttrArg2};
static const iocshFuncDef dbPutAttrFuncDef =
{"dbPutAttribute",3,dbPutAttrArgs};
static void dbPutAttrCallFunc(const iocshArgBuf *args)
{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);}
/* tpn */
static const iocshArg tpnArg0 = { "record name",iocshArgString};
static const iocshArg tpnArg1 = { "value",iocshArgString};
static const iocshArg * const tpnArgs[2] = {&tpnArg0,&tpnArg1};
static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs};
static void tpnCallFunc(const iocshArgBuf *args)
{ tpn(args[0].sval,args[1].sval);}
/* dblsr */
static const iocshArg dblsrArg0 = { "record name",iocshArgString};
static const iocshArg dblsrArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dblsrArgs[2] = {&dblsrArg0,&dblsrArg1};
static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs};
static void dblsrCallFunc(const iocshArgBuf *args)
{ dblsr(args[0].sval,args[1].ival);}
/* dbLockShowLocked */
static const iocshArg dbLockShowLockedArg0 = { "interest level",iocshArgInt};
static const iocshArg * const dbLockShowLockedArgs[1] = {&dbLockShowLockedArg0};
static const iocshFuncDef dbLockShowLockedFuncDef =
{"dbLockShowLocked",1,dbLockShowLockedArgs};
static void dbLockShowLockedCallFunc(const iocshArgBuf *args)
{ dbLockShowLocked(args[0].ival);}
/* scanOnceSetQueueSize */
static const iocshArg scanOnceSetQueueSizeArg0 = { "size",iocshArgInt};
static const iocshArg * const scanOnceSetQueueSizeArgs[1] =
{&scanOnceSetQueueSizeArg0};
static const iocshFuncDef scanOnceSetQueueSizeFuncDef =
{"scanOnceSetQueueSize",1,scanOnceSetQueueSizeArgs};
static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args)
{
scanOnceSetQueueSize(args[0].ival);
}
/* scanppl */
static const iocshArg scanpplArg0 = { "rate",iocshArgDouble};
static const iocshArg * const scanpplArgs[1] = {&scanpplArg0};
static const iocshFuncDef scanpplFuncDef = {"scanppl",1,scanpplArgs};
static void scanpplCallFunc(const iocshArgBuf *args)
{ scanppl(args[0].dval);}
/* scanpel */
static const iocshArg scanpelArg0 = { "event name",iocshArgString};
static const iocshArg * const scanpelArgs[1] = {&scanpelArg0};
static const iocshFuncDef scanpelFuncDef = {"scanpel",1,scanpelArgs};
static void scanpelCallFunc(const iocshArgBuf *args)
{ scanpel(args[0].sval);}
/* postEvent */
static const iocshArg postEventArg0 = { "event name",iocshArgString};
static const iocshArg * const postEventArgs[1] = {&postEventArg0};
static const iocshFuncDef postEventFuncDef = {"postEvent",1,postEventArgs};
static void postEventCallFunc(const iocshArgBuf *args)
{
EVENTPVT pel = eventNameToHandle(args[0].sval);
postEvent(pel);
}
/* scanpiol */
static const iocshFuncDef scanpiolFuncDef = {"scanpiol",0};
static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();}
/* callbackSetQueueSize */
static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt};
static const iocshArg * const callbackSetQueueSizeArgs[1] =
{&callbackSetQueueSizeArg0};
static const iocshFuncDef callbackSetQueueSizeFuncDef =
{"callbackSetQueueSize",1,callbackSetQueueSizeArgs};
static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args)
{
callbackSetQueueSize(args[0].ival);
}
/* callbackParallelThreads */
static const iocshArg callbackParallelThreadsArg0 = { "no of threads", iocshArgInt};
static const iocshArg callbackParallelThreadsArg1 = { "priority", iocshArgString};
static const iocshArg * const callbackParallelThreadsArgs[2] =
{&callbackParallelThreadsArg0,&callbackParallelThreadsArg1};
static const iocshFuncDef callbackParallelThreadsFuncDef =
{"callbackParallelThreads",2,callbackParallelThreadsArgs};
static void callbackParallelThreadsCallFunc(const iocshArgBuf *args)
{
callbackParallelThreads(args[0].ival, args[1].sval);
}
/* dbStateCreate */
static const iocshArg dbStateArgName = { "name", iocshArgString };
static const iocshArg * const dbStateCreateArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateCreateFuncDef = { "dbStateCreate", 1, dbStateCreateArgs };
static void dbStateCreateCallFunc (const iocshArgBuf *args)
{
dbStateCreate(args[0].sval);
}
/* dbStateSet */
static const iocshArg * const dbStateSetArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateSetFuncDef = { "dbStateSet", 1, dbStateSetArgs };
static void dbStateSetCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
if (sid)
dbStateSet(sid);
}
/* dbStateClear */
static const iocshArg * const dbStateClearArgs[] = { &dbStateArgName };
static const iocshFuncDef dbStateClearFuncDef = { "dbStateClear", 1, dbStateClearArgs };
static void dbStateClearCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
if (sid)
dbStateClear(sid);
}
/* dbStateShow */
static const iocshArg dbStateShowArg1 = { "level", iocshArgInt };
static const iocshArg * const dbStateShowArgs[] = { &dbStateArgName, &dbStateShowArg1 };
static const iocshFuncDef dbStateShowFuncDef = { "dbStateShow", 2, dbStateShowArgs };
static void dbStateShowCallFunc (const iocshArgBuf *args)
{
dbStateId sid = dbStateFind(args[0].sval);
if (sid)
dbStateShow(sid, args[1].ival);
}
/* dbStateShowAll */
static const iocshArg dbStateShowAllArg0 = { "level", iocshArgInt };
static const iocshArg * const dbStateShowAllArgs[] = { &dbStateShowAllArg0 };
static const iocshFuncDef dbStateShowAllFuncDef = { "dbStateShowAll", 1, dbStateShowAllArgs };
static void dbStateShowAllCallFunc (const iocshArgBuf *args)
{
dbStateShowAll(args[0].ival);
}
void dbIocRegister(void)
{
iocshRegister(&dbbFuncDef,dbbCallFunc);
iocshRegister(&dbdFuncDef,dbdCallFunc);
iocshRegister(&dbcFuncDef,dbcCallFunc);
iocshRegister(&dbsFuncDef,dbsCallFunc);
iocshRegister(&dbstatFuncDef,dbstatCallFunc);
iocshRegister(&dbpFuncDef,dbpCallFunc);
iocshRegister(&dbapFuncDef,dbapCallFunc);
iocshRegister(&dbsrFuncDef,dbsrCallFunc);
iocshRegister(&dbcarFuncDef,dbcarCallFunc);
iocshRegister(&dbelFuncDef,dbelCallFunc);
iocshRegister(&dbjlrFuncDef,dbjlrCallFunc);
iocshRegister(&dbLoadDatabaseFuncDef,dbLoadDatabaseCallFunc);
iocshRegister(&dbLoadRecordsFuncDef,dbLoadRecordsCallFunc);
iocshRegister(&dbaFuncDef,dbaCallFunc);
iocshRegister(&dblFuncDef,dblCallFunc);
iocshRegister(&dbnrFuncDef,dbnrCallFunc);
iocshRegister(&dblaFuncDef,dblaCallFunc);
iocshRegister(&dbgrepFuncDef,dbgrepCallFunc);
iocshRegister(&dbgfFuncDef,dbgfCallFunc);
iocshRegister(&dbpfFuncDef,dbpfCallFunc);
iocshRegister(&dbprFuncDef,dbprCallFunc);
iocshRegister(&dbtrFuncDef,dbtrCallFunc);
iocshRegister(&dbtgfFuncDef,dbtgfCallFunc);
iocshRegister(&dbtpfFuncDef,dbtpfCallFunc);
iocshRegister(&dbiorFuncDef,dbiorCallFunc);
iocshRegister(&dbhcrFuncDef,dbhcrCallFunc);
iocshRegister(&gftFuncDef,gftCallFunc);
iocshRegister(&pftFuncDef,pftCallFunc);
iocshRegister(&dbtpnFuncDef,dbtpnCallFunc);
iocshRegister(&dbNotifyDumpFuncDef,dbNotifyDumpCallFunc);
iocshRegister(&dbPutAttrFuncDef,dbPutAttrCallFunc);
iocshRegister(&tpnFuncDef,tpnCallFunc);
iocshRegister(&dblsrFuncDef,dblsrCallFunc);
iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc);
iocshRegister(&scanOnceSetQueueSizeFuncDef,scanOnceSetQueueSizeCallFunc);
iocshRegister(&scanpplFuncDef,scanpplCallFunc);
iocshRegister(&scanpelFuncDef,scanpelCallFunc);
iocshRegister(&postEventFuncDef,postEventCallFunc);
iocshRegister(&scanpiolFuncDef,scanpiolCallFunc);
iocshRegister(&callbackSetQueueSizeFuncDef,callbackSetQueueSizeCallFunc);
iocshRegister(&callbackParallelThreadsFuncDef,callbackParallelThreadsCallFunc);
/* Needed before callback system is initialized */
callbackParallelThreadsDefault = epicsThreadGetCPUs();
iocshRegister(&dbStateCreateFuncDef, dbStateCreateCallFunc);
iocshRegister(&dbStateSetFuncDef, dbStateSetCallFunc);
iocshRegister(&dbStateClearFuncDef, dbStateClearCallFunc);
iocshRegister(&dbStateShowFuncDef, dbStateShowCallFunc);
iocshRegister(&dbStateShowAllFuncDef, dbStateShowAllCallFunc);
}
@@ -0,0 +1,25 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_dbIocRegister_H
#define INC_dbIocRegister_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc void dbIocRegister(void);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbIocRegister_H */
+538
View File
@@ -0,0 +1,538 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbJLink.c */
#include <stdio.h>
#include <string.h>
#include "epicsAssert.h"
#include "dbmf.h"
#include "errlog.h"
#include "yajl_alloc.h"
#include "yajl_parse.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbCommon.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "dbLink.h"
#include "dbJLink.h"
#include "dbLock.h"
#include "dbStaticLib.h"
#include "link.h"
#define IFDEBUG(n) if(parser->parse_debug)
typedef struct parseContext {
jlink *pjlink;
jlink *product;
short dbfType;
short jsonDepth;
unsigned key_is_link:1;
unsigned parse_debug:1;
unsigned lset_debug:1;
} parseContext;
#define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine)
static int dbjl_return(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
printf("dbjl_return(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
if (result == jlif_stop && pjlink) {
jlink *parent;
while ((parent = pjlink->parent)) {
pjlink->pif->free_jlink(pjlink);
pjlink = parent;
}
pjlink->pif->free_jlink(pjlink);
}
return result;
}
static int dbjl_value(parseContext *parser, jlif_result result) {
jlink *pjlink = parser->pjlink;
jlink *parent;
IFDEBUG(10) {
printf("dbjl_value(%s@%p, %d)\t", pjlink ? pjlink->pif->name : "", pjlink, result);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
if (result == jlif_stop || pjlink->parseDepth > 0)
return dbjl_return(parser, result);
parent = pjlink->parent;
if (!parent) {
parser->product = pjlink;
} else if (parent->pif->end_child) {
parent->pif->end_child(parent, pjlink);
}
pjlink->debug = 0;
parser->pjlink = parent;
IFDEBUG(8)
printf("dbjl_value: product = %p\n", pjlink);
return jlif_continue;
}
static int dbjl_null(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
printf("dbjl_null(%s@%p)\n", pjlink ? pjlink->pif->name : "", pjlink);
assert(pjlink);
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_null)(pjlink));
}
static int dbjl_boolean(void *ctx, int val) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
assert(pjlink);
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_boolean)(pjlink, val));
}
static int dbjl_integer(void *ctx, long long num) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
printf("dbjl_integer(%s@%p, %lld)\n",
pjlink->pif->name, pjlink, num);
assert(pjlink);
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_integer)(pjlink, num));
}
static int dbjl_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
printf("dbjl_double(%s@%p, %g)\n",
pjlink->pif->name, pjlink, num);
assert(pjlink);
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_double)(pjlink, num));
}
static int dbjl_string(void *ctx, const unsigned char *val, size_t len) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10)
printf("dbjl_string(%s@%p, \"%.*s\")\n",
pjlink->pif->name, pjlink, (int) len, val);
assert(pjlink);
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_string)(pjlink, (const char *) val, len));
}
static int dbjl_start_map(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
int result;
if (!pjlink) {
IFDEBUG(10) {
printf("dbjl_start_map(NULL)\t");
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
}
assert(parser->jsonDepth == 0);
parser->jsonDepth++;
parser->key_is_link = 1;
return jlif_continue; /* Opening '{' */
}
IFDEBUG(10) {
printf("dbjl_start_map(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
pjlink->parseDepth++;
parser->jsonDepth++;
result = CALL_OR_STOP(pjlink->pif->parse_start_map)(pjlink);
if (result == jlif_key_child_link) {
parser->key_is_link = 1;
result = jlif_continue;
}
IFDEBUG(10)
printf("dbjl_start_map -> %d\n", result);
return dbjl_return(parser, result);
}
static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
char *link_name;
linkSup *linkSup;
jlif *pjlif;
if (!parser->key_is_link) {
if (!pjlink) {
errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n",
(int) len, key);
return dbjl_return(parser, jlif_stop);
}
IFDEBUG(10) {
printf("dbjl_map_key(%s@%p, \"%.*s\")\t",
pjlink->pif->name, pjlink, (int) len, key);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink->parseDepth > 0);
return dbjl_return(parser,
CALL_OR_STOP(pjlink->pif->parse_map_key)(pjlink,
(const char *) key, len));
}
IFDEBUG(10) {
printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key);
printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
}
link_name = dbmfStrndup((const char *) key, len);
linkSup = dbFindLinkSup(pdbbase, link_name);
if (!linkSup) {
errlogPrintf("dbJLinkInit: Link type '%s' not found\n",
link_name);
dbmfFree(link_name);
return dbjl_return(parser, jlif_stop);
}
pjlif = linkSup->pjlif;
if (!pjlif) {
errlogPrintf("dbJLinkInit: Support for Link type '%s' not loaded\n",
link_name);
dbmfFree(link_name);
return dbjl_return(parser, jlif_stop);
}
dbmfFree(link_name);
pjlink = pjlif->alloc_jlink(parser->dbfType);
if (!pjlink) {
errlogPrintf("dbJLinkInit: Out of memory\n");
return dbjl_return(parser, jlif_stop);
}
pjlink->pif = pjlif;
pjlink->parent = NULL;
pjlink->parseDepth = 0;
pjlink->debug = !!parser->lset_debug;
if (parser->pjlink) {
/* We're starting a child link, save its parent */
pjlink->parent = parser->pjlink;
}
parser->pjlink = pjlink;
parser->key_is_link = 0;
IFDEBUG(8)
printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink);
return jlif_continue;
}
static int dbjl_end_map(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
jlif_result result;
IFDEBUG(10) {
printf("dbjl_end_map(%s@%p)\t",
pjlink ? pjlink->pif->name : "NULL", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0,
parser->key_is_link);
}
parser->jsonDepth--;
if (pjlink) {
pjlink->parseDepth--;
result = dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_end_map)(pjlink));
}
else {
result = jlif_continue;
}
return result;
}
static int dbjl_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
printf("dbjl_start_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink);
pjlink->parseDepth++;
parser->jsonDepth++;
return dbjl_return(parser,
CALL_OR_STOP(pjlink->pif->parse_start_array)(pjlink));
}
static int dbjl_end_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
jlink *pjlink = parser->pjlink;
IFDEBUG(10) {
printf("dbjl_end_array(%s@%p)\t", pjlink ? pjlink->pif->name : "", pjlink);
printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n",
parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link);
}
assert(pjlink);
pjlink->parseDepth--;
parser->jsonDepth--;
return dbjl_value(parser,
CALL_OR_STOP(pjlink->pif->parse_end_array)(pjlink));
}
static yajl_callbacks dbjl_callbacks = {
dbjl_null, dbjl_boolean, dbjl_integer, dbjl_double, NULL, dbjl_string,
dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array
};
long dbJLinkParse(const char *json, size_t jlen, short dbfType,
jlink **ppjlink, unsigned opts)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbjl_allocs;
yajl_handle yh;
yajl_status ys;
long status;
parser->pjlink = NULL;
parser->product = NULL;
parser->dbfType = dbfType;
parser->jsonDepth = 0;
parser->key_is_link = 0;
parser->parse_debug = !!(opts&LINK_DEBUG_JPARSE);
parser->lset_debug = !!(opts&LINK_DEBUG_LSET);
IFDEBUG(10)
printf("dbJLinkInit(\"%.*s\", %d, %p)\n",
(int) jlen, json, dbfType, ppjlink);
IFDEBUG(10)
printf("dbJLinkInit: jsonDepth=%d, key_is_link=%d\n",
parser->jsonDepth, parser->key_is_link);
yajl_set_default_alloc_funcs(&dbjl_allocs);
yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser);
if (!yh)
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_ok)
ys = yajl_complete_parse(yh);
switch (ys) {
unsigned char *err;
case yajl_status_ok:
assert(parser->jsonDepth == 0);
*ppjlink = parser->product;
status = 0;
break;
case yajl_status_error:
err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen);
errlogPrintf("dbJLinkInit: %s\n", err);
yajl_free_error(yh, err);
dbJLinkFree(parser->pjlink);
dbJLinkFree(parser->product);
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
return status;
}
long dbJLinkInit(struct link *plink)
{
jlink *pjlink;
assert(plink);
pjlink = plink->value.json.jlink;
if (pjlink)
plink->lset = pjlink->pif->get_lset(pjlink);
dbLinkOpen(plink);
return 0;
}
void dbJLinkFree(jlink *pjlink)
{
if (pjlink)
pjlink->pif->free_jlink(pjlink);
}
void dbJLinkReport(jlink *pjlink, int level, int indent) {
if (pjlink && pjlink->pif->report)
pjlink->pif->report(pjlink, level, indent);
}
long dbJLinkMapChildren(struct link *plink, jlink_map_fn rtn, void *ctx)
{
jlink *pjlink;
long status;
if (!plink || plink->type != JSON_LINK)
return 0;
pjlink = plink->value.json.jlink;
if (!pjlink)
return 0;
status = rtn(pjlink, ctx);
if (!status && pjlink->pif->map_children)
status = pjlink->pif->map_children(pjlink, rtn, ctx);
return status;
}
long dbjlr(const char *recname, int level)
{
DBENTRY dbentry;
DBENTRY * const pdbentry = &dbentry;
long status;
if (!recname || recname[0] == '\0' || !strcmp(recname, "*")) {
recname = NULL;
printf("JSON links in all records\n\n");
}
else
printf("JSON links in record '%s'\n\n", recname);
dbInitEntry(pdbbase, pdbentry);
for (status = dbFirstRecordType(pdbentry);
status == 0;
status = dbNextRecordType(pdbentry)) {
for (status = dbFirstRecord(pdbentry);
status == 0;
status = dbNextRecord(pdbentry)) {
dbRecordType *pdbRecordType = pdbentry->precordType;
dbCommon *precord = pdbentry->precnode->precord;
char *prec = (char *) precord;
int i;
if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
continue;
if (dbIsAlias(pdbentry))
continue;
printf(" %s record '%s':\n", pdbRecordType->name, precord->name);
dbScanLock(precord);
for (i = 0; i < pdbRecordType->no_links; i++) {
int idx = pdbRecordType->link_ind[i];
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
if (plink->type != JSON_LINK)
continue;
if (!dbLinkIsDefined(plink))
continue;
printf(" Link field '%s':\n", pdbFldDes->name);
dbJLinkReport(plink->value.json.jlink, level, 6);
}
dbScanUnlock(precord);
if (recname)
goto done;
}
}
done:
return 0;
}
long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx)
{
DBENTRY dbentry;
DBENTRY * const pdbentry = &dbentry;
long status;
if (recname && (recname[0] = '\0' || !strcmp(recname, "*")))
recname = NULL;
dbInitEntry(pdbbase, pdbentry);
for (status = dbFirstRecordType(pdbentry);
status == 0;
status = dbNextRecordType(pdbentry)) {
for (status = dbFirstRecord(pdbentry);
status == 0;
status = dbNextRecord(pdbentry)) {
dbRecordType *pdbRecordType = pdbentry->precordType;
dbCommon *precord = pdbentry->precnode->precord;
char *prec = (char *) precord;
int i;
if (recname && strcmp(recname, dbGetRecordName(pdbentry)))
continue;
if (dbIsAlias(pdbentry))
continue;
dbScanLock(precord);
for (i = 0; i < pdbRecordType->no_links; i++) {
int idx = pdbRecordType->link_ind[i];
dbFldDes *pdbFldDes = pdbRecordType->papFldDes[idx];
DBLINK *plink = (DBLINK *) (prec + pdbFldDes->offset);
status = dbJLinkMapChildren(plink, rtn, ctx);
if (status)
goto unlock;
}
unlock:
dbScanUnlock(precord);
if (status || recname)
goto done;
}
}
done:
return status;
}
+133
View File
@@ -0,0 +1,133 @@
/*************************************************************************\
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbJLink.h */
#ifndef INC_dbJLink_H
#define INC_dbJLink_H
#include <stdlib.h>
#include <shareLib.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
jlif_stop = 0,
jlif_continue = 1
} jlif_result;
typedef enum {
jlif_key_stop = jlif_stop,
jlif_key_continue = jlif_continue,
jlif_key_child_link
} jlif_key_result;
struct link;
struct lset;
struct jlif;
typedef struct jlink {
struct jlif *pif; /* Link methods */
struct jlink *parent; /* NULL for top-level links */
int parseDepth; /* Used by parser, unused afterwards */
unsigned debug:1; /* set by caller of jlif operations to request debug output to console */
/* Link types extend or embed this structure for private storage */
} jlink;
typedef long (*jlink_map_fn)(jlink *, void *ctx);
typedef struct jlif {
/* Optional parser methods below given as NULL are equivalent to
* providing a routine that always returns jlif_stop, meaning that
* this JSON construct is not allowed at this point in the parse.
*/
const char *name;
/* Name for the link type, used in link value */
jlink* (*alloc_jlink)(short dbfType);
/* Required, allocate new link structure */
void (*free_jlink)(jlink *);
/* Required, release all resources allocated for link */
jlif_result (*parse_null)(jlink *);
/* Optional, parser saw a null value */
jlif_result (*parse_boolean)(jlink *, int val);
/* Optional, parser saw a boolean value */
jlif_result (*parse_integer)(jlink *, long long num);
/* Optional, parser saw an integer value */
jlif_result (*parse_double)(jlink *, double num);
/* Optional, parser saw a double value */
jlif_result (*parse_string)(jlink *, const char *val, size_t len);
/* Optional, parser saw a string value */
jlif_key_result (*parse_start_map)(jlink *);
/* Optional, parser saw an open-brace '{'. Return jlif_key_child_link
* to expect a child link next (extra key/value pairs may follow).
*/
jlif_result (*parse_map_key)(jlink *, const char *key, size_t len);
/* Optional, parser saw a map key */
jlif_result (*parse_end_map)(jlink *);
/* Optional, parser saw a close-brace '}' */
jlif_result (*parse_start_array)(jlink *);
/* Optional, parser saw an open-bracket */
jlif_result (*parse_end_array)(jlink *);
/* Optional, parser saw a close-bracket */
void (*end_child)(jlink *parent, jlink *child);
/* Optional, called with pointer to the new child link after
* parse_start_map() returned jlif_key_child_link */
struct lset* (*get_lset)(const jlink *);
/* Required, return lset for this link instance */
void (*report)(const jlink *, int level, int indent);
/* Optional, print status information about this link instance, then
* if (level > 0) print a link identifier (at indent+2) and call
* dbJLinkReport(child, level-1, indent+4)
* for each child.
*/
long (*map_children)(jlink *, jlink_map_fn rtn, void *ctx);
/* Optional, call dbJLinkMapChildren() on all embedded links.
* Stop immediately and return status if non-zero.
*/
/* Link types must NOT extend this table with their own routines,
* this space is reserved for extensions to the jlink interface.
*/
} jlif;
epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType,
jlink **ppjlink, unsigned opts);
epicsShareFunc long dbJLinkInit(struct link *plink);
epicsShareFunc void dbJLinkFree(jlink *);
epicsShareFunc void dbJLinkReport(jlink *, int level, int indent);
epicsShareFunc long dbJLinkMapChildren(struct link *,
jlink_map_fn rtn, void *ctx);
epicsShareFunc long dbjlr(const char *recname, int level);
epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbJLink_H */
+505
View File
@@ -0,0 +1,505 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbLink.c */
/*
* Original Authors: Bob Dalesio, Marty Kraimer
* Current Author: Andrew Johnson
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "cvtFast.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsTime.h"
#include "errlog.h"
#include "caeventmask.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbCa.h"
#include "dbCommon.h"
#include "dbConstLink.h"
#include "dbDbLink.h"
#include "db_field_log.h"
#include "dbFldTypes.h"
#include "dbJLink.h"
#include "dbLink.h"
#include "dbLock.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "devSup.h"
#include "link.h"
#include "recGbl.h"
#include "recSup.h"
#include "special.h"
/* How to identify links in error messages */
static const char * link_field_name(const struct link *plink)
{
const struct dbCommon *precord = plink->precord;
const dbRecordType *pdbRecordType = precord->rdes;
dbFldDes * const *papFldDes = pdbRecordType->papFldDes;
const short *link_ind = pdbRecordType->link_ind;
int i;
for (i = 0; i < pdbRecordType->no_links; i++) {
const dbFldDes *pdbFldDes = papFldDes[link_ind[i]];
if (plink == (DBLINK *)((char *)precord + pdbFldDes->offset))
return pdbFldDes->name;
}
return "????";
}
/* Special TSEL handler for PV links */
/* FIXME: Generalize for new link types... */
static void TSEL_modified(struct link *plink)
{
struct pv_link *ppv_link;
char *pfieldname;
if (plink->type != PV_LINK) {
errlogPrintf("dbLink::TSEL_modified called for non PV_LINK\n");
return;
}
/* If pvname contains .TIME truncate it to point to VAL instead */
ppv_link = &plink->value.pv_link;
pfieldname = strstr(ppv_link->pvname, ".TIME");
if (pfieldname) {
*pfieldname = 0;
plink->flags |= DBLINK_FLAG_TSELisTIME;
}
}
/***************************** Generic Link API *****************************/
void dbInitLink(struct link *plink, short dbfType)
{
struct dbCommon *precord = plink->precord;
/* Only initialize link once */
if (plink->flags & DBLINK_FLAG_INITIALIZED)
return;
else
plink->flags |= DBLINK_FLAG_INITIALIZED;
if (plink->type == CONSTANT) {
dbConstInitLink(plink);
return;
}
if (plink->type == JSON_LINK) {
dbJLinkInit(plink);
return;
}
if (plink->type != PV_LINK)
return;
if (plink == &precord->tsel)
TSEL_modified(plink);
if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
/* Make it a DB link if possible */
if (!dbDbInitLink(plink, dbfType))
return;
}
/* Make it a CA link */
if (dbfType == DBF_INLINK)
plink->value.pv_link.pvlMask |= pvlOptInpNative;
dbCaAddLink(NULL, plink, dbfType);
if (dbfType == DBF_FWDLINK) {
char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
if (pperiod && strstr(pperiod, "PROC")) {
plink->value.pv_link.pvlMask |= pvlOptFWD;
}
else {
errlogPrintf("Forward-link uses Channel Access "
"without pointing to PROC field\n"
" %s.%s => %s\n",
precord->name, link_field_name(plink),
plink->value.pv_link.pvname);
}
}
}
void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
DBADDR *ptarget)
{
struct dbCommon *precord = plink->precord;
/* Clear old TSELisTIME flag */
plink->flags &= ~DBLINK_FLAG_TSELisTIME;
if (plink->type == CONSTANT) {
dbConstAddLink(plink);
return;
}
if (plink->type == JSON_LINK) {
/*
* FIXME: Can't create DB links as dbJLink types yet,
* dbLock.c doesn't have any way to find/track them.
*/
dbJLinkInit(plink);
return;
}
if (plink->type != PV_LINK)
return;
if (plink == &precord->tsel)
TSEL_modified(plink);
if (ptarget) {
/* It's a DB link */
dbDbAddLink(locker, plink, dbfType, ptarget);
return;
}
/* Make it a CA link */
if (dbfType == DBF_INLINK)
plink->value.pv_link.pvlMask |= pvlOptInpNative;
dbCaAddLink(locker, plink, dbfType);
if (dbfType == DBF_FWDLINK) {
char *pperiod = strrchr(plink->value.pv_link.pvname, '.');
if (pperiod && strstr(pperiod, "PROC"))
plink->value.pv_link.pvlMask |= pvlOptFWD;
}
}
void dbLinkOpen(struct link *plink)
{
lset *plset = plink->lset;
if (plset && plset->openLink)
plset->openLink(plink);
}
void dbRemoveLink(struct dbLocker *locker, struct link *plink)
{
lset *plset = plink->lset;
if (plset) {
if (plset->removeLink)
plset->removeLink(locker, plink);
plink->lset = NULL;
}
if (plink->type == JSON_LINK)
plink->value.json.jlink = NULL;
}
int dbLinkIsDefined(const struct link *plink)
{
return (plink->lset != 0);
}
int dbLinkIsConstant(const struct link *plink)
{
lset *plset = plink->lset;
return !plset || plset->isConstant;
}
int dbLinkIsVolatile(const struct link *plink)
{
lset *plset = plink->lset;
return plset && plset->isVolatile;
}
long dbLoadLink(struct link *plink, short dbrType, void *pbuffer)
{
lset *plset = plink->lset;
if (plset && plset->loadScalar)
return plset->loadScalar(plink, dbrType, pbuffer);
return S_db_noLSET;
}
long dbLoadLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
lset *plset = plink->lset;
if (plset && plset->loadLS)
return plset->loadLS(plink, pbuffer, size, plen);
return S_db_noLSET;
}
long dbLoadLinkArray(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
lset *plset = plink->lset;
if (plset && plset->loadArray)
return plset->loadArray(plink, dbrType, pbuffer, pnRequest);
return S_db_noLSET;
}
int dbIsLinkConnected(const struct link *plink)
{
lset *plset = plink->lset;
if (!plset || !plset->isConnected)
return FALSE;
return plset->isConnected(plink);
}
int dbGetLinkDBFtype(const struct link *plink)
{
lset *plset = plink->lset;
if (!plset || !plset->getDBFtype)
return -1;
return plset->getDBFtype(plink);
}
long dbGetNelements(const struct link *plink, long *nelements)
{
lset *plset = plink->lset;
if (!plset || !plset->getElements)
return S_db_noLSET;
return plset->getElements(plink, nelements);
}
long dbTryGetLink(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
lset *plset = plink->lset;
if (!plset || !plset->getValue)
return S_db_noLSET;
return plset->getValue(plink, dbrType, pbuffer, pnRequest);
}
long dbGetLink(struct link *plink, short dbrType, void *pbuffer,
long *poptions, long *pnRequest)
{
struct dbCommon *precord = plink->precord;
long status;
if (poptions && *poptions) {
printf("dbGetLink: Use of poptions no longer supported\n");
*poptions = 0;
}
status = dbTryGetLink(plink, dbrType, pbuffer, pnRequest);
if (status == S_db_noLSET)
return -1;
if (status)
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
return status;
}
long dbGetControlLimits(const struct link *plink, double *low, double *high)
{
lset *plset = plink->lset;
if (!plset || !plset->getControlLimits)
return S_db_noLSET;
return plset->getControlLimits(plink, low, high);
}
long dbGetGraphicLimits(const struct link *plink, double *low, double *high)
{
lset *plset = plink->lset;
if (!plset || !plset->getGraphicLimits)
return S_db_noLSET;
return plset->getGraphicLimits(plink, low, high);
}
long dbGetAlarmLimits(const struct link *plink, double *lolo, double *low,
double *high, double *hihi)
{
lset *plset = plink->lset;
if (!plset || !plset->getAlarmLimits)
return S_db_noLSET;
return plset->getAlarmLimits(plink, lolo, low, high, hihi);
}
long dbGetPrecision(const struct link *plink, short *precision)
{
lset *plset = plink->lset;
if (!plset || !plset->getPrecision)
return S_db_noLSET;
return plset->getPrecision(plink, precision);
}
long dbGetUnits(const struct link *plink, char *units, int unitsSize)
{
lset *plset = plink->lset;
if (!plset || !plset->getUnits)
return S_db_noLSET;
return plset->getUnits(plink, units, unitsSize);
}
long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
{
lset *plset = plink->lset;
if (!plset || !plset->getAlarm)
return S_db_noLSET;
return plset->getAlarm(plink, status, severity);
}
long dbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
lset *plset = plink->lset;
if (!plset || !plset->getTimeStamp)
return S_db_noLSET;
return plset->getTimeStamp(plink, pstamp);
}
long dbPutLink(struct link *plink, short dbrType, const void *pbuffer,
long nRequest)
{
lset *plset = plink->lset;
long status;
if (!plset || !plset->putValue)
return S_db_noLSET;
status = plset->putValue(plink, dbrType, pbuffer, nRequest);
if (status) {
struct dbCommon *precord = plink->precord;
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
}
return status;
}
void dbLinkAsyncComplete(struct link *plink)
{
dbCommon *pdbCommon = plink->precord;
dbScanLock(pdbCommon);
pdbCommon->rset->process(pdbCommon);
dbScanUnlock(pdbCommon);
}
long dbPutLinkAsync(struct link *plink, short dbrType, const void *pbuffer,
long nRequest)
{
lset *plset = plink->lset;
long status;
if (!plset || !plset->putAsync)
return S_db_noLSET;
status = plset->putAsync(plink, dbrType, pbuffer, nRequest);
if (status) {
struct dbCommon *precord = plink->precord;
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
}
return status;
}
void dbScanFwdLink(struct link *plink)
{
lset *plset = plink->lset;
if (plset && plset->scanForward)
plset->scanForward(plink);
}
long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
void *priv)
{
lset *plset = plink->lset;
if (!rtn || !plset || !plset->doLocked)
return S_db_noLSET;
return plset->doLocked(plink, rtn, priv);
}
/* Helper functions for long string support */
long dbGetLinkLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
int dtyp = dbGetLinkDBFtype(plink);
long len = size;
long status;
if (dtyp < 0) /* Not connected */
return 0;
if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR) {
status = dbGetLink(plink, dtyp, pbuffer, 0, &len);
}
else if (size >= MAX_STRING_SIZE)
status = dbGetLink(plink, DBR_STRING, pbuffer, 0, 0);
else {
/* pbuffer is too small to fetch using DBR_STRING */
char tmp[MAX_STRING_SIZE];
status = dbGetLink(plink, DBR_STRING, tmp, 0, 0);
if (!status)
strncpy(pbuffer, tmp, len - 1);
}
if (!status) {
pbuffer[--len] = 0;
*plen = (epicsUInt32) strlen(pbuffer) + 1;
}
return status;
}
long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len)
{
int dtyp = dbGetLinkDBFtype(plink);
if (dtyp < 0)
return 0; /* Not connected */
if (dtyp == DBR_CHAR || dtyp == DBF_UCHAR)
return dbPutLink(plink, dtyp, pbuffer, len);
return dbPutLink(plink, DBR_STRING, pbuffer, 1);
}
+141
View File
@@ -0,0 +1,141 @@
/*************************************************************************\
* Copyright (c) 2010 The UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbLink.h
*
* Created on: Mar 21, 2010
* Author: Andrew Johnson
*/
#ifndef INC_dbLink_H
#define INC_dbLink_H
#include "link.h"
#include "shareLib.h"
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAddr.h"
#ifdef __cplusplus
extern "C" {
#endif
struct dbLocker;
typedef long (*dbLinkUserCallback)(struct link *plink, void *priv);
typedef struct lset {
/* Characteristics of the link type */
const unsigned isConstant:1;
const unsigned isVolatile:1;
/* Activation */
void (*openLink)(struct link *plink);
/* Destructor */
void (*removeLink)(struct dbLocker *locker, struct link *plink);
/* Const init, data type hinting */
long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer);
long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen);
long (*loadArray)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
/* Metadata */
int (*isConnected)(const struct link *plink);
int (*getDBFtype)(const struct link *plink);
long (*getElements)(const struct link *plink, long *nelements);
/* Get data */
long (*getValue)(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest);
long (*getControlLimits)(const struct link *plink, double *lo, double *hi);
long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi);
long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo,
double *hi, double *hihi);
long (*getPrecision)(const struct link *plink, short *precision);
long (*getUnits)(const struct link *plink, char *units, int unitsSize);
long (*getAlarm)(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity);
long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp);
/* Put data */
long (*putValue)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
long (*putAsync)(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
/* Process */
void (*scanForward)(struct link *plink);
/* Atomicity */
long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv);
} lset;
#define dbGetSevr(link, sevr) \
dbGetAlarm(link, NULL, sevr)
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
short dbfType, DBADDR *ptarget);
epicsShareFunc void dbLinkOpen(struct link *plink);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
epicsShareFunc int dbLinkIsDefined(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbLinkIsConstant(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbLinkIsVolatile(const struct link *plink); /* 0 or 1 */
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
void *pbuffer);
epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
long *pnRequest);
epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements);
epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
epicsShareFunc int dbGetLinkDBFtype(const struct link *plink);
epicsShareFunc long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
long *nRequest);
epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer,
long *options, long *nRequest);
epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low,
double *high);
epicsShareFunc long dbGetGraphicLimits(const struct link *plink, double *low,
double *high);
epicsShareFunc long dbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi);
epicsShareFunc long dbGetPrecision(const struct link *plink, short *precision);
epicsShareFunc long dbGetUnits(const struct link *plink, char *units,
int unitsSize);
epicsShareFunc long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity);
epicsShareFunc long dbGetTimeStamp(const struct link *plink,
epicsTimeStamp *pstamp);
epicsShareFunc long dbPutLink(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
epicsShareFunc void dbLinkAsyncComplete(struct link *plink);
epicsShareFunc long dbPutLinkAsync(struct link *plink, short dbrType,
const void *pbuffer, long nRequest);
epicsShareFunc void dbScanFwdLink(struct link *plink);
epicsShareFunc long dbLinkDoLocked(struct link *plink, dbLinkUserCallback rtn,
void *priv);
epicsShareFunc long dbLoadLinkLS(struct link *plink, char *pbuffer,
epicsUInt32 size, epicsUInt32 *plen);
epicsShareFunc long dbGetLinkLS(struct link *plink, char *pbuffer,
epicsUInt32 buffer_size, epicsUInt32 *plen);
epicsShareFunc long dbPutLinkLS(struct link *plink, char *pbuffer,
epicsUInt32 len);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbLink_H */
+990
View File
@@ -0,0 +1,990 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cantProceed.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsAssert.h"
#include "epicsAtomic.h"
#include "epicsMutex.h"
#include "epicsPrint.h"
#include "epicsSpin.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "errMdef.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbBase.h"
#include "dbLink.h"
#include "dbCommon.h"
#include "dbFldTypes.h"
#include "dbLockPvt.h"
#include "dbStaticLib.h"
#include "link.h"
typedef struct dbScanLockNode dbScanLockNode;
static epicsThreadOnceId dbLockOnceInit = EPICS_THREAD_ONCE_INIT;
static ELLLIST lockSetsActive; /* in use */
#ifndef LOCKSET_NOFREE
static ELLLIST lockSetsFree; /* free list */
#endif
/* Guard the global list */
static epicsMutexId lockSetsGuard;
#ifndef LOCKSET_NOCNT
/* Counter which we increment whenever
* any lockRecord::plockSet is changed.
* An optimization to avoid checking lockSet
* associations when no links have changed.
*/
static size_t recomputeCnt;
#endif
/*private routines */
static void dbLockOnce(void* ignore)
{
lockSetsGuard = epicsMutexMustCreate();
}
/* global ID number assigned to each lockSet on creation.
* When the free-list is in use will never exceed
* the number of records +1.
* Without the free-list it can roll over, potentially
* leading to duplicate IDs.
*/
static size_t next_id = 1;
static lockSet* makeSet(void)
{
lockSet *ls;
int iref;
epicsMutexMustLock(lockSetsGuard);
#ifndef LOCKSET_NOFREE
ls = (lockSet*)ellGet(&lockSetsFree);
if(!ls) {
epicsMutexUnlock(lockSetsGuard);
#endif
ls=dbCalloc(1,sizeof(*ls));
ellInit(&ls->lockRecordList);
ls->lock = epicsMutexMustCreate();
ls->id = epicsAtomicIncrSizeT(&next_id);
#ifndef LOCKSET_NOFREE
epicsMutexMustLock(lockSetsGuard);
}
#endif
/* the initial reference for the first lockRecord */
iref = epicsAtomicIncrIntT(&ls->refcount);
ellAdd(&lockSetsActive, &ls->node);
epicsMutexUnlock(lockSetsGuard);
assert(ls->id>0);
assert(iref>0);
assert(ellCount(&ls->lockRecordList)==0);
return ls;
}
unsigned long dbLockGetRefs(struct dbCommon* prec)
{
return (unsigned long)epicsAtomicGetIntT(&prec->lset->plockSet->refcount);
}
unsigned long dbLockCountSets(void)
{
unsigned long count;
epicsMutexMustLock(lockSetsGuard);
count = (unsigned long)ellCount(&lockSetsActive);
epicsMutexUnlock(lockSetsGuard);
return count;
}
/* caller must lock accessLock.*/
void dbLockIncRef(lockSet* ls)
{
int cnt = epicsAtomicIncrIntT(&ls->refcount);
if(cnt<=1) {
errlogPrintf("dbLockIncRef(%p) on dead lockSet. refs: %d\n", ls, cnt);
cantProceed(NULL);
}
}
/* caller must lock accessLock.
* lockSet must *not* be locked
*/
void dbLockDecRef(lockSet *ls)
{
int cnt = epicsAtomicDecrIntT(&ls->refcount);
assert(cnt>=0);
if(cnt)
return;
/* lockSet is unused and will be free'd */
/* not necessary as no one else (should) hold a reference,
* but lock anyway to quiet valgrind
*/
epicsMutexMustLock(ls->lock);
if(ellCount(&ls->lockRecordList)!=0) {
errlogPrintf("dbLockDecRef(%p) would free lockSet with %d records\n",
ls, ellCount(&ls->lockRecordList));
cantProceed(NULL);
}
epicsMutexUnlock(ls->lock);
epicsMutexMustLock(lockSetsGuard);
ellDelete(&lockSetsActive, &ls->node);
#ifndef LOCKSET_NOFREE
ellAdd(&lockSetsFree, &ls->node);
#else
epicsMutexDestroy(ls->lock);
memset(ls, 0, sizeof(*ls)); /* paranoia */
free(ls);
#endif
epicsMutexUnlock(lockSetsGuard);
}
lockSet* dbLockGetRef(lockRecord *lr)
{
lockSet *ls;
epicsSpinLock(lr->spin);
ls = lr->plockSet;
dbLockIncRef(ls);
epicsSpinUnlock(lr->spin);
return ls;
}
unsigned long dbLockGetLockId(dbCommon *precord)
{
unsigned long id=0;
epicsSpinLock(precord->lset->spin);
id = precord->lset->plockSet->id;
epicsSpinUnlock(precord->lset->spin);
return id;
}
void dbScanLock(dbCommon *precord)
{
int cnt;
lockRecord * const lr = precord->lset;
lockSet *ls;
assert(lr);
ls = dbLockGetRef(lr);
assert(epicsAtomicGetIntT(&ls->refcount)>0);
retry:
epicsMutexMustLock(ls->lock);
epicsSpinLock(lr->spin);
if(ls!=lr->plockSet) {
/* oops, collided with recompute.
* take a reference to the new lockSet.
*/
lockSet *ls2 = lr->plockSet;
int newcnt = epicsAtomicIncrIntT(&ls2->refcount);
assert(newcnt>=2); /* at least lockRecord and us */
epicsSpinUnlock(lr->spin);
epicsMutexUnlock(ls->lock);
dbLockDecRef(ls);
ls = ls2;
goto retry;
}
epicsSpinUnlock(lr->spin);
/* Release reference taken within this
* function. The count will *never* fall to zero
* as the lockRecords can't be changed while
* we hold the lock.
*/
cnt = epicsAtomicDecrIntT(&ls->refcount);
assert(cnt>0);
#ifdef LOCKSET_DEBUG
if(ls->owner) {
assert(ls->owner==epicsThreadGetIdSelf());
assert(ls->ownercount>=1);
ls->ownercount++;
} else {
assert(ls->ownercount==0);
ls->owner = epicsThreadGetIdSelf();
ls->ownercount = 1;
}
#endif
}
void dbScanUnlock(dbCommon *precord)
{
lockSet *ls = precord->lset->plockSet;
dbLockIncRef(ls);
#ifdef LOCKSET_DEBUG
assert(ls->owner==epicsThreadGetIdSelf());
assert(ls->ownercount>=1);
ls->ownercount--;
if(ls->ownercount==0)
ls->owner = NULL;
#endif
epicsMutexUnlock(ls->lock);
dbLockDecRef(ls);
}
static
int lrrcompare(const void *rawA, const void *rawB)
{
const lockRecordRef *refA=rawA, *refB=rawB;
const lockSet *A=refA->plockSet, *B=refB->plockSet;
if(!A && !B)
return 0; /* NULL == NULL */
else if(!A)
return 1; /* NULL > !NULL */
else if(!B)
return -1; /* !NULL < NULL */
else if(A < B)
return -1;
else if(A > B)
return 1;
else
return 0;
}
/* Call w/ update=1 before locking to update cached lockSet entries.
* Call w/ update=0 after locking to verify that lockRecord weren't updated
*/
static
int dbLockUpdateRefs(dbLocker *locker, int update)
{
int changed = 0;
size_t i, nlock = locker->maxrefs;
#ifndef LOCKSET_NOCNT
const size_t recomp = epicsAtomicGetSizeT(&recomputeCnt);
if(locker->recomp!=recomp) {
#endif
/* some lockset recompute happened.
* must re-check our references.
*/
for(i=0; i<nlock; i++) {
lockRecordRef *ref = &locker->refs[i];
lockSet *oldref = NULL;
if(!ref->plr) { /* this lockRecord slot not used */
assert(!ref->plockSet);
continue;
}
epicsSpinLock(ref->plr->spin);
if(ref->plockSet!=ref->plr->plockSet) {
changed = 1;
if(update) {
/* exchange saved lockSet reference */
oldref = ref->plockSet; /* will be NULL on first iteration */
ref->plockSet = ref->plr->plockSet;
dbLockIncRef(ref->plockSet);
}
}
epicsSpinUnlock(ref->plr->spin);
if(oldref)
dbLockDecRef(oldref);
if(!update && changed)
return changed;
}
#ifndef LOCKSET_NOCNT
/* Use the value captured before we started.
* If it has changed in the intrim we will catch this later
* during the update==0 pass (which triggers a re-try)
*/
if(update)
locker->recomp = recomp;
}
#endif
if(changed && update) {
qsort(locker->refs, nlock, sizeof(lockRecordRef),
&lrrcompare);
}
return changed;
}
void dbLockerPrepare(struct dbLocker *locker,
struct dbCommon * const *precs,
size_t nrecs)
{
size_t i;
locker->maxrefs = nrecs;
/* intentionally spoil the recomp count to ensure that
* references will be updated this first time
*/
#ifndef LOCKSET_NOCNT
locker->recomp = epicsAtomicGetSizeT(&recomputeCnt)-1;
#endif
for(i=0; i<nrecs; i++) {
locker->refs[i].plr = precs[i] ? precs[i]->lset : NULL;
}
/* acquire a reference to all lockRecords */
dbLockUpdateRefs(locker, 1);
}
dbLocker *dbLockerAlloc(dbCommon * const *precs,
size_t nrecs,
unsigned int flags)
{
size_t Nextra = nrecs>DBLOCKER_NALLOC ? nrecs-DBLOCKER_NALLOC : 0;
dbLocker *locker = calloc(1, sizeof(*locker)+Nextra*sizeof(lockRecordRef));
if(locker)
dbLockerPrepare(locker, precs, nrecs);
return locker;
}
void dbLockerFinalize(dbLocker *locker)
{
size_t i;
assert(ellCount(&locker->locked)==0);
/* release references taken in dbLockUpdateRefs() */
for(i=0; i<locker->maxrefs; i++) {
if(locker->refs[i].plockSet)
dbLockDecRef(locker->refs[i].plockSet);
}
}
void dbLockerFree(dbLocker *locker)
{
dbLockerFinalize(locker);
free(locker);
}
/* Lock the given list of records.
* This function modifies its arguments.
*/
void dbScanLockMany(dbLocker* locker)
{
size_t i, nlock = locker->maxrefs;
lockSet *plock;
#ifdef LOCKSET_DEBUG
const epicsThreadId myself = epicsThreadGetIdSelf();
#endif
if(ellCount(&locker->locked)!=0) {
cantProceed("dbScanLockMany(%p) already locked. Recursive locking not allowed", locker);
return;
}
retry:
assert(ellCount(&locker->locked)==0);
dbLockUpdateRefs(locker, 1);
for(i=0, plock=NULL; i<nlock; i++) {
lockRecordRef *ref = &locker->refs[i];
/* skip duplicates (same lockSet
* referenced by more than one lockRecord).
* Sorting will group these together.
*/
if(!ref->plr || (plock && plock==ref->plockSet))
continue;
plock = ref->plockSet;
epicsMutexMustLock(plock->lock);
assert(plock->ownerlocker==NULL);
plock->ownerlocker = locker;
ellAdd(&locker->locked, &plock->lockernode);
/* An extra ref for the locked list */
dbLockIncRef(plock);
#ifdef LOCKSET_DEBUG
if(plock->owner) {
if(plock->owner!=myself || plock->ownercount<1) {
errlogPrintf("dbScanLockMany(%p) ownership violation %p (%p) %u\n",
locker, plock->owner, myself, plock->ownercount);
cantProceed(NULL);
}
plock->ownercount++;
} else {
assert(plock->ownercount==0);
plock->owner = myself;
plock->ownercount = 1;
}
#endif
}
if(dbLockUpdateRefs(locker, 0)) {
/* oops, collided with recompute */
dbScanUnlockMany(locker);
goto retry;
}
if(nlock!=0 && ellCount(&locker->locked)<=0) {
/* if we have at least one lockRecord, then we will always lock
* at least its present lockSet
*/
errlogPrintf("dbScanLockMany(%p) didn't lock anything\n", locker);
cantProceed(NULL);
}
}
void dbScanUnlockMany(dbLocker* locker)
{
ELLNODE *cur;
#ifdef LOCKSET_DEBUG
const epicsThreadId myself = epicsThreadGetIdSelf();
#endif
while((cur=ellGet(&locker->locked))!=NULL) {
lockSet *plock = CONTAINER(cur, lockSet, lockernode);
assert(plock->ownerlocker==locker);
plock->ownerlocker = NULL;
#ifdef LOCKSET_DEBUG
assert(plock->owner==myself);
assert(plock->ownercount>=1);
plock->ownercount--;
if(plock->ownercount==0)
plock->owner = NULL;
#endif
epicsMutexUnlock(plock->lock);
/* release ref for locked list */
dbLockDecRef(plock);
}
}
typedef int (*reciter)(void*, DBENTRY*);
static int forEachRecord(void *priv, dbBase *pdbbase, reciter fn)
{
long status;
int ret = 0;
DBENTRY dbentry;
dbInitEntry(pdbbase,&dbentry);
status = dbFirstRecordType(&dbentry);
while(!status)
{
status = dbFirstRecord(&dbentry);
while(!status)
{
/* skip alias names */
if(!dbentry.precnode->recordname[0] || dbentry.precnode->flags & DBRN_FLAGS_ISALIAS) {
/* skip */
} else {
ret = fn(priv, &dbentry);
if(ret)
goto done;
}
status = dbNextRecord(&dbentry);
}
status = dbNextRecordType(&dbentry);
}
done:
dbFinishEntry(&dbentry);
return ret;
}
static int createLockRecord(void* junk, DBENTRY* pdbentry)
{
dbCommon *prec = pdbentry->precnode->precord;
lockRecord *lrec;
assert(!prec->lset);
/* TODO: one allocation for all records? */
lrec = callocMustSucceed(1, sizeof(*lrec), "lockRecord");
lrec->spin = epicsSpinCreate();
if(!lrec->spin)
cantProceed("no memory for spinlock in lockRecord");
lrec->precord = prec;
prec->lset = lrec;
prec->lset->plockSet = makeSet();
ellAdd(&prec->lset->plockSet->lockRecordList, &prec->lset->node);
return 0;
}
void dbLockInitRecords(dbBase *pdbbase)
{
epicsThreadOnce(&dbLockOnceInit, &dbLockOnce, NULL);
/* create all lockRecords and lockSets */
forEachRecord(NULL, pdbbase, &createLockRecord);
}
static int freeLockRecord(void* junk, DBENTRY* pdbentry)
{
dbCommon *prec = pdbentry->precnode->precord;
lockRecord *lr = prec->lset;
lockSet *ls = lr->plockSet;
prec->lset = NULL;
lr->precord = NULL;
assert(ls->refcount>0);
assert(ellCount(&ls->lockRecordList)>0);
ellDelete(&ls->lockRecordList, &lr->node);
dbLockDecRef(ls);
epicsSpinDestroy(lr->spin);
free(lr);
return 0;
}
void dbLockCleanupRecords(dbBase *pdbbase)
{
#ifndef LOCKSET_NOFREE
ELLNODE *cur;
#endif
epicsThreadOnce(&dbLockOnceInit, &dbLockOnce, NULL);
forEachRecord(NULL, pdbbase, &freeLockRecord);
if(ellCount(&lockSetsActive)) {
printf("Warning: dbLockCleanupRecords() leaking lockSets\n");
dblsr(NULL,2);
}
#ifndef LOCKSET_NOFREE
while((cur=ellGet(&lockSetsFree))!=NULL) {
lockSet *ls = (lockSet*)cur;
assert(ls->refcount==0);
assert(ellCount(&ls->lockRecordList)==0);
epicsMutexDestroy(ls->lock);
free(ls);
}
#endif
}
/* Called in two modes.
* During dbLockInitRecords w/ locker==NULL, then no mutex are locked.
* After dbLockInitRecords w/ locker!=NULL, then
* the caller must lock both pfirst and psecond.
*
* Assumes that pfirst has been modified
* to link to psecond.
*/
void dbLockSetMerge(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
{
ELLNODE *cur;
lockSet *A=pfirst->lset->plockSet,
*B=psecond->lset->plockSet;
int Nb;
#ifdef LOCKSET_DEBUG
const epicsThreadId myself = epicsThreadGetIdSelf();
#endif
assert(A && B);
#ifdef LOCKSET_DEBUG
if(locker && (A->owner!=myself || B->owner!=myself)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->owner, B->owner, myself);
cantProceed(NULL);
}
#endif
if(locker && (A->ownerlocker!=locker || B->ownerlocker!=locker)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") locker ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->ownerlocker, B->ownerlocker, locker);
cantProceed(NULL);
}
if(A==B)
return; /* already in the same lockSet */
Nb = ellCount(&B->lockRecordList);
assert(Nb>0);
/* move all records from B to A */
while((cur=ellGet(&B->lockRecordList))!=NULL)
{
lockRecord *lr = CONTAINER(cur, lockRecord, node);
assert(lr->plockSet==B);
ellAdd(&A->lockRecordList, cur);
epicsSpinLock(lr->spin);
lr->plockSet = A;
#ifndef LOCKSET_NOCNT
epicsAtomicIncrSizeT(&recomputeCnt);
#endif
epicsSpinUnlock(lr->spin);
}
/* there are at minimum, 1 ref for each lockRecord,
* and one for the locker's locked list
* (and perhaps another for its refs cache)
*/
assert(epicsAtomicGetIntT(&B->refcount)>=Nb+(locker?1:0));
/* update ref counters. for lockRecords */
epicsAtomicAddIntT(&A->refcount, Nb);
epicsAtomicAddIntT(&B->refcount, -Nb+1); /* drop all but one ref, see below */
if(locker) {
/* at least two refs, possibly three, remain.
* # One ref from above
* # locker->locked list, which is released now.
* # locker->refs array, assuming it is directly referenced,
* and not added as the result of a dbLockSetSplit,
* which will be cleaned when the locker is free'd (not here).
*/
#ifdef LOCKSET_DEBUG
B->owner = NULL;
B->ownercount = 0;
#endif
assert(B->ownerlocker==locker);
ellDelete(&locker->locked, &B->lockernode);
B->ownerlocker = NULL;
epicsAtomicDecrIntT(&B->refcount);
epicsMutexUnlock(B->lock);
}
dbLockDecRef(B); /* last ref we hold */
assert(A==psecond->lset->plockSet);
}
/* recompute assuming a link from pfirst to psecond
* may have been removed.
* pfirst and psecond must currently be in the same lockset,
* which the caller must lock before calling this function.
* If a new lockset is created, then it is locked
* when this function returns.
*/
void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
{
lockSet *ls = pfirst->lset->plockSet;
ELLLIST toInspect, newLS;
#ifdef LOCKSET_DEBUG
const epicsThreadId myself = epicsThreadGetIdSelf();
#endif
#ifdef LOCKSET_DEBUG
if(ls->owner!=myself || psecond->lset->plockSet->owner!=myself) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
ls->owner, psecond->lset->plockSet->owner, myself);
cantProceed(NULL);
}
#endif
/* lockset consistency violation */
if(ls!=psecond->lset->plockSet) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") consistency violation %p %p\n",
locker, pfirst->name, psecond->name,
pfirst->lset->plockSet, psecond->lset->plockSet);
cantProceed(NULL);
}
if(pfirst==psecond)
return;
/* at least 1 ref for each lockRecord,
* and one for the locker
*/
assert(epicsAtomicGetIntT(&ls->refcount)>=ellCount(&ls->lockRecordList)+1);
ellInit(&toInspect);
ellInit(&newLS);
/* strategy is to start with psecond and do
* a breadth first traversal until all records are
* visited. If we encounter pfirst, then there
* is no need to create a new lockset so we abort
* early.
*/
ellAdd(&toInspect, &psecond->lset->compnode);
psecond->lset->compflag = 1;
{
lockSet *splitset;
ELLNODE *cur;
while((cur=ellGet(&toInspect))!=NULL)
{
lockRecord *lr=CONTAINER(cur,lockRecord,compnode);
dbCommon *prec=lr->precord;
dbRecordType *rtype = prec->rdes;
size_t i;
ELLNODE *bcur;
ellAdd(&newLS, cur);
prec->lset->compflag = 2;
/* Visit all the links originating from prec */
for(i=0; i<rtype->no_links; i++) {
dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];
DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);
DBADDR *ptarget;
lockRecord *lr;
if(plink->type!=DB_LINK)
continue;
ptarget = plink->value.pv_link.pvt;
lr = ptarget->precord->lset;
assert(lr);
if(lr->precord==pfirst) {
/* so pfirst is still reachable from psecond,
* no new lock set should be created.
*/
goto nosplit;
}
/* have we already visited this record? */
if(lr->compflag)
continue;
ellAdd(&toInspect, &lr->compnode);
lr->compflag = 1;
}
/* Visit all links terminating at prec */
for(bcur=ellFirst(&prec->bklnk); bcur; bcur=ellNext(bcur))
{
struct pv_link *plink1 = CONTAINER(bcur, struct pv_link, backlinknode);
union value *plink2 = CONTAINER(plink1, union value, pv_link);
DBLINK *plink = CONTAINER(plink2, DBLINK, value);
lockRecord *lr = plink->precord->lset;
/* plink->type==DB_LINK is implied. Only DB_LINKs are tracked from BKLNK */
if(lr->precord==pfirst) {
goto nosplit;
}
if(lr->compflag)
continue;
ellAdd(&toInspect, &lr->compnode);
lr->compflag = 1;
}
}
/* All links involving psecond were traversed without finding
* pfirst. So we must create a new lockset.
* newLS contains the nodes which will
* make up this new lockset.
*/
/* newLS will have at least psecond in it */
assert(ellCount(&newLS) > 0);
/* If we didn't find pfirst, then it must be in the
* original lockset, and not the new one
*/
assert(ellCount(&newLS) < ellCount(&ls->lockRecordList));
assert(ellCount(&newLS) < ls->refcount);
splitset = makeSet(); /* reference for locker->locked */
epicsMutexMustLock(splitset->lock);
assert(splitset->ownerlocker==NULL);
ellAdd(&locker->locked, &splitset->lockernode);
splitset->ownerlocker = locker;
assert(splitset->refcount==1);
#ifdef LOCKSET_DEBUG
splitset->owner = ls->owner;
splitset->ownercount = 1;
assert(ls->ownercount==1);
#endif
while((cur=ellGet(&newLS))!=NULL)
{
lockRecord *lr=CONTAINER(cur,lockRecord,compnode);
lr->compflag = 0; /* reset for next time */
assert(lr->plockSet == ls);
ellDelete(&ls->lockRecordList, &lr->node);
ellAdd(&splitset->lockRecordList, &lr->node);
epicsSpinLock(lr->spin);
lr->plockSet = splitset;
#ifndef LOCKSET_NOCNT
epicsAtomicIncrSizeT(&recomputeCnt);
#endif
epicsSpinUnlock(lr->spin);
/* new lockSet is "live" at this point
* as other threads may find it.
*/
}
/* refcount of ls can't go to zero as the locker
* holds at least one reference (its locked list)
*/
epicsAtomicAddIntT(&ls->refcount, -ellCount(&splitset->lockRecordList));
assert(ls->refcount>0);
epicsAtomicAddIntT(&splitset->refcount, ellCount(&splitset->lockRecordList));
assert(splitset->refcount>=ellCount(&splitset->lockRecordList)+1);
assert(psecond->lset->plockSet==splitset);
/* must have refs from pfirst lockRecord,
* and the locked list.
*/
assert(epicsAtomicGetIntT(&ls->refcount)>=2);
return;
}
nosplit:
{
/* reset compflag for all nodes visited
* during the aborted search
*/
ELLNODE *cur;
while((cur=ellGet(&toInspect))!=NULL)
{
lockRecord *lr=CONTAINER(cur,lockRecord,compnode);
lr->compflag = 0;
}
while((cur=ellGet(&newLS))!=NULL)
{
lockRecord *lr=CONTAINER(cur,lockRecord,compnode);
lr->compflag = 0;
}
return;
}
}
static char *msstring[4]={"NMS","MS","MSI","MSS"};
long dblsr(char *recordname,int level)
{
int link;
DBENTRY dbentry;
DBENTRY *pdbentry=&dbentry;
long status;
dbCommon *precord;
lockSet *plockSet;
lockRecord *plockRecord;
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
DBLINK *plink;
if (recordname && ((*recordname == '\0') || !strcmp(recordname,"*")))
recordname = NULL;
if(recordname) {
dbInitEntry(pdbbase,pdbentry);
status = dbFindRecord(pdbentry,recordname);
if(status) {
printf("Record not found\n");
dbFinishEntry(pdbentry);
return 0;
}
precord = pdbentry->precnode->precord;
dbFinishEntry(pdbentry);
plockRecord = precord->lset;
if (!plockRecord) return 0; /* before iocInit */
plockSet = plockRecord->plockSet;
} else {
plockSet = (lockSet *)ellFirst(&lockSetsActive);
}
for( ; plockSet; plockSet = (lockSet *)ellNext(&plockSet->node)) {
printf("Lock Set %lu %d members %d refs epicsMutexId %p\n",
plockSet->id,ellCount(&plockSet->lockRecordList),plockSet->refcount,plockSet->lock);
if(level==0) { if(recordname) break; continue; }
for(plockRecord = (lockRecord *)ellFirst(&plockSet->lockRecordList);
plockRecord; plockRecord = (lockRecord *)ellNext(&plockRecord->node)) {
precord = plockRecord->precord;
pdbRecordType = precord->rdes;
printf("%s\n",precord->name);
if(level<=1) continue;
for(link=0; (link<pdbRecordType->no_links) ; link++) {
DBADDR *pdbAddr;
pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[link]];
plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if(plink->type != DB_LINK) continue;
pdbAddr = (DBADDR *)(plink->value.pv_link.pvt);
printf("\t%s",pdbFldDes->name);
if(pdbFldDes->field_type==DBF_INLINK) {
printf("\t INLINK");
} else if(pdbFldDes->field_type==DBF_OUTLINK) {
printf("\tOUTLINK");
} else if(pdbFldDes->field_type==DBF_FWDLINK) {
printf("\tFWDLINK");
}
printf(" %s %s",
((plink->value.pv_link.pvlMask&pvlOptPP)?" PP":"NPP"),
msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
printf(" %s\n",pdbAddr->precord->name);
}
}
if(recordname) break;
}
return 0;
}
long dbLockShowLocked(int level)
{
int indListType;
lockSet *plockSet;
printf("Active lockSets: %d\n", ellCount(&lockSetsActive));
#ifndef LOCKSET_NOFREE
printf("Free lockSets: %d\n", ellCount(&lockSetsFree));
#endif
/*Even if failure on lockSetModifyLock will continue */
for(indListType=0; indListType <= 1; ++indListType) {
plockSet = (lockSet *)ellFirst(&lockSetsActive);
if(plockSet) {
if (indListType==0)
printf("listTypeScanLock\n");
else
printf("listTypeRecordLock\n");
}
while(plockSet) {
epicsMutexLockStatus status;
status = epicsMutexTryLock(plockSet->lock);
if(status==epicsMutexLockOK) epicsMutexUnlock(plockSet->lock);
if(status!=epicsMutexLockOK || indListType==1) {
epicsMutexShow(plockSet->lock,level);
}
plockSet = (lockSet *)ellNext(&plockSet->node);
}
}
return 0;
}
int * dbLockSetAddrTrace(dbCommon *precord)
{
lockRecord *plockRecord = precord->lset;
lockSet *plockSet = plockRecord->plockSet;
return(&plockSet->trace);
}
+64
View File
@@ -0,0 +1,64 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbLock.h */
/* Author: Marty Kraimer Date: 12MAR96 */
#ifndef INCdbLockh
#define INCdbLockh
#include "ellLib.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
struct dbCommon;
struct dbBase;
typedef struct dbLocker dbLocker;
epicsShareFunc void dbScanLock(struct dbCommon *precord);
epicsShareFunc void dbScanUnlock(struct dbCommon *precord);
epicsShareFunc dbLocker *dbLockerAlloc(struct dbCommon * const *precs,
size_t nrecs,
unsigned int flags);
epicsShareFunc void dbLockerFree(dbLocker *);
epicsShareFunc void dbScanLockMany(dbLocker*);
epicsShareFunc void dbScanUnlockMany(dbLocker*);
epicsShareFunc unsigned long dbLockGetLockId(
struct dbCommon *precord);
epicsShareFunc void dbLockInitRecords(struct dbBase *pdbbase);
epicsShareFunc void dbLockCleanupRecords(struct dbBase *pdbbase);
/* Lock Set Report */
epicsShareFunc long dblsr(char *recordname,int level);
/* If recordname NULL then all records*/
/* level = (0,1,2) (lock set state, + recordname, +DB links) */
epicsShareFunc long dbLockShowLocked(int level);
/*KLUDGE to support field TPRO*/
epicsShareFunc int * dbLockSetAddrTrace(struct dbCommon *precord);
/* debugging */
epicsShareFunc unsigned long dbLockGetRefs(struct dbCommon*);
epicsShareFunc unsigned long dbLockCountSets(void);
#ifdef __cplusplus
}
#endif
#endif /*INCdbLockh*/
+110
View File
@@ -0,0 +1,110 @@
/*************************************************************************\
* Copyright (c) 2014 Brookhaven Science Assoc., as Operator of Brookhaven
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef DBLOCKPVT_H
#define DBLOCKPVT_H
#include "dbLock.h"
#include "epicsSpin.h"
/* Define to enable additional error checking */
#undef LOCKSET_DEBUG
/* Define to disable the free list for lockSets */
#undef LOCKSET_NOFREE
/* Define to disable use of recomputeCnt optimization */
#undef LOCKSET_NOCNT
/* except for refcount (and lock), all members of dbLockSet
* are guarded by its lock.
*/
typedef struct dbLockSet {
ELLNODE node;
ELLLIST lockRecordList; /* holds lockRecord::node */
epicsMutexId lock;
unsigned long id;
int refcount;
#ifdef LOCKSET_DEBUG
int ownercount;
epicsThreadId owner;
#endif
dbLocker *ownerlocker;
ELLNODE lockernode;
int trace; /*For field TPRO*/
} lockSet;
struct lockRecord;
/* dbCommon.LSET is a plockRecord.
* Except for spin and plockSet, all members of lockRecord are guarded
* by the present lockset lock.
* plockSet is guarded by spin.
*/
typedef struct lockRecord {
ELLNODE node; /* in lockSet::lockRecordList */
/* The association between lockRecord and lockSet
* can only be changed while the lockSet is held,
* and the lockRecord's spinlock is held.
* It may be read which either lock is held.
*/
lockSet *plockSet;
/* the association between lockRecord and dbCommon never changes */
dbCommon *precord;
epicsSpinId spin;
/* temp used during lockset split.
* lockSet must be locked for access
*/
ELLNODE compnode;
unsigned int compflag;
} lockRecord;
typedef struct {
lockRecord *plr;
/* the last lock found associated with the ref.
* not stable unless lock is locked, or ref spin
* is locked.
*/
lockSet *plockSet;
} lockRecordRef;
#define DBLOCKER_NALLOC 2
/* a dbLocker can only be used by a single thread. */
struct dbLocker {
ELLLIST locked;
#ifndef LOCKSET_NOCNT
size_t recomp; /* snapshot of recomputeCnt when refs[] cache updated */
#endif
size_t maxrefs;
lockRecordRef refs[DBLOCKER_NALLOC]; /* actual length is maxrefs */
};
/* These are exported for testing only */
epicsShareFunc lockSet* dbLockGetRef(lockRecord *lr); /* lookup lockset and increment ref count */
epicsShareFunc void dbLockIncRef(lockSet* ls);
epicsShareFunc void dbLockDecRef(lockSet *ls);
/* Calling dbLockerPrepare directly is an internal
* optimization used when dbLocker on the stack.
* nrecs must be <=DBLOCKER_NALLOC.
*/
void dbLockerPrepare(struct dbLocker *locker,
struct dbCommon * const *precs,
size_t nrecs);
void dbLockerFinalize(dbLocker *);
void dbLockSetMerge(struct dbLocker *locker,
struct dbCommon *pfirst,
struct dbCommon *psecond);
void dbLockSetSplit(struct dbLocker *locker,
struct dbCommon *psource,
struct dbCommon *psecond);
#endif /* DBLOCKPVT_H */
+686
View File
@@ -0,0 +1,686 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbNotify.c */
/*
* Author: Marty Kraimer
* Andrew Johnson <anj@aps.anl.gov>
*
* Extracted from dbLink.c
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "cantProceed.h"
#include "dbDefs.h"
#include "ellLib.h"
#include "epicsAssert.h"
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "errlog.h"
#include "errMdef.h"
#define epicsExportSharedSymbols
#include "callback.h"
#include "dbAccessDefs.h"
#include "dbBase.h"
#include "dbChannel.h"
#include "dbCommon.h"
#include "dbFldTypes.h"
#include "dbLock.h"
#include "dbNotify.h"
#include "dbScan.h"
#include "dbStaticLib.h"
#include "link.h"
#include "recGbl.h"
/*notify state values */
typedef enum {
notifyNotActive,
notifyWaitForRestart,
notifyRestartCallbackRequested,
notifyRestartInProgress,
notifyProcessInProgress,
notifyUserCallbackRequested,
notifyUserCallbackActive
} notifyState;
/*structure attached to ppnr field of each record*/
typedef struct processNotifyRecord {
ellCheckNode waitNode;
ELLLIST restartList; /*list of processNotifys to restart*/
dbCommon *precord;
} processNotifyRecord;
#define MAGIC 0xfedc0123
typedef struct notifyPvt {
ELLNODE node; /*For free list*/
long magic;
short state;
CALLBACK callback;
ELLLIST waitList; /*list of records for current processNotify*/
short cancelWait;
short userCallbackWait;
epicsEventId cancelEvent;
epicsEventId userCallbackEvent;
} notifyPvt;
/* processNotify groups can span locksets if links are dynamically modified*/
/* Thus a global lock is taken while processNotify fields are accessed */
typedef struct notifyGlobal {
epicsMutexId lock;
ELLLIST freeList;
} notifyGlobal;
static notifyGlobal *pnotifyGlobal = 0;
/*Local routines*/
static void notifyInit(processNotify *ppn);
static void notifyCleanup(processNotify *ppn);
static void restartCheck(processNotifyRecord *ppnr);
static void callDone(dbCommon *precord,processNotify *ppn);
static void processNotifyCommon(processNotify *ppn,dbCommon *precord);
static void notifyCallback(CALLBACK *pcallback);
#define ellSafeAdd(list,listnode) \
{ \
assert((listnode)->isOnList==0); \
ellAdd((list),&((listnode)->node)); \
(listnode)->isOnList=1; \
}
#define ellSafeDelete(list,listnode) \
{ \
assert((listnode)->isOnList); \
ellDelete((list),&((listnode)->node)); \
(listnode)->isOnList=0; \
}
static void notifyFree(void *raw)
{
notifyPvt *pnotifyPvt = raw;
assert(pnotifyPvt->magic==MAGIC);
epicsEventDestroy(pnotifyPvt->cancelEvent);
epicsEventDestroy(pnotifyPvt->userCallbackEvent);
free(pnotifyPvt);
}
static void notifyInit(processNotify *ppn)
{
notifyPvt *pnotifyPvt;
pnotifyPvt = (notifyPvt *) ellFirst(&pnotifyGlobal->freeList);
if (pnotifyPvt) {
ellDelete(&pnotifyGlobal->freeList, &pnotifyPvt->node);
} else {
pnotifyPvt = dbCalloc(1,sizeof(notifyPvt));
pnotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty);
pnotifyPvt->userCallbackEvent = epicsEventCreate(epicsEventEmpty);
pnotifyPvt->magic = MAGIC;
pnotifyPvt->state = notifyNotActive;
}
pnotifyPvt->state = notifyNotActive;
callbackSetCallback(notifyCallback,&pnotifyPvt->callback);
callbackSetUser(ppn,&pnotifyPvt->callback);
callbackSetPriority(priorityLow,&pnotifyPvt->callback);
ellInit(&pnotifyPvt->waitList);
ppn->status = notifyOK;
ppn->wasProcessed = 0;
pnotifyPvt->state = notifyNotActive;
pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0;
ppn->pnotifyPvt = pnotifyPvt;
}
static void notifyCleanup(processNotify *ppn)
{
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
pnotifyPvt->state = notifyNotActive;
ellAdd(&pnotifyGlobal->freeList, &pnotifyPvt->node);
ppn->pnotifyPvt = 0;
}
static void restartCheck(processNotifyRecord *ppnr)
{
dbCommon *precord = ppnr->precord;
processNotify *pfirst;
notifyPvt *pnotifyPvt;
assert(precord->ppn);
pfirst = (processNotify *) ellFirst(&ppnr->restartList);
if (!pfirst) {
precord->ppn = 0;
return;
}
pnotifyPvt = (notifyPvt *) pfirst->pnotifyPvt;
assert(pnotifyPvt->state == notifyWaitForRestart);
/* remove pfirst from restartList */
ellSafeDelete(&ppnr->restartList, &pfirst->restartNode);
/*make pfirst owner of the record*/
precord->ppn = pfirst;
/* request callback for pfirst */
pnotifyPvt->state = notifyRestartCallbackRequested;
callbackRequest(&pnotifyPvt->callback);
}
static void callDone(dbCommon *precord, processNotify *ppn)
{
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
epicsMutexUnlock(pnotifyGlobal->lock);
if (ppn->requestType == processGetRequest ||
ppn->requestType == putProcessGetRequest) {
ppn->getCallback(ppn, getFieldType);
}
dbScanUnlock(precord);
ppn->doneCallback(ppn);
epicsMutexMustLock(pnotifyGlobal->lock);
if (pnotifyPvt->cancelWait && pnotifyPvt->userCallbackWait) {
errlogPrintf("%s processNotify: both cancelWait and userCallbackWait true."
"This is illegal\n", precord->name);
pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0;
}
if (!pnotifyPvt->cancelWait && !pnotifyPvt->userCallbackWait) {
notifyCleanup(ppn);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
if (pnotifyPvt->cancelWait) {
pnotifyPvt->cancelWait = 0;
epicsEventSignal(pnotifyPvt->cancelEvent);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
assert(pnotifyPvt->userCallbackWait);
pnotifyPvt->userCallbackWait = 0;
epicsEventSignal(pnotifyPvt->userCallbackEvent);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
static void processNotifyCommon(processNotify *ppn,dbCommon *precord)
{
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
int didPut = 0;
int doProcess = 0;
if (precord->ppn &&
pnotifyPvt->state != notifyRestartCallbackRequested) {
/* Another processNotify owns the record */
pnotifyPvt->state = notifyWaitForRestart;
ellSafeAdd(&precord->ppnr->restartList, &ppn->restartNode);
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
} else if (precord->ppn) {
assert(precord->ppn == ppn);
assert(pnotifyPvt->state == notifyRestartCallbackRequested);
}
if (precord->pact) {
precord->ppn = ppn;
ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
pnotifyPvt->state = notifyRestartInProgress;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
}
if (ppn->requestType == putProcessRequest ||
ppn->requestType == putProcessGetRequest) {
/* Check if puts disabled */
if (precord->disp && (dbChannelField(ppn->chan) != (void *) &precord->disp)) {
ppn->putCallback(ppn, putDisabledType);
} else {
didPut = ppn->putCallback(ppn, putType);
}
}
/* Check if dbProcess should be called */
if (didPut &&
((dbChannelField(ppn->chan) == (void *) &precord->proc) ||
(dbChannelFldDes(ppn->chan)->process_passive && precord->scan == 0)))
doProcess = 1;
else
if (ppn->requestType == processGetRequest &&
precord->scan == 0)
doProcess = 1;
if (doProcess) {
ppn->wasProcessed = 1;
precord->ppn = ppn;
ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
pnotifyPvt->state = notifyProcessInProgress;
epicsMutexUnlock(pnotifyGlobal->lock);
dbProcess(precord);
dbScanUnlock(precord);
return;
}
if (pnotifyPvt->state == notifyRestartCallbackRequested) {
restartCheck(precord->ppnr);
}
pnotifyPvt->state = notifyUserCallbackActive;
assert(precord->ppn!=ppn);
callDone(precord, ppn);
}
static void notifyCallback(CALLBACK *pcallback)
{
processNotify *ppn = NULL;
dbCommon *precord;
notifyPvt *pnotifyPvt;
callbackGetUser(ppn,pcallback);
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
precord = dbChannelRecord(ppn->chan);
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
assert(precord->ppnr);
assert(pnotifyPvt->state == notifyRestartCallbackRequested ||
pnotifyPvt->state == notifyUserCallbackRequested);
assert(ellCount(&pnotifyPvt->waitList) == 0);
if (pnotifyPvt->cancelWait) {
if (pnotifyPvt->state == notifyRestartCallbackRequested) {
restartCheck(precord->ppnr);
}
epicsEventSignal(pnotifyPvt->cancelEvent);
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
}
if(pnotifyPvt->state == notifyRestartCallbackRequested) {
processNotifyCommon(ppn, precord);
return;
}
/* All done. Clean up and call userCallback */
pnotifyPvt->state = notifyUserCallbackActive;
assert(precord->ppn!=ppn);
callDone(precord, ppn);
}
void dbProcessNotifyExit(void)
{
ellFree2(&pnotifyGlobal->freeList, &notifyFree);
epicsMutexDestroy(pnotifyGlobal->lock);
free(pnotifyGlobal);
pnotifyGlobal = NULL;
}
void dbProcessNotifyInit(void)
{
if (pnotifyGlobal)
return;
pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal));
pnotifyGlobal->lock = epicsMutexMustCreate();
ellInit(&pnotifyGlobal->freeList);
}
void dbProcessNotify(processNotify *ppn)
{
struct dbChannel *chan = ppn->chan;
dbCommon *precord = dbChannelRecord(chan);
short dbfType = dbChannelFieldType(chan);
notifyPvt *pnotifyPvt;
/* Must handle DBF_XXXLINKs as special case.
* Only dbPutField will change link fields.
* Also the record is not processed as a result
*/
ppn->status = notifyOK;
ppn->wasProcessed = 0;
if (dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) {
if (ppn->requestType == putProcessRequest ||
ppn->requestType == putProcessGetRequest) {
/* Check if puts disabled */
if (precord->disp && (dbChannelField(ppn->chan) != (void *) &precord->disp)) {
ppn->putCallback(ppn, putDisabledType);
} else {
ppn->putCallback(ppn, putFieldType);
}
}
if (ppn->requestType == processGetRequest ||
ppn->requestType == putProcessGetRequest) {
ppn->getCallback(ppn, getFieldType);
}
ppn->doneCallback(ppn);
return;
}
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
if (pnotifyPvt && (pnotifyPvt->magic != MAGIC)) {
printf("dbPutNotify:pnotifyPvt was not initialized\n");
pnotifyPvt = 0;
}
if (pnotifyPvt) {
assert(pnotifyPvt->state == notifyUserCallbackActive);
pnotifyPvt->userCallbackWait = 1;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
epicsEventWait(pnotifyPvt->userCallbackEvent);
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
notifyCleanup(ppn);
}
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
assert(!pnotifyPvt);
notifyInit(ppn);
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
if (!precord->ppnr) {
/* make sure record has a processNotifyRecord*/
precord->ppnr = dbCalloc(1, sizeof(processNotifyRecord));
precord->ppnr->precord = precord;
ellInit(&precord->ppnr->restartList);
}
processNotifyCommon(ppn, precord);
}
void dbNotifyCancel(processNotify *ppn)
{
dbCommon *precord = dbChannelRecord(ppn->chan);
notifyState state;
notifyPvt *pnotifyPvt;
dbScanLock(precord);
epicsMutexMustLock(pnotifyGlobal->lock);
ppn->status = notifyCanceled;
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
if (!pnotifyPvt || pnotifyPvt->state == notifyNotActive) {
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
return;
}
state = pnotifyPvt->state;
switch (state) {
case notifyUserCallbackRequested:
case notifyRestartCallbackRequested:
case notifyUserCallbackActive:
/* Callback is scheduled or active, wait for it to complete */
pnotifyPvt->cancelWait = 1;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
epicsEventWait(pnotifyPvt->cancelEvent);
epicsMutexMustLock(pnotifyGlobal->lock);
notifyCleanup(ppn);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
case notifyNotActive:
break;
case notifyWaitForRestart:
assert(precord->ppn);
assert(precord->ppn!=ppn);
ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode);
break;
case notifyRestartInProgress:
case notifyProcessInProgress:
{ /*Take all records out of wait list */
processNotifyRecord *ppnrWait;
while ((ppnrWait = (processNotifyRecord *)
ellFirst(&pnotifyPvt->waitList))) {
ellSafeDelete(&pnotifyPvt->waitList, &ppnrWait->waitNode);
restartCheck(ppnrWait);
}
}
if (precord->ppn == ppn)
restartCheck(precord->ppnr);
break;
default:
printf("dbNotify: illegal state for notifyCallback\n");
}
pnotifyPvt->state = notifyNotActive;
notifyCleanup(ppn);
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
}
void dbNotifyCompletion(dbCommon *precord)
{
processNotify *ppn = precord->ppn;
notifyPvt *pnotifyPvt;
epicsMutexMustLock(pnotifyGlobal->lock);
assert(ppn);
assert(precord->ppnr);
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
if (pnotifyPvt->state != notifyRestartInProgress &&
pnotifyPvt->state != notifyProcessInProgress) {
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
ellSafeDelete(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
if ((ellCount(&pnotifyPvt->waitList) != 0)) {
restartCheck(precord->ppnr);
}
else if (pnotifyPvt->state == notifyProcessInProgress) {
pnotifyPvt->state = notifyUserCallbackRequested;
restartCheck(precord->ppnr);
callbackRequest(&pnotifyPvt->callback);
}
else if(pnotifyPvt->state == notifyRestartInProgress) {
pnotifyPvt->state = notifyRestartCallbackRequested;
callbackRequest(&pnotifyPvt->callback);
} else {
cantProceed("dbNotifyCompletion illegal state");
}
epicsMutexUnlock(pnotifyGlobal->lock);
}
void dbNotifyAdd(dbCommon *pfrom, dbCommon *pto)
{
processNotify *ppn = pfrom->ppn;
notifyPvt *pnotifyPvt;
if (pto->pact)
return; /*if active it will not be processed*/
epicsMutexMustLock(pnotifyGlobal->lock);
if (!pto->ppnr) {/* make sure record has a processNotifyRecord*/
pto->ppnr = dbCalloc(1, sizeof(processNotifyRecord));
pto->ppnr->precord = pto;
ellInit(&pto->ppnr->restartList);
}
assert(ppn);
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
if (!pto->ppn &&
(pnotifyPvt->state == notifyProcessInProgress) &&
(pto != dbChannelRecord(ppn->chan))) {
notifyPvt *pnotifyPvt;
pto->ppn = pfrom->ppn;
pnotifyPvt = (notifyPvt *) pfrom->ppn->pnotifyPvt;
ellSafeAdd(&pnotifyPvt->waitList, &pto->ppnr->waitNode);
}
epicsMutexUnlock(pnotifyGlobal->lock);
}
typedef struct tpnInfo {
epicsEventId callbackDone;
processNotify *ppn;
char buffer[80];
} tpnInfo;
static int putCallback(processNotify *ppn, notifyPutType type)
{
tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
int status = 0;
if (ppn->status == notifyCanceled)
return 0;
ppn->status = notifyOK;
switch (type) {
case putDisabledType:
ppn->status = notifyError;
return 0;
case putFieldType:
status = dbChannelPutField(ppn->chan, DBR_STRING, ptpnInfo->buffer, 1);
break;
case putType:
status = dbChannelPut(ppn->chan, DBR_STRING, ptpnInfo->buffer, 1);
break;
}
if (status)
ppn->status = notifyError;
return 1;
}
static void getCallback(processNotify *ppn,notifyGetType type)
{
tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
int status = 0;
long no_elements = 1;
long options = 0;
if(ppn->status==notifyCanceled) {
printf("dbtpn:getCallback notifyCanceled\n");
return;
}
switch(type) {
case getFieldType:
status = dbChannelGetField(ppn->chan, DBR_STRING, ptpnInfo->buffer,
&options, &no_elements, 0);
break;
case getType:
status = dbChannelGet(ppn->chan, DBR_STRING, ptpnInfo->buffer,
&options, &no_elements, 0);
break;
}
if (status) {
ppn->status = notifyError;
printf("dbtpn:getCallback error\n");
} else {
printf("dbtpn:getCallback value %s\n", ptpnInfo->buffer);
}
}
static void doneCallback(processNotify *ppn)
{
notifyStatus status = ppn->status;
tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
const char *pname = dbChannelRecord(ppn->chan)->name;
if (status == 0)
printf("dbtpnCallback: success record=%s\n", pname);
else
printf("%s dbtpnCallback processNotify.status %d\n",
pname, (int) status);
epicsEventSignal(ptpnInfo->callbackDone);
}
static void tpnThread(void *pvt)
{
tpnInfo *ptpnInfo = (tpnInfo *) pvt;
processNotify *ppn = (processNotify *) ptpnInfo->ppn;
dbProcessNotify(ppn);
epicsEventWait(ptpnInfo->callbackDone);
dbNotifyCancel(ppn);
epicsEventDestroy(ptpnInfo->callbackDone);
dbChannelDelete(ppn->chan);
free(ppn);
free(ptpnInfo);
}
long dbtpn(char *pname, char *pvalue)
{
struct dbChannel *chan;
tpnInfo *ptpnInfo;
processNotify *ppn=NULL;
chan = dbChannelCreate(pname);
if (!chan) {
printf("dbtpn: No such channel");
return -1;
}
ppn = dbCalloc(1, sizeof(processNotify));
ppn->requestType = pvalue ? putProcessRequest : processGetRequest;
ppn->chan = chan;
ppn->putCallback = putCallback;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ptpnInfo = dbCalloc(1, sizeof(tpnInfo));
ptpnInfo->ppn = ppn;
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
strncpy(ptpnInfo->buffer, pvalue, 80);
ptpnInfo->buffer[79] = 0;
ppn->usrPvt = ptpnInfo;
epicsThreadCreate("dbtpn", epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
return 0;
}
int dbNotifyDump(void)
{
epicsMutexLockStatus lockStatus;
dbRecordType *pdbRecordType;
processNotify *ppnRestart;
processNotifyRecord *ppnr;
int itry;
for (itry = 0; itry < 100; itry++) {
lockStatus = epicsMutexTryLock(pnotifyGlobal->lock);
if (lockStatus == epicsMutexLockOK)
break;
epicsThreadSleep(.05);
}
for (pdbRecordType = (dbRecordType *) ellFirst(&pdbbase->recordTypeList);
pdbRecordType;
pdbRecordType = (dbRecordType *) ellNext(&pdbRecordType->node)) {
dbRecordNode *pdbRecordNode;
for (pdbRecordNode = (dbRecordNode *) ellFirst(&pdbRecordType->recList);
pdbRecordNode;
pdbRecordNode = (dbRecordNode *) ellNext(&pdbRecordNode->node)) {
dbCommon *precord = pdbRecordNode->precord;
processNotify *ppn;
notifyPvt *pnotifyPvt;
if (!precord->name[0] || pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
continue;
ppn = precord->ppn;
if (!ppn || !precord->ppnr)
continue;
if (dbChannelRecord(precord->ppn->chan) != precord)
continue;
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
printf("%s state %d ppn %p\n waitList\n",
precord->name, pnotifyPvt->state, (void*) ppn);
ppnr = (processNotifyRecord *) ellFirst(&pnotifyPvt->waitList);
while (ppnr) {
printf(" %s pact %d\n",
ppnr->precord->name, ppnr->precord->pact);
ppnr = (processNotifyRecord *) ellNext(&ppnr->waitNode.node);
}
ppnr = precord->ppnr;
if (ppnr) {
ppnRestart = (processNotify *)ellFirst(
&precord->ppnr->restartList);
if (ppnRestart)
printf("%s restartList\n", precord->name);
while (ppnRestart) {
printf(" %s\n", dbChannelRecord(ppnRestart->chan)->name);
ppnRestart = (processNotify *) ellNext(
&ppnRestart->restartNode.node);
}
}
}
}
if (lockStatus == epicsMutexLockOK)
epicsMutexUnlock(pnotifyGlobal->lock);
return 0;
}
+168
View File
@@ -0,0 +1,168 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbNotify.h */
#ifndef INCdbNotifyh
#define INCdbNotifyh
#include "shareLib.h"
#include "ellLib.h"
#include "epicsEvent.h"
#include "callback.h"
#ifdef __cplusplus
extern "C" {
#endif
struct dbCommon;
struct processNotify;
typedef struct ellCheckNode{
ELLNODE node;
int isOnList;
} ellCheckNode;
typedef enum {
processRequest,
putProcessRequest,
processGetRequest,
putProcessGetRequest
} notifyRequestType;
typedef enum {
putDisabledType,
putFieldType,
putType
} notifyPutType;
typedef enum {
getFieldType,
getType /* FIXME: Never used? */
} notifyGetType;
typedef enum {
notifyOK,
notifyCanceled,
notifyError,
notifyPutDisabled
} notifyStatus;
typedef struct processNotify {
/* following fields are for private use by dbNotify implementation */
ellCheckNode restartNode;
void *pnotifyPvt;
/* The following fields are set by dbNotify. */
notifyStatus status;
int wasProcessed; /* (0,1) => (no,yes) */
/*The following members are set by user*/
notifyRequestType requestType;
struct dbChannel *chan; /*dbChannel*/
int (*putCallback)(struct processNotify *,notifyPutType type);
void (*getCallback)(struct processNotify *,notifyGetType type);
void (*doneCallback)(struct processNotify *);
void *usrPvt; /*for private use of user*/
} processNotify;
/* dbProcessNotify and dbNotifyCancel are called by user*/
epicsShareFunc void dbProcessNotify(processNotify *pprocessNotify);
epicsShareFunc void dbNotifyCancel(processNotify *pprocessNotify);
/* dbProcessNotifyInit called by iocInit */
epicsShareFunc void dbProcessNotifyInit(void);
epicsShareFunc void dbProcessNotifyExit(void);
/*dbNotifyAdd called by dbScanPassive and dbScanLink*/
epicsShareFunc void dbNotifyAdd(
struct dbCommon *pfrom,struct dbCommon *pto);
/*dbNotifyCompletion called by recGblFwdLink or dbAccess*/
epicsShareFunc void dbNotifyCompletion(struct dbCommon *precord);
/* db_put_process defined here since it requires dbNotify.
* src_type is the old DBR type
* This is called by a dbNotify putCallback that uses oldDbr types
*/
epicsShareFunc int db_put_process(
processNotify *processNotify,notifyPutType type,
int src_type,const void *psrc, int no_elements);
/* dbtpn is test routine for dbNotify putProcessRequest */
epicsShareFunc long dbtpn(char *recordname,char *value);
/* dbNotifyDump is an INVASIVE debug utility. Don't use this needlessly*/
epicsShareFunc int dbNotifyDump(void);
/* This module provides code to handle process notify.
* client code semantics are:
* 1) The client code allocates storage for a processNotify structure.
* This structure can be used for multiple calls to dbProcessNotify.
* The client is responsible for setting the following fields :
* requestType - The type of request.
* chan - This is typically set via a call to dbChannelCreate.
* putCallback - If requestType is putProcessRequest or putProcessGetRequest
* getCallback - If request is processGetRequest or putProcessGetRequest
* doneCallback - Must be set
* usrPvt - For exclusive use of client. dbNotify does not access this field
* 2) The client calls dbProcessNotify.
* 3) putCallback is called after dbNotify has claimed the record instance
* but before a potential process is requested.
* The putCallback MUST issue the correct put request
* specified by notifyPutType
* 4) getCallback is called after a possible process is complete
* (including asynchronous completion) but before dbNotify has
* released the record.
* The getCallback MUST issue the correct get request
* specified by notifyGetType
* 5) doneCallback is called when dbNotify has released the record.
* The client can issue a new dbProcessNotify request from
* doneCallback or anytime after doneCallback returns.
* 6) The client can call dbNotifyCancel at any time.
* If a dbProcessNotify is active, dbNotifyCancel will not return until
* the dbNotifyRequest is actually canceled. The client must be prepared
* for a callback to be called while dbNotifyCancel is active.
*
* dbProcessNotify handles the semantics of record locking and deciding
* if a process request is issued and also calls the client callbacks.
*
* A process request is issued if any of the following is true.
* 1) The requester has issued a processs request and record is passive.
* 2) The requester is doing a put, the record is passive, and either
* a) The field description is process passive.
* b) The field is PROC.
* 3) The requester has requested processGet and the record is passive.
*
* iocInit calls processNotifyInit.
*
* The other global routines (dbNotifyAdd and dbNotifyCompletion) are called by:
*
* dbAccess.c
* dbScanPassive and dbScanLink
* call dbNotifyAdd just before calling dbProcess
* dbProcess
* Calls dbNotifyCompletion if dbProcess does not call process
* Unless pact is already true.
* recGbl
* recGblFwdLink calls dbNotifyCompletion
*
* Two fields in dbCommon are used for put notify.
* ppn pointer to processNotify
* If a record is part of a put notify group,
* This field is the address of the associated processNotify.
* As soon as a record completes processing the field is set NULL
* ppnr pointer to processNotifyRecord, which is a private structure
* owned by dbNotify.
* dbNotify is reponsible for this structure.
*
*/
#ifdef __cplusplus
}
#endif
#endif /*INCdbNotifyh*/
@@ -0,0 +1,231 @@
/*************************************************************************\
* Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author:
* Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <string>
#include <stdexcept>
#include <limits.h>
#include <string.h>
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "epicsTime.h"
#include "tsFreeList.h"
#include "errMdef.h"
#include "errlog.h"
#include "caerr.h" // this needs to be eliminated
#include "db_access.h" // this needs to be eliminated
#define epicsExportSharedSymbols
#include "dbCAC.h"
#include "dbChannelIO.h"
#include "dbPutNotifyBlocker.h"
dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) :
mutex ( mutexIn ), pNotify ( 0 ),
maxValueSize ( sizeof ( this->dbrScalarValue ) )
{
memset ( & this->pn, '\0', sizeof ( this->pn ) );
memset ( & this->dbrScalarValue, '\0', sizeof ( this->dbrScalarValue ) );
this->pbuffer = & this->dbrScalarValue;
}
dbPutNotifyBlocker::~dbPutNotifyBlocker ()
{
}
void dbPutNotifyBlocker::destructor ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->cancel ( cbGuard, guard );
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
char * pBuf = static_cast < char * > ( this->pbuffer );
delete [] pBuf;
}
this->~dbPutNotifyBlocker ();
}
void dbPutNotifyBlocker::cancel (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pNotify ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
dbNotifyCancel ( &this->pn );
}
this->pNotify = 0;
this->block.signal ();
}
void dbPutNotifyBlocker::expandValueBuf (
epicsGuard < epicsMutex > & guard, unsigned long newSize )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->maxValueSize < newSize ) {
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
char * pBuf = static_cast < char * > ( this->pbuffer );
delete [] pBuf;
this->maxValueSize = sizeof ( this->dbrScalarValue );
this->pbuffer = & this->dbrScalarValue;
}
this->pbuffer = new char [newSize];
this->maxValueSize = newSize;
}
}
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType type )
{
if(ppn->status==notifyCanceled) return 0;
/*
* No locking in this method because only a dbNotifyCancel could interrupt
* and it does not return until cancel is done.
*/
dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
return db_put_process(ppn,type,
pBlocker->dbrType,pBlocker->pbuffer,pBlocker->nRequest);
}
extern "C" void putNotifyCompletion ( processNotify *ppn )
{
dbPutNotifyBlocker * const pBlocker =
static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
epicsGuard < epicsMutex > guard ( pBlocker->mutex );
cacWriteNotify * const pNtfy = pBlocker->pNotify;
if ( pNtfy ) {
pBlocker->pNotify = 0;
// Its necessary to signal the initiators now before we call
// the user callback. This is less efficent, and potentially
// causes more thread context switching, but its probably
// unavoidable because its possible that the use callback
// might destroy this object.
pBlocker->block.signal ();
if ( pBlocker->pn.status != notifyOK ) {
pNtfy->exception (
guard, ECA_PUTFAIL, "put notify unsuccessful",
static_cast < unsigned > (pBlocker->dbrType),
static_cast < unsigned > (pBlocker->nRequest) );
}
else {
pNtfy->completion ( guard );
}
}
else {
errlogPrintf ( "put notify completion with nill pNotify?\n" );
}
}
void dbPutNotifyBlocker::initiatePutNotify (
epicsGuard < epicsMutex > & guard, cacWriteNotify & notify,
struct dbChannel * dbch, unsigned type, unsigned long count,
const void * pValue )
{
guard. assertIdenticalMutex ( this->mutex );
epicsTime begin;
bool beginTimeInit = false;
while ( true ) {
if ( this->pNotify == 0 ) {
this->pNotify = & notify;
break;
}
if ( beginTimeInit ) {
if ( epicsTime::getCurrent () - begin > 30.0 ) {
throw cacChannel::requestTimedOut ();
}
}
else {
begin = epicsTime::getCurrent ();
beginTimeInit = true;
}
{
epicsGuardRelease < epicsMutex > autoRelease ( guard );
this->block.wait ( 1.0 );
}
}
if ( count > LONG_MAX ) {
throw cacChannel::outOfBounds();
}
if ( type > SHRT_MAX ) {
throw cacChannel::badType();
}
this->dbrType = type;
this->nRequest = static_cast < unsigned > ( count );
this->pn.requestType = putProcessRequest;
this->pn.chan = dbch;
this->pn.putCallback = putNotifyPut;
this->pn.doneCallback = putNotifyCompletion;
this->pn.usrPvt = this;
unsigned long size = dbr_size_n ( type, count );
this->expandValueBuf ( guard, size );
memcpy ( this->pbuffer, pValue, size );
{
epicsGuardRelease < epicsMutex > autoRelease ( guard );
::dbProcessNotify ( &this->pn );
}
}
void dbPutNotifyBlocker::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void dbPutNotifyBlocker::show (
epicsGuard < epicsMutex > &, unsigned level ) const
{
printf ( "put notify blocker at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
this->block.show ( level - 1u );
}
}
dbSubscriptionIO * dbPutNotifyBlocker::isSubscription ()
{
return 0;
}
void * dbPutNotifyBlocker::operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
void dbPutNotifyBlocker::operator delete ( void *pCadaver,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
void dbPutNotifyBlocker::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}
@@ -0,0 +1,85 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef dbPutNotifyBlockerh
#define dbPutNotifyBlockerh
#ifdef epicsExportSharedSymbols
#define dbPutNotifyBlockerh_restore_epicsExportSharedSymbols
#undef epicsExportSharedSymbols
#endif
#include "tsFreeList.h"
#include "compilerDependencies.h"
#ifdef dbPutNotifyBlockerh_restore_epicsExportSharedSymbols
#define epicsExportSharedSymbols
#endif
class dbPutNotifyBlocker : public dbBaseIO {
public:
dbPutNotifyBlocker ( epicsMutex & );
void destructor ( CallbackGuard &, epicsGuard < epicsMutex > & );
void initiatePutNotify ( epicsGuard < epicsMutex > &,
cacWriteNotify &, struct dbChannel *,
unsigned type, unsigned long count, const void * pValue );
void cancel ( CallbackGuard &, epicsGuard < epicsMutex > & );
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
void show ( unsigned level ) const;
void * operator new ( size_t size,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & );
epicsPlacementDeleteOperator (( void *,
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & ))
private:
processNotify pn;
//
// Include a union of all scalar types
// including fixed length strings so
// that in many cases we can avoid
// allocating another buffer
//
union {
dbr_string_t strval;
dbr_short_t shrtval;
dbr_short_t intval;
dbr_float_t fltval;
dbr_enum_t enmval;
dbr_char_t charval;
dbr_long_t longval;
dbr_double_t doubleval;
} dbrScalarValue;
epicsEvent block;
epicsMutex & mutex;
cacWriteNotify * pNotify;
unsigned long maxValueSize;
// arguments for db_put_field
void *pbuffer;
long nRequest;
short dbrType;
// end arguments for db_put_field
dbSubscriptionIO * isSubscription ();
void expandValueBuf (
epicsGuard < epicsMutex > &, unsigned long newSize );
friend void putNotifyCompletion ( processNotify * ppn );
friend int putNotifyPut ( processNotify *ppn, notifyPutType type );
dbPutNotifyBlocker ( const dbPutNotifyBlocker & );
dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & );
virtual ~dbPutNotifyBlocker ();
void operator delete ( void * );
};
#endif // ifndef dbPutNotifyBlockerh
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Marty Kraimer
* Date: 07-17-91
*/
#ifndef INCdbScanH
#define INCdbScanH
#include <limits.h>
#include "menuScan.h"
#include "shareLib.h"
#include "compilerDependencies.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SCAN_PASSIVE menuScanPassive
#define SCAN_EVENT menuScanEvent
#define SCAN_IO_EVENT menuScanI_O_Intr
#define SCAN_1ST_PERIODIC (menuScanI_O_Intr + 1)
#define MAX_PHASE SHRT_MAX
#define MIN_PHASE SHRT_MIN
/*definitions for I/O Interrupt Scanning */
struct ioscan_head;
typedef struct ioscan_head *IOSCANPVT;
typedef struct event_list *EVENTPVT;
struct dbCommon;
typedef void (*io_scan_complete)(void *usr, IOSCANPVT, int prio);
typedef void (*once_complete)(void *usr, struct dbCommon*);
epicsShareFunc long scanInit(void);
epicsShareFunc void scanRun(void);
epicsShareFunc void scanPause(void);
epicsShareFunc void scanStop(void);
epicsShareFunc void scanCleanup(void);
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
epicsShareFunc void postEvent(EVENTPVT epvt);
epicsShareFunc void post_event(int event) EPICS_DEPRECATED;
epicsShareFunc void scanAdd(struct dbCommon *);
epicsShareFunc void scanDelete(struct dbCommon *);
epicsShareFunc double scanPeriod(int scan);
epicsShareFunc int scanOnce(struct dbCommon *);
epicsShareFunc int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
epicsShareFunc int scanOnceSetQueueSize(int size);
/*print periodic lists*/
epicsShareFunc int scanppl(double rate);
/*print event lists*/
epicsShareFunc int scanpel(const char *event_name);
/*print io_event list*/
epicsShareFunc int scanpiol(void);
epicsShareFunc void scanIoInit(IOSCANPVT *ppios);
epicsShareFunc unsigned int scanIoRequest(IOSCANPVT pios);
epicsShareFunc unsigned int scanIoImmediate(IOSCANPVT pios, int prio);
epicsShareFunc void scanIoSetComplete(IOSCANPVT, io_scan_complete, void *usr);
#ifdef __cplusplus
}
#endif
#endif
+140
View File
@@ -0,0 +1,140 @@
/*************************************************************************\
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
*/
#include <stddef.h>
#include <string.h>
#include "ellLib.h"
#include "envDefs.h"
#include "epicsStdio.h"
#define epicsExportSharedSymbols
#include "dbServer.h"
static ELLLIST serverList = ELLLIST_INIT;
static enum { registering, initialized, running, paused, stopped }
state = registering;
static char *stateNames[] = {
"registering", "initialized", "running", "paused", "stopped"
};
int dbRegisterServer(dbServer *psrv)
{
const char * ignore = envGetConfigParamPtr(&EPICS_IOC_IGNORE_SERVERS);
if (!psrv || !psrv->name || state != registering)
return -1;
if (strchr(psrv->name, ' ')) {
fprintf(stderr, "dbRegisterServer: Bad server name '%s'\n",
psrv->name);
return -1;
}
if (ignore) {
size_t len = strlen(psrv->name);
const char *found;
while ((found = strstr(ignore, psrv->name))) {
/* Make sure the name isn't just a substring */
if ((found == ignore || (found > ignore && found[-1] == ' ')) &&
(found[len] == 0 || found[len] == ' ')) {
fprintf(stderr, "dbRegisterServer: Ignoring '%s', per environment\n",
psrv->name);
return 0;
}
/* It was, try again further down */
ignore = found + len;
}
}
if (ellNext(&psrv->node) || ellLast(&serverList) == &psrv->node) {
fprintf(stderr, "dbRegisterServer: '%s' registered twice?\n",
psrv->name);
return -1;
}
ellAdd(&serverList, &psrv->node);
return 0;
}
int dbUnregisterServer(dbServer *psrv)
{
if (state != registering && state != stopped) {
fprintf(stderr, "dbUnregisterServer: Servers still active!\n");
return -1;
}
if (ellFind(&serverList, &psrv->node) < 0) {
fprintf(stderr, "dbUnregisterServer: '%s' not registered.\n",
psrv->name);
return -1;
}
if (state == stopped && psrv->stop == NULL) {
fprintf(stderr, "dbUnregisterServer: '%s' has no stop() method.\n",
psrv->name);
return -1;
}
ellDelete(&serverList, &psrv->node);
return 0;
}
void dbsr(unsigned level)
{
dbServer *psrv = (dbServer *)ellFirst(&serverList);
if (!psrv) {
printf("No server layers registered with IOC\n");
return;
}
printf("Server state: %s\n", stateNames[state]);
while (psrv) {
printf("Server '%s'\n", psrv->name);
if (state == running && psrv->report)
psrv->report(level);
psrv = (dbServer *)ellNext(&psrv->node);
}
}
int dbServerClient(char *pBuf, size_t bufSize)
{
dbServer *psrv = (dbServer *)ellFirst(&serverList);
if (state != running)
return -1;
while (psrv) {
if (psrv->client &&
psrv->client(pBuf, bufSize) == 0)
return 0;
psrv = (dbServer *)ellNext(&psrv->node);
}
return -1;
}
#define STARTSTOP(routine, method, newState) \
void routine(void) \
{ \
dbServer *psrv = (dbServer *)ellFirst(&serverList); \
\
while (psrv) { \
if (psrv->method) \
psrv->method(); \
psrv = (dbServer *)ellNext(&psrv->node); \
} \
state = newState; \
}
STARTSTOP(dbInitServers, init, initialized)
STARTSTOP(dbRunServers, run, running)
STARTSTOP(dbPauseServers, pause, paused)
STARTSTOP(dbStopServers, stop, stopped)
+175
View File
@@ -0,0 +1,175 @@
/*************************************************************************\
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/**
* @file dbServer.h
* @author Andrew Johnson <anj@aps.anl.gov>
*
* @brief The IOC's interface to the server layers that publish its PVs.
*
* All server layers which publish IOC record data should initialize a
* dbServer structure and register it with the IOC. The methods that
* the dbServer interface provides allow the IOC to start, pause and stop
* the servers together, and to provide status and debugging information
* to the IOC user/developer through a common set of commands.
*
* @todo No API is provided yet for calling stats() methods.
* Nothing in the IOC calls dbStopServers(), not sure where it should go.
*/
#ifndef INC_dbServer_H
#define INC_dbServer_H
#include <stddef.h>
#include "ellLib.h"
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Server information structure.
*
* Every server layer should initialize and register an instance of this
* structure with the IOC by passing it to the dbRegisterServer() routine.
*
* All methods in this struct are optional; use @c NULL if a server is
* unable to support a particular operation (or if it hasn't been
* implemented yet).
*/
typedef struct dbServer {
/** @brief Linked list node; initialize to @c ELLNODE_INIT */
ELLNODE node;
/** @brief A short server identifier; printable, with no spaces */
const char *name;
/** @brief Print level-dependent status report to stdout.
*
* @param level Interest level, specifies how much detail to print.
*/
void (* report) (unsigned level);
/** @brief Get number of channels and clients currently connected.
*
* @param channels NULL or pointer for returning channel count.
* @param clients NULL or pointer for returning client count.
*/
void (* stats) (unsigned *channels, unsigned *clients);
/** @brief Get identity of client initiating the calling thread.
*
* Must fill in the buffer with the client's identity when called from a
* thread that belongs to this server layer. For other threads, the
* method should do nothing, just return -1.
* @param pBuf Buffer for client identity string.
* @param bufSize Number of chars available in pBuf.
* @return -1 means calling thread is not owned by this server.
* 0 means the thread was recognized and pBuf has been filled in.
*/
int (* client) (char *pBuf, size_t bufSize);
/** @name Control Methods
* These control methods for the server will be called by routines
* related to iocInit for all registered servers in turn when the IOC
* is being initialized, run, paused and stopped respectively.
*
* @{
*/
/** @brief Server init method.
*
* Called for all registered servers by dbInitServers().
*/
void (* init) (void);
/** @brief Server run method.
*
* Called for all registered servers by dbRunServers().
*/
void (* run) (void);
/** @brief Server pause method.
*
* Called for all registered servers by dbPauseServers().
*/
void (* pause) (void);
/** @brief Server stop method.
*
* Called for all registered servers by dbStopServers().
*/
void (* stop) (void);
/** @}
*/
} dbServer;
/** @brief Register a server layer with the IOC
*
* This should only be called once for each server layer.
* @param psrv Server information structure for the server
*/
epicsShareFunc int dbRegisterServer(dbServer *psrv);
/** @brief Unregister a server layer
*
* This should only be called when the servers are inactive.
* @param psrv Server information structure for the server
*/
epicsShareFunc int dbUnregisterServer(dbServer *psrv);
/** @brief Print dbServer Reports.
*
* Calls the report methods of all registered servers.
* This routine is provided as an IOC Shell command.
* @param level Interest level, specifies how much detail to print.
*/
epicsShareFunc void dbsr(unsigned level);
/** @brief Query servers for client's identity.
*
* This routine is called by code that wants to identify who (or what)
* is responsible for the thread which is currently running. Setting
* the @c TPRO field of a record is one way to trigger this; the identity
* of the calling thread is printed along with the record name whenever
* the record is subsequently processed.
*/
epicsShareFunc int dbServerClient(char *pBuf, size_t bufSize);
/** @brief Initialize all registered servers.
*
* Calls all dbServer::init() methods.
*/
epicsShareFunc void dbInitServers(void);
/** @brief Run all registered servers.
*
* Calls all dbServer::run() methods.
*/
epicsShareFunc void dbRunServers(void);
/** @brief Pause all registered servers.
*
* Calls all dbServer::pause() methods.
*/
epicsShareFunc void dbPauseServers(void);
/** @brief Stop all registered servers.
*
* Calls all dbServer::stop() methods.
*/
epicsShareFunc void dbStopServers(void);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbServer_H */
+109
View File
@@ -0,0 +1,109 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
#include <string.h>
#include <stdlib.h>
#include "ellLib.h"
#include "epicsMutex.h"
#include "epicsString.h"
#include "iocsh.h"
#define epicsExportSharedSymbols
#include "dbDefs.h"
#include "dbState.h"
#include "dbStaticLib.h"
static ELLLIST states = ELLLIST_INIT;
typedef struct dbState {
ELLNODE node;
int status;
char *name;
epicsMutexId lock; /* FIXME: Use atomic operations instead */
} dbState;
dbStateId dbStateFind(const char *name)
{
ELLNODE *node;
dbStateId id;
for (node = ellFirst(&states); node; node = ellNext(node)) {
id = CONTAINER(node, dbState, node);
if (strcmp(id->name, name) == 0)
return id;
}
return NULL;
}
dbStateId dbStateCreate(const char *name)
{
dbStateId id;
if ((id = dbStateFind(name)))
return id;
id = callocMustSucceed(1, sizeof(dbState), "createDbState");
id->name = epicsStrDup(name);
id->lock = epicsMutexMustCreate();
ellAdd(&states, &id->node);
return id;
}
void dbStateSet(dbStateId id)
{
if (!id)
return;
epicsMutexMustLock(id->lock);
id->status = 1;
epicsMutexUnlock(id->lock);
}
void dbStateClear(dbStateId id)
{
if (!id)
return;
epicsMutexMustLock(id->lock);
id->status = 0;
epicsMutexUnlock(id->lock);
}
int dbStateGet(dbStateId id)
{
int status;
if (!id)
return 0;
epicsMutexMustLock(id->lock);
status = id->status;
epicsMutexUnlock(id->lock);
return status;
}
void dbStateShow(dbStateId id, unsigned int level)
{
if (level >=1)
printf("id %p '%s' : ", id, id->name);
printf("%s\n", dbStateGet(id) ? "TRUE" : "FALSE");
}
void dbStateShowAll(unsigned int level)
{
ELLNODE *node;
dbStateId id;
for (node = ellFirst(&states); node; node = ellNext(node)) {
id = CONTAINER(node, dbState, node);
dbStateShow(id, level+1);
}
}
+92
View File
@@ -0,0 +1,92 @@
/*************************************************************************\
* Copyright (c) 2010 Brookhaven National Laboratory.
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
* fuer Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Ralph Lange <Ralph.Lange@bessy.de>
*/
#ifndef INCdbStateH
#define INCdbStateH
#include "shareLib.h"
/** @file dbState.h
* @brief Generic IOC state facility
*
* This library provides a simple global flag facility that can be used to
* synchronize e.g. plugins with IOC-wide states, that may be derived from
* events (either soft events or hard events coming from specialized timing
* and event hardware).
*
* A subset of this API is provided as IOC Shell commands to allow
* command line debugging.
*
*/
typedef struct dbState *dbStateId;
/** @brief Create db state.
*
* Creates a new db state with the specified 'name', returning the new id.
* If state with that name already exists, the existing state's id is returned.
*
* <em>Also provided as an IOC Shell command.</em>
*
* @param name Db state name.
* @return Id of db state, NULL for failure.
*/
epicsShareFunc dbStateId dbStateCreate(const char *name);
/** @brief Find db state.
*
* @param name Db state name.
* @return Id of db state, NULL if not found.
*/
epicsShareFunc dbStateId dbStateFind(const char *name);
/** @brief Set db state to TRUE.
*
* <em>Also provided as an IOC Shell command.</em>
*
* @param id Db state id.
*/
epicsShareFunc void dbStateSet(dbStateId id);
/** @brief Set db state to FALSE.
*
* <em>Also provided as an IOC Shell command.</em>
*
* @param id Db state id.
*/
epicsShareFunc void dbStateClear(dbStateId id);
/** @brief Get db state.
*
* @param id Db state id.
* @return Current db state (0|1).
*/
epicsShareFunc int dbStateGet(dbStateId id);
/** @brief Print info about db state.
*
* <em>Also provided as an IOC Shell command.</em>
*
* @param id Db state id.
* @param level Interest level.
*/
epicsShareFunc void dbStateShow(dbStateId id, unsigned int level);
/** @brief Print info about all db states.
*
* <em>Also provided as an IOC Shell command.</em>
*
* @param level Interest level.
*/
epicsShareFunc void dbStateShowAll(unsigned int level);
#endif // INCdbStateH
@@ -0,0 +1,154 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <string>
#include <stdexcept>
#include <limits.h>
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "tsFreeList.h"
#include "db_access.h" // need to eliminate this
#include "cadef.h" // this can be eliminated when the callbacks use the new interface
#include "errlog.h"
#define epicsExportSharedSymbols
#include "dbCAC.h"
#include "dbChannelIO.h"
#include "db_access_routines.h"
dbSubscriptionIO::dbSubscriptionIO (
epicsGuard < epicsMutex > & guard, epicsMutex & mutexIn,
dbContext &, dbChannelIO & chanIO,
dbChannel * dbch, cacStateNotify & notifyIn, unsigned typeIn,
unsigned long countIn, unsigned maskIn, dbEventCtx ctx ) :
mutex ( mutexIn ), count ( countIn ), notify ( notifyIn ),
chan ( chanIO ), es ( 0 ), type ( typeIn ), id ( 0u )
{
guard.assertIdenticalMutex ( this->mutex );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
this->es = db_add_event ( ctx, dbch,
dbSubscriptionEventCallback, (void *) this, maskIn );
if ( this->es == 0 ) {
throw std::bad_alloc();
}
db_post_single_event ( this->es );
db_event_enable ( this->es );
}
}
dbSubscriptionIO::~dbSubscriptionIO ()
{
}
void dbSubscriptionIO::destructor ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->~dbSubscriptionIO ();
}
void dbSubscriptionIO::unsubscribe ( CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->es ) {
dbEventSubscription tmp = this->es;
this->es = 0;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
db_cancel_event ( tmp );
}
}
}
void dbSubscriptionIO::channelDeleteException (
CallbackGuard &,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
this->notify.exception ( guard, ECA_CHANDESTROY,
this->chan.pName(guard), this->type, this->count );
}
void dbSubscriptionIO::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}
void * dbSubscriptionIO::operator new ( size_t size,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
return freeList.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
void dbSubscriptionIO::operator delete ( void * pCadaver,
tsFreeList < dbSubscriptionIO, 256, epicsMutexNOOP > & freeList )
{
freeList.release ( pCadaver );
}
#endif
extern "C" void dbSubscriptionEventCallback ( void *pPrivate, struct dbChannel * /* dbch */,
int /* eventsRemaining */, struct db_field_log *pfl )
{
dbSubscriptionIO * pIO = static_cast < dbSubscriptionIO * > ( pPrivate );
pIO->chan.callStateNotify ( pIO->type, pIO->count, pfl, pIO->notify );
}
void dbSubscriptionIO::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void dbSubscriptionIO::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->mutex );
printf ( "Data base subscription IO at %p\n",
static_cast <const void *> ( this ) );
if ( level > 0u ) {
short tmpType;
if ( this->type < SHRT_MAX ) {
tmpType = static_cast < short > ( this->type );
printf ( "\ttype %s, count %lu, channel at %p\n",
dbf_type_to_text ( tmpType ), this->count,
static_cast <void *> ( &this->chan ) );
}
else {
printf ( "strange type !, count %lu, channel at %p\n",
this->count, static_cast <void *> ( &this->chan ) );
}
}
}
dbSubscriptionIO * dbSubscriptionIO::isSubscription ()
{
return this;
}
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
/*************************************************************************\
* Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INC_dbTest_H
#define INC_dbTest_H
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
/*dbAddr info */
epicsShareFunc long dba(const char *pname);
/*list records*/
epicsShareFunc long dbl(
const char *precordTypename,const char *fields);
/*list number of records of each type*/
epicsShareFunc long dbnr(int verbose);
/* list aliases */
epicsShareFunc long dbla(const char *pmask);
/*list records with mask*/
epicsShareFunc long dbgrep(const char *pmask);
/*get field value*/
epicsShareFunc long dbgf(const char *pname);
/*put field value*/
epicsShareFunc long dbpf(const char *pname,const char *pvalue);
/*print record*/
epicsShareFunc long dbpr(const char *pname,int interest_level);
/*test record*/
epicsShareFunc long dbtr(const char *pname);
/*test get field*/
epicsShareFunc long dbtgf(const char *pname);
/*test put field*/
epicsShareFunc long dbtpf(const char *pname,const char *pvalue);
/*I/O report */
epicsShareFunc long dbior(
const char *pdrvName,int interest_level);
/*Hardware Configuration Report*/
epicsShareFunc int dbhcr(void);
#ifdef __cplusplus
}
#endif
#endif /* INC_dbTest_H */

Some files were not shown because too many files have changed in this diff Show More