Merge branch '7.0' into PSI-7.0

This commit is contained in:
2024-08-07 17:30:04 +02:00
72 changed files with 1441 additions and 1032 deletions

2
.ci

Submodule .ci updated: 130e88b709...0e93b70855

14
.gitattributes vendored
View File

@ -1,9 +1,11 @@
.ci/ export-ignore
.tools/ export-ignore
.github/ export-ignore
.appveyor/ export-ignore
.appveyor.yml export-ignore
README export-subst
.appveyor.yml export-ignore
.appveyor/ export-ignore
.ci/ export-ignore
.github/ export-ignore
.gitmodules export-ignore
.readthedocs.yml export-ignore
.tools/ export-ignore
README export-subst
#Which files need CRLF handling
# default to automatic

View File

@ -8,6 +8,6 @@ jobs:
editorconfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: EditorConfig-Action
uses: greut/eclint-action@v0

View File

@ -237,10 +237,10 @@ jobs:
matrix:
# Job names also name artifacts, character limitations apply
include:
- name: "CentOS-7"
image: centos:7
cmp: gcc
configuration: default
#- name: "CentOS-7"
# image: centos:7
# cmp: gcc
# configuration: default
- name: "Fedora-33"
image: fedora:33
@ -284,6 +284,10 @@ jobs:
submodules: true
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@master
if: matrix.image!='centos:7'
- name: Automatic core dumper analysis
uses: mdavidsaver/ci-core-dumper@node16
if: matrix.image=='centos:7'
- name: Prepare and compile dependencies
run: python .ci/cue.py prepare
- name: Build main module

View File

@ -136,19 +136,20 @@ sed -i -e 's|^\./||' "$TDIR"/list.1
# Exclude files
sed \
-e '/\/\.ci\//d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.appveyor\//d' \
-e '/\/\.ci-local\//d' \
-e '/\/\.tools\//d' \
-e '/\/jenkins\//d' \
-e '/\/\.ci\//d' \
-e '/\/\.cproject$/d' \
-e '/\/\.github\//d' \
-e '/\/\.gitmodules$/d' \
-e '/\/\.hgtags$/d' \
-e '/\/\.cproject$/d' \
-e '/\/\.project$/d' \
-e '/\/\.lgtm\.yml$/d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.project$/d' \
-e '/\/\.readthedocs\.yml$/d' \
-e '/\/\.tools\//d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/jenkins\//d' \
"$TDIR"/list.1 > "$TDIR"/list.2
if ! diff -U 0 "$TDIR"/list.1 "$TDIR"/list.2

View File

@ -27,16 +27,16 @@ RANLIB = $(GNU_BIN)/$(CMPLR_PREFIX)ranlib$(CMPLR_SUFFIX)
ASAN_FLAGS_YES = -fsanitize=address
ASAN_LDFLAGS_YES = $(ASAN_FLAGS_YES)
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
PROF_CFLAGS_YES = -p
GPROF_CFLAGS_YES = -pg
CODE_CFLAGS = $(PROF_CFLAGS_$(PROFILE)) $(GPROF_CFLAGS_$(GPROF))
CODE_CFLAGS += $(ASAN_FLAGS_$(ENABLE_ASAN))
WARN_CFLAGS_YES = -Wall -Werror-implicit-function-declaration
WARN_CFLAGS_NO = -w
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES = -O3 -g
OPT_CFLAGS_NO = -g

View File

@ -52,7 +52,7 @@ EPICS_MODIFICATION = 8
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included in the official EPICS version number if zero
EPICS_PATCH_LEVEL = 1
EPICS_PATCH_LEVEL = 2
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)

View File

@ -2,7 +2,7 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 14
EPICS_CA_MAINTENANCE_VERSION = 4
EPICS_CA_MAINTENANCE_VERSION = 5
# Development flag, set to zero for release versions

View File

@ -2,7 +2,7 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 23
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions

View File

@ -2,7 +2,7 @@
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 23
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
EPICS_LIBCOM_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions

View File

@ -34,5 +34,9 @@ CFG += TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A)
include $(TOP)/configure/RULES
ifeq ($(GNU),YES)
# Pass compiler flags to preprocessor to enable _FORTIFY_SOURCE
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): CPPFLAGS += $(CFLAGS)
endif
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): toolchain.c
$(PREPROCESS.cpp)

View File

@ -42,12 +42,6 @@ ARCH_DEP_LDFLAGS += $(ARCH_DEP_FLAGS)
OP_SYS_CFLAGS += -isysroot $(SDK_DIR)
OP_SYS_LDFLAGS += -isysroot $(SDK_DIR)
#--------------------------------------------------
# Always compile in debugging symbol table information
#
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
#-------------------------------------------------------
# Compiler definitions:

View File

@ -39,12 +39,6 @@ OP_SYS_CFLAGS += -fno-common
#
OP_SYS_CPPFLAGS += -Ddarwin
#
# Always compile in debugging symbol table information
#
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
#
# Libraries for command-line editing.
#

View File

@ -6,11 +6,3 @@
# GNU_DIR used when COMMANDLINE_LIBRARY is READLINE
#GNU_DIR=C:/cygwin
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@ -3,10 +3,3 @@
# Site specific definitions for native linux-aarch64 builds
#-------------------------------------------------------
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@ -47,3 +47,8 @@ COMMANDLINE_LIBRARY ?= EPICS
#else
COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS))
#endif
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2
OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
#endif

View File

@ -20,9 +20,59 @@ should also be read to understand what has changed since earlier releases:
**This version of EPICS has not been released yet.**
## Changes made on the 7.0 branch since 7.0.8
## Changes made on the 7.0 branch since 7.0.8.1
-----
## EPICS Release 7.0.8.1
### Limit to `_FORTIFY_SOURCE=2`
GCC versions 12 and beyond and glibc have added some aggressive runtime
checks for buffer overflows in libc functions at runtime, and the
[Ubuntu 2024.04](https://wiki.ubuntu.com/ToolChain/CompilerFlags) release
increased their default gcc fortification level from 2 to 3.
This has started causing EPICS Base builds to fail on that version, and
other OS releases may make that configuration change with similar results.
This release detects a compiler configured with `_FORTIFY_SOURCE=3` and
overrides it to 2.
Later releases of Base will adjust the code, providing information to the
compiler to avoid triggering these incorrect protections.
### Fix issue with compress record
In Base 7.0.8, an update to the compress record was added to allow for certain
algorithms to use partially filled buffers in their computations. Unfortunately,
this broke the behaviour of the records in certain cases. This has been fixed.
### Various minor changes
These included fixing minor memory leaks and documentation corrections. The
`SIZV` field of lsi, lso and printf record VAL fields now can't exceed 32767
characters, to match an internal limit.
### `epicsSocketAccept()` now returns `SOCKET`, not `int`
This might have some effect on downstream modules still using `int`, but the
OS-specific osdSock.h headers which osiSock.h includes have all declared
`SOCKET` (in most casese as a typedef for `int`) for many releases.
This change removes a compiler warning on WIN32.
Further details and the discussion about this change can be found
[here](https://github.com/epics-base/epics-base/pull/458).
### `dbLoadRecords` allows macros with default values
Previously the parser assumed that files containing macro substitutions were
bad if no macro definitions were provided; that assumption was made incorrect
once macro substitutions were allowed to provide a default value.
### Hostname length limit in CA removed
Before this release, the CA client library only handled hostnames in address
list environment variables up to 255 characters long.
This limit has been removed.
-----
## EPICS Release 7.0.8

View File

@ -179,14 +179,10 @@ everything that has to be done since it's so easy to miss steps.</p>
<li><tt>git grep UNRELEASED</tt> and insert the module version to any
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
Commit (don't push yet).</li>
<li>Check that the module's Release Notes have been updated to cover
all changes; add items as necessary, and set the module version
number and release date if appropriate. Convert to HTML and view in
a browser to check the formatting:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
number and release date if appropriate.
Commit these changes (don't push).</li>
<li>Edit the module's release version file
@ -194,14 +190,37 @@ everything that has to be done since it's so easy to miss steps.</p>
<tt>Doxyfile</tt>s in the top-level and/or documentation
directories. In these, set <tt>DEVELOPMENT_FLAG</tt> to 0 and remove
<tt>-dev</tt> from the <tt>PROJECT_NUMBER</tt> string. Commit these
changes (don't push).</li>
changes (don't push):
<blockquote><tt>
git ci -m 'Final commit for &lt;module-version&gt;'
</tt></blockquote>
</li>
<li>Tag the module:
<blockquote><tt>
git tag -m 'ANJ: Tag for EPICS 7.0.8' &lt;module-version&gt;
git tag -m 'ANJ: Tag for EPICS 7.0.8.2' &lt;module-version&gt;
</tt></blockquote>
</li>
<li>Generate documentation or Release Notes using one of these:
<ul>
<li>For older modules with a RELEASE_NOTES.md file convert it to
HTML and view in a browser to check the formatting as follows:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
<li>For newer modules with release_notes.dox file, generate the
new github-pages website as follows:
<blockquote><tt>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
make commit
git push --force upstream gh-pages
</tt></blockquote>
<i>Q: Delay this <tt>git push</tt> until later?</i></li>
</ul></li>
<li>Update the git submodule on the Base-7.0 branch to the
newly-tagged version, check the module's status matches the tag:
<blockquote><tt>
@ -269,7 +288,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for release' R7.0.8
git tag -m 'ANJ: Tagged for release' R7.0.8.2
</tt></blockquote>
<p>Don't push to GitHub yet.</p>
</td>
@ -303,12 +322,12 @@ everything that has to be done since it's so easy to miss steps.</p>
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.0<br />
./.tools/make-tar.sh R7.0.8 ../base-7.0.8.tar.gz base-7.0.8/
./.tools/make-tar.sh R7.0.8.2 ../base-7.0.8.2.tar.gz base-7.0.8.2/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
cd ..<br />
gpg --armor --sign --detach-sig base-7.0.8.tar.gz
gpg --armor --sign --detach-sig base-7.0.8.2.tar.gz
</tt></blockquote>
</td>
</tr>
@ -374,7 +393,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
epics-controls web-server.
<blockquote><tt>
scp base-7.0.8.tar.gz base-7.0.8.tar.gz.asc epics-controls:download/base<br />
scp base-7.0.8.2.tar.gz base-7.0.8.2.tar.gz.asc epics-controls:download/base<br />
</tt></blockquote>
</td>
</tr>
@ -397,8 +416,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<td><input type="checkbox"></td>
<td>Release Manager</td>
<td>Go to the GitHub
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8">
Create release from tag R7.0.8</a> page.
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8.2">
Create release from tag R7.0.8.2</a> page.
Upload the tar file and its <tt>.asc</tt> signature file to the new
GitHub release page.</td>
</tr>

View File

@ -118,7 +118,6 @@ EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)
SRC_DIRS += $(CURDIR)/test
PROD_HOST += ca_test
ca_test_SRCS = ca_test_main.c ca_test.c
ca_test_LIBS = ca Com
ca_test_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
OBJS_vxWorks += ca_test

View File

@ -23,4 +23,4 @@ dbCore_SRCS += asIocRegister.c
PROD_HOST += ascheck
ascheck_SRCS = ascheck.c
ascheck_LIBS = dbCore ca Com
ascheck_LIBS = dbCore ca

View File

@ -225,6 +225,11 @@ static void asCaTask(void)
if(asCaDebug) printf("asCaTask has cleared all channels\n");
epicsEventSignal(asCaTaskWait);
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
taskwdRemove(0);
}
void asCaStart(void)

View File

@ -112,7 +112,7 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func)
long dbPutSpecial(DBADDR *paddr,int pass)
{
long int (*pspecial)()=NULL;
long int (*pspecial)(struct dbAddr *, int)=NULL;
rset *prset;
dbCommon *precord = paddr->precord;
long status=0;

View File

@ -225,6 +225,7 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
assert(plink->type==CA_LINK);
pca = (caLink *)plink->value.pv_link.pvt;
caLinkInc(pca);
epicsMutexMustLock(pca->lock);
assert(!pca->monitor && !pca->connect && !pca->userPvt);
@ -239,6 +240,8 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
dbScanUnlock(plink->precord);
epicsEventMustWait(evt);
/* ensure worker has finished executing */
dbCaSync();
dbScanLock(plink->precord);
epicsMutexMustLock(pca->lock);
@ -250,6 +253,7 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event
epicsEventDestroy(evt);
epicsMutexUnlock(pca->lock);
caLinkDec(pca);
dbScanUnlock(plink->precord);
}
@ -287,16 +291,15 @@ void dbCaSync(void)
epicsEventMustWait(wake);
/* Worker holds workListLock when calling epicsEventMustTrigger()
* we cycle through workListLock to ensure worker call to
* we hold workListLock to ensure worker call to
* epicsEventMustTrigger() returns before we destroy the event.
*/
epicsMutexMustLock(workListLock);
epicsMutexUnlock(workListLock);
assert(templink.refcount==1);
epicsMutexDestroy(templink.lock);
epicsEventDestroy(wake);
epicsMutexUnlock(workListLock);
}
void dbCaCallbackProcess(void *userPvt)

View File

@ -7,20 +7,38 @@
* EPICS Base is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbConvertFast.h */
/** @file dbConvertFast.h
* @brief Data conversion for scalar values
*
* The typedef FASTCONVERTFUNC is defined in link.h as:
* @code
* long convert(const void *from, void *to, const struct dbAddr *paddr);
* @endcode
*
* The arrays declared here provide pointers to the fast conversion
* routine where the first array index is the data type for the first
* "from" pointer arg, and the second array index is the data type for
* the second "to" pointer arg. The array index values are a subset of
* the DBF_ enum values defined in dbFldTypes.h
*/
#ifndef INCdbConvertFasth
#define INCdbConvertFasth
#include "dbFldTypes.h"
#include "dbCoreAPI.h"
#include "link.h"
#ifdef __cplusplus
extern "C" {
#endif
DBCORE_API extern long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])();
DBCORE_API extern long (*dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1])();
/** Function pointers for get conversions */
DBCORE_API extern const FASTCONVERTFUNC
dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1];
/** Function pointers for put conversions */
DBCORE_API extern const FASTCONVERTFUNC
dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1];
#ifdef __cplusplus
}

View File

@ -19,8 +19,6 @@
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
typedef long (*FASTCONVERT)();
typedef struct parseContext {
int depth;
short dbrType;
@ -42,7 +40,7 @@ static int dbcj_boolean(void *ctx, int val) {
static int dbcj_integer(void *ctx, long long num) {
parseContext *parser = (parseContext *) ctx;
epicsInt64 val64 = num;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType];
FASTCONVERTFUNC conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType];
if (parser->elems > 0) {
conv(&val64, parser->pdest, NULL);
@ -54,7 +52,7 @@ static int dbcj_integer(void *ctx, long long num) {
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
FASTCONVERTFUNC conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
if (parser->elems > 0) {
conv(&num, parser->pdest, NULL);

View File

@ -98,8 +98,8 @@ struct event_user {
unsigned char extra_labor; /* if set call extra labor func */
unsigned char flowCtrlMode; /* replace existing monitor */
unsigned char extraLaborBusy;
void (*init_func)();
epicsThreadId init_func_arg;
void (*init_func)(void *);
void *init_func_arg;
};
typedef struct {

File diff suppressed because it is too large Load Diff

View File

@ -133,7 +133,7 @@ void dbInitLink(struct link *plink, short dbfType)
plink->value.pv_link.pvlMask |= pvlOptFWD;
}
else {
errlogPrintf("Forward-link uses Channel Access "
errlogPrintf(ERL_WARNING ": Forward-link uses Channel Access "
"without pointing to PROC field\n"
" %s.%s => %s\n",
precord->name, dbLinkFieldName(plink),

View File

@ -307,7 +307,7 @@ typedef struct lset {
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pbuffer where the data is
* @param nRequest number of elements to send
* @returns status value
*/
@ -324,7 +324,7 @@ typedef struct lset {
*
* @param plink the link
* @param dbrType data type code
* @param pbuffer where to put the value
* @param pbuffer where the data is
* @param nRequest number of elements to send
* @returns status value
*/

View File

@ -918,7 +918,7 @@ long dblsr(char *recordname,int level)
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);
pdbAddr = &((dbChannel *)(plink->value.pv_link.pvt))->addr;
printf("\t%s",pdbFldDes->name);
if(pdbFldDes->field_type==DBF_INLINK) {
printf("\t INLINK");

View File

@ -155,7 +155,7 @@ void scanStop(void)
{
int i;
if (scanCtl == ctlExit) return;
if (scanCtl == ctlInit || scanCtl == ctlExit) return;
scanCtl = ctlExit;
interruptAccept = FALSE;
@ -264,7 +264,7 @@ void scanAdd(struct dbCommon *precord)
} else if (scan == menuScanI_O_Intr) {
ioscan_head *piosh = NULL;
int prio;
DEVSUPFUN get_ioint_info;
long (*get_ioint_info)(int, struct dbCommon *, IOSCANPVT*);
if (precord->dset == NULL){
recGblRecordError(-1, (void *)precord,
@ -332,7 +332,7 @@ void scanDelete(struct dbCommon *precord)
} else if (scan == menuScanI_O_Intr) {
ioscan_head *piosh = NULL;
int prio;
DEVSUPFUN get_ioint_info;
long (*get_ioint_info)(int, struct dbCommon *, IOSCANPVT*);
if (precord->dset==NULL) {
recGblRecordError(-1, (void *)precord,

View File

@ -680,7 +680,7 @@ long dbtpf(const char *pname, const char *pvalue)
long dbior(const char *pdrvName,int interest_level)
{
drvSup *pdrvSup;
struct drvet *pdrvet;
drvet *pdrvet;
dbRecordType *pdbRecordType;
if (!pdbbase) {

View File

@ -62,7 +62,7 @@ void recGblRecordError(long status, void *pdbc,
dbCommon *precord = pdbc;
char errMsg[256] = "";
if (status)
if ( status>0 )
errSymLookup(status, errMsg, sizeof(errMsg));
errlogPrintf("recGblRecordError: %s %s PV: %s\n",

View File

@ -11,6 +11,8 @@
SRC_DIRS += $(IOCDIR)/dbStatic
USR_CFLAGS += -DUSE_TYPED_DRVET
INC += dbBase.h
INC += dbFldTypes.h
INC += dbStaticLib.h

View File

@ -21,6 +21,7 @@
#include "dbDefs.h"
#include "recSup.h"
#include "devSup.h"
#include "drvSup.h"
typedef struct dbMenu {
ELLNODE node;
@ -33,7 +34,7 @@ typedef struct dbMenu {
typedef struct drvSup {
ELLNODE node;
char *name;
struct drvet *pdrvet;
drvet *pdrvet;
}drvSup;
typedef struct devSup {
@ -119,7 +120,7 @@ typedef struct dbRecordNode {
ELLLIST infoList; /*LIST head of info nodes*/
int flags;
/** Parse order of this record()
* @since UNRELEASED
* @since 7.0.8.1
*/
unsigned order;
struct dbRecordNode *aliasedRecnode; /* NULL unless flags|DBRN_FLAGS_ISALIAS */
@ -189,7 +190,7 @@ typedef struct dbBase {
short ignoreMissingMenus;
short loadCdefs;
/** Total number of records.
* @since UNRELEASED
* @since 7.0.8.1
*/
unsigned no_records;
}dbBase;

View File

@ -225,7 +225,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
char **macPairs;
if (ellCount(&tempList)) {
epicsPrintf("dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
}
if (getIocState() != iocVoid) {
@ -250,7 +250,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
if (substitutions == NULL)
substitutions = "";
if(macCreateHandle(&macHandle,NULL)) {
epicsPrintf("macCreateHandle error\n");
fprintf(stderr, ERL_ERROR ": macCreateHandle failed\n");
status = -1;
goto cleanup;
}
@ -294,7 +294,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
status = pvt_yy_parse();
if (ellCount(&tempList) && !yyAbort)
epicsPrintf("dbReadCOM: Parser stack dirty w/o error. %d\n", ellCount(&tempList));
fprintf(stderr, ERL_WARNING ": dbReadCOM: Parser stack dirty w/o error. %d\n", ellCount(&tempList));
while (ellCount(&tempList))
popFirstTemp(); /* Memory leak on parser failure */
@ -401,15 +401,15 @@ static void dbIncludePrint(void)
inputFile *pinputFile = pinputFileNow;
while (pinputFile) {
epicsPrintf(" in");
fprintf(stderr, " in");
if (pinputFile->path)
epicsPrintf(" path \"%s\" ",pinputFile->path);
fprintf(stderr, " path \"%s\" ",pinputFile->path);
if (pinputFile->filename) {
epicsPrintf(" file \"%s\"",pinputFile->filename);
fprintf(stderr, " file \"%s\"",pinputFile->filename);
} else {
epicsPrintf(" standard input");
fprintf(stderr, " standard input");
}
epicsPrintf(" line %d\n",pinputFile->line_num);
fprintf(stderr, " line %d\n",pinputFile->line_num);
pinputFile = (inputFile *)ellPrevious(&pinputFile->node);
}
return;
@ -434,7 +434,7 @@ static void dbIncludeNew(char *filename)
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp);
if (!fp) {
epicsPrintf("Can't open include file \"%s\"\n", filename);
fprintf(stderr, "Can't open include file \"%s\"\n", filename);
yyerror(NULL);
free((void *)pinputFile->filename);
free((void *)pinputFile);
@ -696,7 +696,7 @@ static void dbRecordtypeEmpty(void)
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
epicsPrintf("Declaration of recordtype(%s) preceeded full definition.\n",
fprintf(stderr, "Declaration of recordtype(%s) preceeded full definition.\n",
pdbRecordType->name);
yyerrorAbort(NULL);
}
@ -801,7 +801,7 @@ static void dbDevice(char *recordtype,char *linktype,
int i,link_type;
pgphentry = gphFind(savedPdbbase->pgpHash,recordtype,&savedPdbbase->recordTypeList);
if(!pgphentry) {
epicsPrintf("Record type \"%s\" not found for device \"%s\"\n",
fprintf(stderr, "Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
yyerror(NULL);
return;
@ -814,7 +814,7 @@ static void dbDevice(char *recordtype,char *linktype,
}
}
if(link_type==-1) {
epicsPrintf("Bad link type \"%s\" for device \"%s\"\n",
fprintf(stderr, "Bad link type \"%s\" for device \"%s\"\n",
linktype, choicestring);
yyerror(NULL);
return;
@ -1077,16 +1077,16 @@ int dbRecordNameValidate(const char *name)
if(i==0) {
/* first character restrictions */
if(c=='-' || c=='+' || c=='[' || c=='{') {
errlogPrintf("Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
fprintf(stderr, "Warning: Record/Alias name '%s' should not begin with '%c'\n", name, c);
}
}
/* any character restrictions */
if(c < ' ') {
errlogPrintf("Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
fprintf(stderr, "Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
name, c);
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
epicsPrintf(ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
fprintf(stderr, ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n",
c, name);
yyerrorAbort(NULL);
return 1;
@ -1113,7 +1113,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbFindRecord(pdbentry, name);
if (status == 0)
return; /* done */
epicsPrintf(ERL_ERROR ": Record \"%s\" not found\n", name);
fprintf(stderr, ERL_ERROR ": Record \"%s\" not found\n", name);
yyerror(NULL);
duplicate = TRUE;
return;
@ -1121,7 +1121,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbFindRecordType(pdbentry, recordType);
if (status) {
epicsPrintf("Record \"%s\" is of unknown type \"%s\"\n",
fprintf(stderr, "Record \"%s\" is of unknown type \"%s\"\n",
name, recordType);
yyerrorAbort(NULL);
return;
@ -1132,14 +1132,14 @@ static void dbRecordHead(char *recordType, char *name, int visible)
status = dbCreateRecord(pdbentry,name);
if (status == S_dbLib_recExists) {
if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) {
epicsPrintf(ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
fprintf(stderr, ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type "
"\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType);
yyerror(NULL);
duplicate = TRUE;
return;
}
else if (dbRecordsOnceOnly) {
epicsPrintf(ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
fprintf(stderr, ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n"
"Used record type \"*\" to append.\n",
name);
yyerror(NULL);
@ -1147,7 +1147,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
}
}
else if (status) {
epicsPrintf("Can't create record \"%s\" of type \"%s\"\n",
fprintf(stderr, "Can't create record \"%s\" of type \"%s\"\n",
name, recordType);
yyerrorAbort(NULL);
}
@ -1167,7 +1167,7 @@ static void dbRecordField(char *name,char *value)
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
if (status) {
epicsPrintf("%s Record \"%s\" does not have a field \"%s\"\n",
fprintf(stderr, "%s Record \"%s\" does not have a field \"%s\"\n",
dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name);
if(dbGetRecordName(pdbentry)) {
DBENTRY temp;
@ -1183,17 +1183,17 @@ static void dbRecordField(char *name,char *value)
}
dbFinishEntry(&temp);
if(bestSim>0.0) {
epicsPrintf(" Did you mean \"%s\"?", bestFld->name);
fprintf(stderr, " Did you mean \"%s\"?", bestFld->name);
if(bestFld->prompt)
epicsPrintf(" (%s)", bestFld->prompt);
epicsPrintf("\n");
fprintf(stderr, " (%s)", bestFld->prompt);
fprintf(stderr, "\n");
}
}
yyerror(NULL);
return;
}
if (pdbentry->indfield == 0) {
epicsPrintf("Can't set \"NAME\" field of record \"%s\"\n",
fprintf(stderr, "Can't set \"NAME\" field of record \"%s\"\n",
dbGetRecordName(pdbentry));
yyerror(NULL);
return;
@ -1211,7 +1211,7 @@ static void dbRecordField(char *name,char *value)
char msg[128];
errSymLookup(status, msg, sizeof(msg));
epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s : %s\n",
fprintf(stderr, "Can't set \"%s.%s\" to \"%s\" %s : %s\n",
dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg);
dbPutStringSuggest(pdbentry, value);
yyerror(NULL);
@ -1242,7 +1242,7 @@ static void dbRecordInfo(char *name, char *value)
status = dbPutInfo(pdbentry,name,value);
if (status) {
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
fprintf(stderr, "Can't set \"%s\" info \"%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
yyerror(NULL);
return;
@ -1263,7 +1263,7 @@ static void dbRecordAlias(char *name)
pdbentry = ptempListNode->item;
status = dbCreateAlias(pdbentry, name);
if (status) {
epicsPrintf("Can't create alias \"%s\" for \"%s\"\n",
fprintf(stderr, "Can't create alias \"%s\" for \"%s\"\n",
name, dbGetRecordName(pdbentry));
yyerror(NULL);
return;
@ -1280,12 +1280,12 @@ static void dbAlias(char *name, char *alias)
dbInitEntry(savedPdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
fprintf(stderr, "Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);
yyerror(NULL);
}
else if (dbCreateAlias(pdbEntry, alias)) {
epicsPrintf("Can't create alias \"%s\" referring to \"%s\"\n",
fprintf(stderr, "Can't create alias \"%s\" referring to \"%s\"\n",
alias, name);
yyerror(NULL);
}

View File

@ -8,7 +8,7 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
%{
static int yyerror();
static int yyerror(char *str);
static int yy_start;
static long pvt_yy_parse(void);
static int yyFailed = 0;
@ -370,11 +370,11 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); }
static int yyerror(char *str)
{
if (str)
epicsPrintf(ERL_ERROR ": %s\n", str);
fprintf(stderr, ERL_ERROR ": %s\n", str);
else
epicsPrintf(ERL_ERROR "");
fprintf(stderr, ERL_ERROR ": ");
if (!yyFailed) { /* Only print this stuff once */
epicsPrintf(" at or before '%s'", yytext);
fprintf(stderr, " at or before '%s'", yytext);
dbIncludePrint();
yyFailed = TRUE;
}

View File

@ -77,14 +77,14 @@ struct macro_link {
char *macroStr;
};
struct dbCommon;
typedef long (*LINKCVT)();
struct dbAddr;
typedef long (*FASTCONVERTFUNC)(const void *from, void *to, const struct dbAddr *paddr);
struct pv_link {
ELLNODE backlinknode;
char *pvname; /* pvname link points to */
void *pvt; /* CA or DB private */
LINKCVT getCvt; /* input conversion function */
FASTCONVERTFUNC getCvt; /* input conversion function */
short pvlMask; /* Options mask */
short lastGetdbrType; /* last dbrType for DB or CA get */
};
@ -188,8 +188,8 @@ union value {
struct vxiio vxiio; /* vxi io */
};
struct dbCommon;
struct lset;
struct link {
struct dbCommon *precord; /* Pointer to record owning link */
short type;

View File

@ -14,7 +14,6 @@ SRC_DIRS += $(IOCDIR)/dbtemplate
PROD_CMD += msi
msi_SRCS = msi.cpp
msi_LIBS += Com
HTMLS += msi.html
INC += dbLoadTemplate.h

View File

@ -114,7 +114,7 @@ int iocInit(void)
static int iocBuild_1(void)
{
if (iocState != iocVoid) {
errlogPrintf("iocBuild: IOC can only be initialized from uninitialized or stopped state\n");
errlogPrintf("iocBuild: " ERL_ERROR " IOC can only be initialized from uninitialized or stopped state\n");
return -1;
}
errlogInit(0);
@ -126,7 +126,7 @@ static int iocBuild_1(void)
errlogPrintf("Starting iocInit\n");
if (checkDatabase(pdbbase)) {
errlogPrintf("iocBuild: Aborting, bad database definition (DBD)!\n");
errlogPrintf("iocBuild: " ERL_ERROR " Aborting, bad database definition (DBD)!\n");
return -1;
}
epicsSignalInstallSigHupIgnore();
@ -237,7 +237,7 @@ int iocBuildIsolated(void)
int iocRun(void)
{
if (iocState != iocPaused && iocState != iocBuilt) {
errlogPrintf("iocRun: IOC not paused\n");
errlogPrintf("iocRun: " ERL_WARNING " IOC not paused\n");
return -1;
}
initHookAnnounce(initHookAtIocRun);
@ -268,7 +268,7 @@ int iocRun(void)
int iocPause(void)
{
if (iocState != iocRunning) {
errlogPrintf("iocPause: IOC not running\n");
errlogPrintf("iocPause: " ERL_WARNING " IOC not running\n");
return -1;
}
initHookAnnounce(initHookAtIocPause);
@ -306,59 +306,59 @@ static int checkDatabase(dbBase *pdbbase)
const dbMenu *pMenu;
if (!pdbbase) {
errlogPrintf("checkDatabase: No database definitions loaded.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " No database definitions loaded.\n");
return -1;
}
pMenu = dbFindMenu(pdbbase, "menuConvert");
if (!pMenu) {
errlogPrintf("checkDatabase: menuConvert not defined.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvert not defined.\n");
return -1;
}
if (pMenu->nChoice <= menuConvertLINEAR) {
errlogPrintf("checkDatabase: menuConvert has too few choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvert has too few choices.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertNO_CONVERSION],
"menuConvertNO_CONVERSION")) {
errlogPrintf("checkDatabase: menuConvertNO_CONVERSION doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertNO_CONVERSION doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertSLOPE], "menuConvertSLOPE")) {
errlogPrintf("checkDatabase: menuConvertSLOPE doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertSLOPE doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuConvertLINEAR], "menuConvertLINEAR")) {
errlogPrintf("checkDatabase: menuConvertLINEAR doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuConvertLINEAR doesn't match.\n");
return -1;
}
pMenu = dbFindMenu(pdbbase, "menuScan");
if (!pMenu) {
errlogPrintf("checkDatabase: menuScan not defined.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan not defined.\n");
return -1;
}
if (pMenu->nChoice <= menuScanI_O_Intr) {
errlogPrintf("checkDatabase: menuScan has too few choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan has too few choices.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanPassive],
"menuScanPassive")) {
errlogPrintf("checkDatabase: menuScanPassive doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanPassive doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanEvent],
"menuScanEvent")) {
errlogPrintf("checkDatabase: menuScanEvent doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanEvent doesn't match.\n");
return -1;
}
if (strcmp(pMenu->papChoiceName[menuScanI_O_Intr],
"menuScanI_O_Intr")) {
errlogPrintf("checkDatabase: menuScanI_O_Intr doesn't match.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScanI_O_Intr doesn't match.\n");
return -1;
}
if (pMenu->nChoice <= SCAN_1ST_PERIODIC) {
errlogPrintf("checkDatabase: menuScan has no periodic choices.\n");
errlogPrintf("checkDatabase: " ERL_ERROR " menuScan has no periodic choices.\n");
return -1;
}
@ -388,7 +388,7 @@ static void initDrvSup(void) /* Locate all driver support entry tables */
for (pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); pdrvSup;
pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
struct drvet *pdrvet = registryDriverSupportFind(pdrvSup->name);
drvet *pdrvet = registryDriverSupportFind(pdrvSup->name);
if (!pdrvet) {
errlogPrintf("iocInit: driver %s not found\n", pdrvSup->name);

View File

@ -32,11 +32,12 @@ namespace {
struct compareLoc {
bool operator()(const recordTypeLocation& lhs, const recordTypeLocation& rhs) const
{
if(lhs.prset<rhs.prset)
if (lhs.prset < rhs.prset)
return true;
else if(lhs.prset>rhs.prset)
if (lhs.prset > rhs.prset)
return false;
return lhs.sizeOffset<rhs.sizeOffset;
return reinterpret_cast<char *>(lhs.sizeOffset)
< reinterpret_cast<char *>(rhs.sizeOffset);
}
};

View File

@ -65,7 +65,7 @@ void registerDevices(DBBASE *pbase, int nDevices,
}
void registerDrivers(DBBASE *pbase, int nDrivers,
const char * const * driverSupportNames, struct drvet * const *drvsl)
const char * const * driverSupportNames, drvet * const *drvsl)
{
int i;
for (i = 0; i < nDrivers; i++) {

View File

@ -29,7 +29,7 @@ DBCORE_API void registerDevices(
const char * const *deviceSupportNames, const dset * const *devsl);
DBCORE_API void registerDrivers(
DBBASE *pbase, int nDrivers,
const char * const *driverSupportNames, struct drvet * const *drvsl);
const char * const *driverSupportNames, drvet * const *drvsl);
DBCORE_API void registerJLinks(
DBBASE *pbase, int nDrivers, jlif * const *jlifsl);

View File

@ -18,12 +18,12 @@ static void *registryID = "driver support";
DBCORE_API int registryDriverSupportAdd(
const char *name, struct drvet *pdrvet)
const char *name, drvet *pdrvet)
{
return registryAdd(registryID, name, pdrvet);
}
DBCORE_API struct drvet * registryDriverSupportFind(
DBCORE_API drvet * registryDriverSupportFind(
const char *name)
{
return registryFind(registryID, name);

View File

@ -19,8 +19,8 @@ extern "C" {
#endif
DBCORE_API int registryDriverSupportAdd(
const char *name, struct drvet *pdrvet);
DBCORE_API struct drvet * registryDriverSupportFind(
const char *name, drvet *pdrvet);
DBCORE_API drvet * registryDriverSupportFind(
const char *name);
#ifdef __cplusplus

View File

@ -120,6 +120,11 @@ static void req_server (void *pParm)
}
}
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
taskwdRemove(0);
}
static
@ -585,8 +590,7 @@ void rsrv_init (void)
errlogPrintf ( "cas " ERL_WARNING ": reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
}
epicsSnprintf(buf, sizeof(buf)-1u, "%u", ca_server_port);
buf[sizeof(buf)-1u] = '\0';
epicsSnprintf(buf, sizeof(buf), "%u", ca_server_port);
epicsEnvSet("RSRV_SERVER_PORT", buf);
}
@ -748,6 +752,7 @@ void rsrv_init (void)
if(!havesometcp)
cantProceed("CAS: No TCP server started\n");
}
free(socks);
/* servers list is considered read-only from this point */

View File

@ -98,13 +98,10 @@ static void clean_addrq(struct client *client)
}
epicsMutexUnlock ( client->chanListLock );
# ifdef DEBUG
if(ndelete){
if (CASDEBUG>1 && ndelete){
epicsPrintf ("CAS: %d CA channels have expired after %f sec\n",
ndelete, maxdelay);
}
# endif
}
/*

View File

@ -129,7 +129,11 @@ void rsrv_online_notify_task(void *pParm)
}
}
/* ATM never reached, just a placeholder */
cantProceed("Unreachable. Perpetual thread.");
free(lastError);
taskwdRemove(0);
}

View File

@ -36,8 +36,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct calc_link {
jlink jlink; /* embedded object */
int nArgs;
@ -558,7 +556,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer,
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;
@ -638,7 +636,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType,
dbCommon *prec = plink->precord;
int i;
long status;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;

View File

@ -23,8 +23,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct const_link {
jlink jlink; /* embedded object */
int nElems;
@ -458,7 +456,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
short dbrSize;
char *pdest = pbuffer;
int nElems = clink->nElems;
FASTCONVERT conv;
FASTCONVERTFUNC conv;
long status;
if(INVALID_DB_REQ(dbrType))
@ -495,9 +493,11 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
}
else {
/* Long string conversion */
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq] = 0;
nElems = strlen(pbuffer) + 1;
if (*pnReq > 0) {
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq - 1] = 0;
nElems = strlen(pbuffer) + 1;
}
status = 0;
}
break;

View File

@ -34,8 +34,6 @@
#include "epicsExport.h"
typedef long (*FASTCONVERT)();
typedef struct state_link {
jlink jlink; /* embedded object */
char *name;
@ -143,7 +141,7 @@ static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer,
{
state_link *slink = CONTAINER(plink->value.json.jlink,
struct state_link, jlink);
FASTCONVERT conv;
FASTCONVERTFUNC conv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;

View File

@ -16,7 +16,7 @@ has a number of additional features:
=item *
It provides 20 different input and output fields which can hold array or
It provides 21 different input and output fields which can hold array or
scalar values.
The types and array capacities of these are user configurable, and they all
have an associated input or output link.

View File

@ -1160,7 +1160,7 @@ See next section.
=head2 C<special>
This is called id CALC or OCAL is changed. C<special> calls postfix.
This is called if CALC or OCAL is changed. C<special> calls postfix.
=head2 C<get_units>

View File

@ -149,13 +149,16 @@ static int compare(const void *arg1, const void *arg2)
else return 1;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
static int compress_array(compressRecord *prec,
double *psource, int no_elements)
{
epicsInt32 i,j;
epicsInt32 j;
epicsInt32 n, nnew;
epicsInt32 nsam = prec->nsam;
double value;
epicsUInt32 samples_written = 0;
double value = 0.0;
/* skip out of limit data */
if (prec->ilil < prec->ihil) {
@ -167,61 +170,54 @@ static int compress_array(compressRecord *prec,
}
if (prec->n <= 0)
prec->n = 1;
if (no_elements < prec->n && prec->pbuf != menuYesNoYES)
return 1; /*dont do anything*/
n = no_elements;
n = prec->n;
/* determine number of samples to take */
if (no_elements < nsam * n)
nnew = (no_elements / n);
else nnew = nsam;
nnew = min(no_elements, nsam * n);
/* compress according to specified algorithm */
switch (prec->alg){
case compressALG_N_to_1_Low_Value:
/* compress N to 1 keeping the lowest value */
for (i = 0; i < nnew; i++) {
while (nnew > 0)
{
if (nnew < n && prec->pbuf != menuYesNoYES)
break;
n = min(n, nnew);
switch (prec->alg)
{
case compressALG_N_to_1_Low_Value:
value = *psource++;
for (j = 1; j < n; j++, psource++) {
for (j = 1; j < n; j++, psource++)
{
if (value > *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_High_Value:
/* compress N to 1 keeping the highest value */
for (i = 0; i < nnew; i++){
break;
case compressALG_N_to_1_High_Value:
value = *psource++;
for (j = 1; j < n; j++, psource++) {
for (j = 1; j < n; j++, psource++)
{
if (value < *psource)
value = *psource;
}
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Average:
/* compress N to 1 keeping the average value */
for (i = 0; i < nnew; i++) {
value = 0;
for (j = 0; j < n; j++, psource++)
break;
case compressALG_N_to_1_Average:
value = *psource++;
for (j = 1; j < n; j++, psource++)
{
value += *psource;
value /= n;
put_value(prec, &value, 1);
}
break;
case compressALG_N_to_1_Median:
/* compress N to 1 keeping the median value */
/* note: sorts source array (OK; it's a work pointer) */
for (i = 0; i < nnew; i++, psource += nnew) {
}
value = value / n;
break;
case compressALG_N_to_1_Median:
/* note: sorts source array (OK; it's a work pointer) */
qsort(psource, n, sizeof(double), compare);
value = psource[n / 2];
put_value(prec, &value, 1);
psource += n;
break;
}
break;
nnew -= n;
put_value(prec, &value, 1);
samples_written++;
}
return 0;
return (samples_written == 0);
}
static int array_average(compressRecord *prec,

View File

@ -91,10 +91,10 @@ The BPTR field contains a pointer to the unsigned long array of frequency
values. The VAL field references this array as well. However, the BPTR field is
not accessible at run-time.
The MCNT field keeps counts the number of signal counts since the last monitor
The MCNT field keeps the number of signal counts since the last monitor
was invoked.
The collections controls field (CMD) is a menu field with five choices:
The collections controls field (CMD) is a menu field with four choices:
=menu histogramCMD
@ -110,8 +110,6 @@ array. Unlike C<Read>, it doesn't clear the array first.
The C<Stop> command disables the reading of signal values into the array.
The C<Setup> command waits until the C<start> or C<read> command has been issued
to start counting.
The CSTA or collections status field implements the CMD field choices by
enabling or disabling the reading of values into the histogram array. While

View File

@ -49,6 +49,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "lsi::init_record");

View File

@ -9,7 +9,7 @@
=title Long String Input Record (lsi)
The long string input record is used to retrieve an arbitrary ASCII string with
a maximum length of 65535 characters.
a maximum length of 32767 characters.
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
@ -36,7 +36,7 @@ from. It can be a database or channel access link, or a constant. If constant,
the VAL field is initialized with the constant and can be changed via dbPuts.
Otherwise, the string is read from the specified location each time the record
is processed and placed in the VAL field. The maximum number of characters in
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
VAL is given by SIZV, and cannot be larger than 32767. In addition, the
appropriate device support module must be entered into the DTYP field.
=fields VAL, OVAL, SIZV, INP, DTYP

View File

@ -53,6 +53,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "lso::init_record");

View File

@ -9,7 +9,7 @@
=title Long String Output Record (lso)
The long string output record is used to write an arbitrary ASCII string with a
maximum length of 65535 characters.
maximum length of 32767 characters.
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
@ -41,7 +41,7 @@ C<supervisory> is specified, DOL is ignored, the current value of VAL is
written, and VAL can be changed externally via dbPuts at run-time.
The maximum number of characters in VAL is given by SIZV, and cannot be larger
than 65535.
than 32767.
DOL can also be a constant instead of a link, in which case VAL is initialized
to the constant value. Most simple string constants are likely to be interpreted

View File

@ -337,6 +337,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (sizv < 16) {
sizv = 16; /* Enforce a minimum size for the VAL field */
prec->sizv = sizv;
} else if (sizv > 0x7fff) {
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
prec->sizv = sizv;
}
prec->val = callocMustSucceed(1, sizv, "printf::init_record");

View File

@ -152,7 +152,7 @@ Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Dat
for information on specifying links.
The formatted string is written to the VAL field. The maximum number of
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
characters in VAL is given by SIZV, and cannot be larger than 32767. The LEN
field contains the length of the formatted string in the VAL field.
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN

View File

@ -17,10 +17,12 @@
#include <epicsGetopt.h>
#include "registryFunction.h"
#include "errlog.h"
#include "epicsThread.h"
#include "epicsExit.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "errlog.h"
#include "dbStaticLib.h"
#include "subRecord.h"
#include "dbAccess.h"
@ -92,7 +94,7 @@ void usage(const char *arg0, const std::string& base_dbd) {
"interactive IOC shell.\n"
"\n"
"Compiled-in path to softIoc.dbd is:\n"
"\t"<<base_dbd.c_str()<<"\n";
"\t"<<base_dbd.c_str()<<std::endl;
}
void errIf(int ret, const std::string& msg)
@ -239,7 +241,9 @@ int main(int argc, char *argv[])
if (loadedDb) {
if (verbose)
std::cout<<"iocInit()\n";
iocInit();
if(iocInit()) {
std::cerr<<ERL_ERROR " during iocInit()"<<std::endl;
}
epicsThreadSleep(0.2);
}
@ -270,7 +274,8 @@ int main(int argc, char *argv[])
return 0;
}catch(std::exception& e){
std::cerr<<"Error: "<<e.what()<<"\n";
errlogFlush();
std::cerr<<ERL_ERROR ": "<<e.what()<<"\n";
epicsExit(2);
return 2;
}

View File

@ -597,8 +597,12 @@ void testJLink(void)
testNumZ(6);
testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}");
testdbPutFieldOk("j1.PHAS", DBF_LONG, 0);
testdbPutFieldOk("j1.OUTP", DBF_STRING, "{z:{good:99}}");
testdbPutFieldOk("j1.PROC", DBF_LONG, 1);
testdbGetFieldEqual("j1.VAL", DBF_LONG, 4);
testdbGetFieldEqual("j1.PHAS", DBF_LONG, 4);
testdbPutFieldOk("j1.OUTP", DBF_STRING, "");
testdbPutFieldOk("j2.TSEL", DBF_STRING, "{'z':{good:0}}");
testdbPutFieldOk("j2.PROC", DBF_LONG, 1);
@ -701,7 +705,7 @@ void testTSEL(void)
MAIN(dbPutLinkTest)
{
testPlan(348);
testPlan(352);
testLinkParse();
testLinkFailParse();
testCADBSet();

View File

@ -59,6 +59,9 @@ static unsigned int nrecords;
#define MAXLOCK 20
/* Verbose output from test if you set this to 1 */
#define MULTI_DIAG 0
static dbCommon **precords;
typedef struct {
@ -120,6 +123,9 @@ void doMulti(workerPriv *p)
}
dbScanUnlockMany(locker);
if (MULTI_DIAG)
testDiag("sum = %d", sum);
dbLockerFree(locker);
}

View File

@ -35,7 +35,6 @@ void z_open(struct link *plink)
if(priv->isopen)
testDiag("lsetZ re-open");
priv->isopen = 1;
testDiag("Open jlinkz %p", priv);
}
static
@ -50,8 +49,6 @@ void z_remove(struct dbLocker *locker, struct link *plink)
epicsMutexUnlock(priv->lock);
testDiag("Remove/free jlinkz %p", priv);
epicsAtomicDecrIntT(&numzalloc);
epicsMutexDestroy(priv->lock);
@ -83,13 +80,13 @@ long z_getval(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
long ret;
long (*pconv)(const epicsInt32 *, void *, const dbAddr *) = dbFastGetConvertRoutine[DBF_LONG][dbrType];
FASTCONVERTFUNC pconv = dbFastGetConvertRoutine[DBF_LONG][dbrType];
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
if(pnRequest && *pnRequest==0) return 0;
epicsMutexLock(priv->lock);
ret = (*pconv)(&priv->value, pbuffer, NULL);
ret = pconv(&priv->value, pbuffer, NULL);
epicsMutexUnlock(priv->lock);
if(ret==0 && pnRequest) *pnRequest = 1;
return ret;
@ -118,19 +115,20 @@ long z_putval(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
long ret;
long (*pconv)(epicsInt32 *, const void *, const dbAddr *);
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
FASTCONVERTFUNC pconv;
if(INVALID_DB_REQ(dbrType))
return S_db_badDbrtype;
pconv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
pconv = dbFastPutConvertRoutine[dbrType][DBF_LONG];
if(nRequest==0) return 0;
epicsMutexLock(priv->lock);
ret = (*pconv)(&priv->value, pbuffer, NULL);
ret = pconv(pbuffer, &priv->value, NULL);
epicsMutexUnlock(priv->lock);
plink->precord->phas = priv->value;
return ret;
}
@ -168,8 +166,6 @@ jlink* z_alloc(short dbfType)
epicsAtomicIncrIntT(&numzalloc);
testDiag("Alloc jlinkz %p", priv);
return &priv->base;
fail:
if(priv && priv->lock) epicsMutexDestroy(priv->lock);
@ -185,8 +181,6 @@ void z_free(jlink *pj)
if(priv->isopen)
testDiag("lsetZ jlink free after open()");
testDiag("Free jlinkz %p", priv);
epicsAtomicDecrIntT(&numzalloc);
epicsMutexDestroy(priv->lock);

View File

@ -71,6 +71,7 @@ static long process(struct dbCommon *pcommon)
ret = (*xset->process)(prec);
monitor(prec);
recGblGetTimeStamp(prec);
dbPutLink(&prec->outp, DBR_LONG, &prec->val, 1);
recGblFwdLink(prec);
prec->pact = FALSE;
return ret;

View File

@ -49,6 +49,9 @@ recordtype(x) {
prompt("Input Link")
special(SPC_MOD)
}
field(OUTP, DBF_OUTLINK) {
prompt("Output Link")
}
field(CLBK, DBF_NOACCESS) {
prompt("Processing callback")
special(SPC_NOMOD)

View File

@ -469,6 +469,38 @@ testNto1Average(void) {
testdbCleanup();
}
void testNto2Average(void) {
DBADDR wfaddr, caddr;
testDiag("Test N to 1 Average, NSAM=2, N=2");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=2");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
checkArrD("comp", 2, 1.5, 3.5, 0, 0);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1AveragePartial(void) {
double buf = 0.0;
@ -517,6 +549,36 @@ testNto1AveragePartial(void) {
testdbCleanup();
}
void
testNtoMPartial(void) {
DBADDR wfaddr, caddr;
testDiag("Test Average, N to M, Partial");
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
recTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=3,PBUF=YES");
eltc(0);
testIocInitOk();
eltc(1);
fetchRecordOrDie("wf", wfaddr);
fetchRecordOrDie("comp", caddr);
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
dbScanLock(caddr.precord);
dbProcess(caddr.precord);
checkArrD("comp", 2, 2.0, 4.0, 0, 0);
dbScanUnlock(caddr.precord);
testIocShutdownOk();
testdbCleanup();
}
void
testNto1LowValue(void) {
double buf = 0.0;
@ -634,12 +696,14 @@ testAIAveragePartial(void) {
MAIN(compressTest)
{
testPlan(132);
testPlan(134);
testFIFOCirc();
testLIFOCirc();
testArrayAverage();
testNto1Average();
testNto2Average();
testNto1AveragePartial();
testNtoMPartial();
testAIAveragePartial();
testNto1LowValue();
return testDone();

View File

@ -522,7 +522,7 @@ void errPrintf(long status, const char *pFileName, int lineno,
errSymLookup(status, name, sizeof(name));
}
nchar = epicsSnprintf(buf, pvt.maxMsgSize, "%s%sfilename=\"%s\" line number=%d",
nchar = epicsSnprintf(buf, pvt.maxMsgSize, "%s%sfilename=\"%s\" line number=%d ",
name, status ? " " : "", pFileName, lineno);
if(nchar < pvt.maxMsgSize)
nchar += epicsVsnprintf(buf + nchar, pvt.maxMsgSize - nchar, pformat, pvar);

View File

@ -1437,13 +1437,16 @@ static void varCallFunc(const iocshArgBuf *args)
varHandler(v->pVarDef, NULL);
found = 1;
}
if (!found && name != NULL)
if (!found && name != NULL) {
fprintf(epicsGetStderr(), ANSI_RED("No var matching") " %s found.\n", name);
iocshSetError(1);
}
}
else {
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
if (v == NULL) {
fprintf(epicsGetStderr(), "Var %s " ANSI_RED("not found.") "\n", name);
iocshSetError(1);
}
else {
varHandler(v->pVarDef, value);
@ -1460,7 +1463,7 @@ static const iocshFuncDef iocshCmdFuncDef = {"iocshCmd",1,iocshCmdArgs,
" from vxWorks or RTEMS startup script (or command line)\n"};
static void iocshCmdCallFunc(const iocshArgBuf *args)
{
iocshCmd(args[0].sval);
iocshSetError(iocshCmd(args[0].sval));
}
/* iocshLoad */
@ -1472,7 +1475,7 @@ static const iocshFuncDef iocshLoadFuncDef = {"iocshLoad",2,iocshLoadArgs,
" * (optional) replace macros within the file with provided values\n"};
static void iocshLoadCallFunc(const iocshArgBuf *args)
{
iocshLoad(args[0].sval, args[1].sval);
iocshSetError(iocshLoad(args[0].sval, args[1].sval));
}
/* iocshRun */
@ -1485,7 +1488,7 @@ static const iocshFuncDef iocshRunFuncDef = {"iocshRun",2,iocshRunArgs,
" from vxWorks or RTEMS startup script (or command line)\n"};
static void iocshRunCallFunc(const iocshArgBuf *args)
{
iocshRun(args[0].sval, args[1].sval);
iocshSetError(iocshRun(args[0].sval, args[1].sval));
}
/* on */