From c1b0c1bac10c8e4c570347c684eb0d91de8d4a62 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Feb 2016 17:09:44 -0500 Subject: [PATCH 001/147] libCom/misc: testMain for RTEMS give weak alias for main() Allows tests to be linked separately or in a common test harness --- src/libCom/misc/testMain.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libCom/misc/testMain.h b/src/libCom/misc/testMain.h index 4db72c39e..7c4d9b29b 100644 --- a/src/libCom/misc/testMain.h +++ b/src/libCom/misc/testMain.h @@ -27,7 +27,13 @@ * } */ -#if defined(vxWorks) || defined(__rtems__) +#if defined(__rtems__) + #ifdef __cplusplus + #define MAIN(prog) extern "C" int prog(void); extern "C" int main() __attribute__((weak, alias(#prog))); extern "C" int prog(void) + #else + #define MAIN(prog) int prog(); int main() __attribute__((weak, alias(#prog))); int prog() + #endif +#elif defined(vxWorks) #ifdef __cplusplus #define MAIN(prog) extern "C" int prog(void) #else From 15b97f65cbde688972986173504700eb38ed1362 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Feb 2016 17:09:44 -0500 Subject: [PATCH 002/147] src/tools: teach makeTestfile about WINE and QEMU Teach makeTestfile host to run test for some cross built targets. --- configure/RULES_BUILD | 2 +- src/tools/makeTestfile.pl | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index ea84db8be..5d335c126 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -380,7 +380,7 @@ endif # Generate a perl program to exec the real test binary. %.t: %$(EXE) $(TOOLS)/makeTestfile.pl @$(RM) $@ - $(PERL) $(TOOLS)/makeTestfile.pl $@ $< + $(PERL) $(TOOLS)/makeTestfile.pl "$(T_A)" $(EPICS_HOST_ARCH) $@ $< #--------------------------------------------------------------- # Generate header with version number from VCS diff --git a/src/tools/makeTestfile.pl b/src/tools/makeTestfile.pl index be4648258..73f522034 100644 --- a/src/tools/makeTestfile.pl +++ b/src/tools/makeTestfile.pl @@ -15,13 +15,38 @@ # If the script is given an argument -tap it sets HARNESS_ACTIVE in the # environment to make the epicsUnitTest code generate strict TAP output. -# Usage: makeTestfile.pl target.t executable +# Usage: makeTestfile.pl target.t executable +# target-arch and host-arch are EPICS build target names (eg. linux-x86) # target.t is the name of the Perl script to generate # executable is the name of the file the script runs use strict; -my ($target, $exe) = @ARGV; +my ($TA, $HA, $target, $exe) = @ARGV; +my $exec; + +# Use WINE to run windows target executables on non-windows host +if( $TA =~ /^win32-x86/ && $HA !~ /^win/ ) { + # new deb. derivatives have wine32 and wine64 + # older have wine and wine64 + # prefer wine32 if present + my $wine32 = "/usr/bin/wine32"; + $wine32 = "/usr/bin/wine" if ! -x $wine32; + $exec = "$wine32 $exe"; +} elsif( $TA =~ /^windows-x64/ && $HA !~ /^win/ ) { + $exec = "wine64 $exe"; + +# Run pc386 test harness w/ QEMU +} elsif( $TA =~ /^RTEMS-pc386$/ ) { + $exec = "qemu-system-i386 -m 64 -no-reboot -serial stdio -display none -net nic,model=ne2k_pci -net user,restrict=yes -kernel $exe"; + +# Explicitly fail for other RTEMS targets +} elsif( $TA =~ /^RTEMS-/ ) { + die "I don't know how to run tests for $TA on $HA"; + +} else { + $exec = "./$exe"; +} open(my $OUT, '>', $target) or die "Can't create $target: $!\n"; @@ -34,14 +59,7 @@ use Cwd 'abs_path'; \$ENV{HARNESS_ACTIVE} = 1 if scalar \@ARGV && shift eq '-tap'; \$ENV{TOP} = abs_path(\$ENV{TOP}) if exists \$ENV{TOP}; -if (\$^O eq 'MSWin32') { - # Use system on Windows, exec doesn't work the same there and - # GNUmake thinks the test has finished as soon as Perl exits. - system('./$exe') == 0 or die "Can't run $exe: \$!\\n"; -} -else { - exec './$exe' or die "Can't run $exe: \$!\\n"; -} +system('$exec') == 0 or die "Can't run $exec: \$!\\n"; EOF close $OUT or die "Can't close $target: $!\n"; From 684fe10d8c2685c168fc9981ddbe2c266694996a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Feb 2016 17:09:44 -0500 Subject: [PATCH 003/147] RTEMS: Add epicsMemFs and hook for app specific FS setup Default falls back to network FS. Compile in a set of files as a epicsMemFS structure. epicsMemFsLoad() creates a set of files based on this. --- src/libCom/RTEMS/Makefile | 2 + src/libCom/RTEMS/epicsMemFs.c | 110 +++++++++++++++++++++++++ src/libCom/RTEMS/epicsMemFs.h | 24 ++++++ src/libCom/RTEMS/epicsRtemsInitHooks.h | 2 + src/libCom/RTEMS/rtems_init.c | 31 ++++++- src/tools/Makefile | 1 + src/tools/epicsMakeMemFs.pl | 83 +++++++++++++++++++ 7 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/libCom/RTEMS/epicsMemFs.c create mode 100644 src/libCom/RTEMS/epicsMemFs.h create mode 100644 src/tools/epicsMakeMemFs.pl diff --git a/src/libCom/RTEMS/Makefile b/src/libCom/RTEMS/Makefile index 4c0b64c04..8652c669b 100644 --- a/src/libCom/RTEMS/Makefile +++ b/src/libCom/RTEMS/Makefile @@ -10,6 +10,7 @@ TOP=../../.. include $(TOP)/configure/CONFIG INC += epicsRtemsInitHooks.h +INC += epicsMemFs.h rtemsCom_SRCS += rtems_init.c rtemsCom_SRCS += rtems_config.c @@ -18,6 +19,7 @@ rtemsCom_SRCS += rtems_util.c rtemsCom_SRCS += setBootConfigFromNVRAM.c rtemsCom_SRCS += epicsRtemsInitHookPre.c rtemsCom_SRCS += epicsRtemsInitHookPost.c +rtemsCom_SRCS += epicsMemFs.c LIBRARY_RTEMS = rtemsCom diff --git a/src/libCom/RTEMS/epicsMemFs.c b/src/libCom/RTEMS/epicsMemFs.c new file mode 100644 index 000000000..4689d210f --- /dev/null +++ b/src/libCom/RTEMS/epicsMemFs.c @@ -0,0 +1,110 @@ +/*************************************************************************\ +* Copyright (c) 2014 Brookhaven National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include "epicsMemFs.h" + +#ifndef PATH_MAX +# define PATH_MAX 100 +#endif + +int epicsMemFsLoad(const epicsMemFS *fs) +{ + char initdir[PATH_MAX]; + const epicsMemFile * const *fileptr = fs->files; + + if(getcwd(initdir, sizeof(initdir)-1)==NULL) { + perror("getcwd"); + return errno; + } + initdir[sizeof(initdir)-1] = '\0'; + + for(;*fileptr; fileptr++) { + const epicsMemFile *curfile = *fileptr; + int fd; + ssize_t ret; + size_t sofar; + const char * const *dir = curfile->directory; + /* jump back to the root each time, + * slow but simple. + */ + if(chdir(initdir)) { + perror("chdir"); + return errno; + } + + printf("-> /"); + + /* traverse directory tree, creating as necessary */ + for(;*dir; dir++) { + int ret; + if(**dir=='.') continue; /* ignore '.' and '..' */ + printf("%s/", *dir); + ret = chdir(*dir); + if(ret==-1 && errno==ENOENT) { + /* this directory doesn't exist */ + if(mkdir(*dir,0744)==-1) { + printf("\n"); + perror("mkdir"); + return errno; + } + if(chdir(*dir)==-1) { + printf("\n"); + perror("chdir2"); + return errno; + } + } else if(ret==-1) { + printf("\n"); + perror("chdir1"); + return errno; + } + } + + /* no file name creates an empty directory */ + if(!curfile->name) { + printf("\n"); + continue; + } + printf("%s", curfile->name); + + /* create or overwrite */ + fd = open(curfile->name, O_WRONLY|O_CREAT|O_TRUNC, 0644); + + if(fd==-1) { + printf("\n"); + perror("open"); + return errno; + } + + sofar = 0; + + while(sofarsize) { + ret = write(fd, curfile->data+sofar, curfile->size-sofar); + if(ret<=0) { + printf("\n"); + perror("write"); + return errno; + } + sofar += ret; + } + + close(fd); + printf(" - ok\n"); + } + + if(chdir(initdir)) + perror("chdir"); + + return 0; +} diff --git a/src/libCom/RTEMS/epicsMemFs.h b/src/libCom/RTEMS/epicsMemFs.h new file mode 100644 index 000000000..c57f4d793 --- /dev/null +++ b/src/libCom/RTEMS/epicsMemFs.h @@ -0,0 +1,24 @@ +/*************************************************************************\ +* Copyright (c) 2014 Brookhaven National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +#ifndef EPICSMEMFS_H +#define EPICSMEMFS_H + +#include + +typedef struct { + const char * const *directory; /* NULL terminated list of directories */ + const char *name; /* file name */ + const char *data; /* file contents */ + size_t size; /* size of file contents in bytes */ +} epicsMemFile; + +typedef struct { + const epicsMemFile * const *files; +} epicsMemFS; + +int epicsMemFsLoad(const epicsMemFS *fs); + +#endif // EPICSMEMFS_H diff --git a/src/libCom/RTEMS/epicsRtemsInitHooks.h b/src/libCom/RTEMS/epicsRtemsInitHooks.h index b7f09c100..4313f19e3 100644 --- a/src/libCom/RTEMS/epicsRtemsInitHooks.h +++ b/src/libCom/RTEMS/epicsRtemsInitHooks.h @@ -21,3 +21,5 @@ extern char *env_nfsMountPoint; */ int epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config); int epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config); +/* Return 0 if local file system was setup, or non-zero (will fall back to network */ +int epicsRtemsMountLocalFilesystem(char **argv); diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c index 82871da0d..4e8298a29 100644 --- a/src/libCom/RTEMS/rtems_init.c +++ b/src/libCom/RTEMS/rtems_init.c @@ -42,6 +42,7 @@ #include "osiUnistd.h" #include "iocsh.h" #include "osdTime.h" +#include "epicsMemFs.h" #include "epicsRtemsInitHooks.h" @@ -138,6 +139,31 @@ mustMalloc(int size, const char *msg) # include #endif +const epicsMemFS *epicsRtemsFSImage __attribute__((weak)); +const epicsMemFS *epicsRtemsFSImage = (void*)&epicsRtemsFSImage; + +/* hook to allow app specific FS setup */ +int +epicsRtemsMountLocalFilesystem(char **argv) __attribute__((weak)); +int +epicsRtemsMountLocalFilesystem(char **argv) +{ + if(epicsRtemsFSImage==(void*)&epicsRtemsFSImage) + return -1; /* no FS image provided. */ + else if(epicsRtemsFSImage==NULL) + return 0; /* no FS image provided, but none is needed. */ + else { + printf("***** Using compiled in file data *****\n"); + if (epicsMemFsLoad(epicsRtemsFSImage) != 0) { + printf("Can't unpack tar filesystem\n"); + return -1; + } else { + argv[1] = "/"; + return 0; + } + } +} + static int initialize_local_filesystem(char **argv) { @@ -146,7 +172,9 @@ initialize_local_filesystem(char **argv) extern char _FlashSize[] __attribute__((weak)); argv[0] = rtems_bsdnet_bootp_boot_file_name; - if (_FlashSize && (_DownloadLocation || _FlashBase)) { + if (epicsRtemsMountLocalFilesystem(argv)==0) { + return 1; /* FS setup successful */ + } else if (_FlashSize && (_DownloadLocation || _FlashBase)) { extern char _edata[]; size_t flashIndex = _edata - _DownloadLocation; char *header = _FlashBase + flashIndex; @@ -596,6 +624,7 @@ Init (rtems_task_argument ignored) } printf("\n***** Initializing network *****\n"); rtems_bsdnet_initialize_network(); + printf("\n***** Setting up file system *****\n"); initialize_remote_filesystem(argv, initialize_local_filesystem(argv)); fixup_hosts(); diff --git a/src/tools/Makefile b/src/tools/Makefile index e7457ae67..0e27c9340 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -48,6 +48,7 @@ PERL_SCRIPTS += mkmf.pl PERL_SCRIPTS += munch.pl PERL_SCRIPTS += replaceVAR.pl PERL_SCRIPTS += tap-to-junit-xml.pl +PERL_SCRIPTS += epicsMakeMemFs.pl PERL_SCRIPTS += useManifestTool.pl PERL_SCRIPTS += genVersionHeader.pl diff --git a/src/tools/epicsMakeMemFs.pl b/src/tools/epicsMakeMemFs.pl new file mode 100644 index 000000000..a97074e0e --- /dev/null +++ b/src/tools/epicsMakeMemFs.pl @@ -0,0 +1,83 @@ +#!/usr/bin/env perl +# + +use File::Basename; + +use strict; + +my $outfile = shift; +my $varname = shift; + +open(my $DST, '>', $outfile) or die "Failed to open $outfile"; + +print $DST < +EOF + +my $N = 0; + +for my $fname (@ARGV) { + print "<- $fname\n"; + my $realfname = $fname; + + # strip leading "../" "./" or "/" + while ($fname =~ /^\.*\/(.*)$/) { $fname = $1; } + + my $file = basename($fname); + my @dirs = split('/', dirname($fname)); + + print $DST "/* begin $realfname */\nstatic const char * const file_${N}_dir[] = {"; + for my $dpart (@dirs) { + print $DST "\"$dpart\", "; + } + print $DST "NULL};\nstatic const char file_${N}_data[] = {\n "; + + open(my $SRC, '<', $realfname) or die "Failed to open $realfname"; + binmode($SRC); + + my $buf; + my $total = 0; + while (my $num = read($SRC, $buf, 32)) { + if($total != 0) { + print $DST ",\n "; + } + $total += $num; + my $out = join(",",map(ord,split(//,$buf))); + print $DST "$out"; + } + + close($SRC); + + print $DST < Date: Sat, 18 Mar 2017 20:11:55 -0400 Subject: [PATCH 004/147] RTEMS: build self contained test harness Test data stub as a separate file to allow linking into test harness and individual tests. --- src/ioc/db/test/Makefile | 4 ++++ src/libCom/test/Makefile | 2 ++ src/libCom/test/rtemsTestData.c | 6 ++++++ src/std/filters/test/Makefile | 5 +++++ src/std/rec/test/Makefile | 5 +++++ 5 files changed, 22 insertions(+) create mode 100644 src/libCom/test/rtemsTestData.c diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index 37ec3da74..d8ca0f15b 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -175,6 +175,8 @@ testHarness_SRCS += epicsRunDbTests.c dbTestHarness_SRCS += $(testHarness_SRCS) dbTestHarness_SRCS_RTEMS += rtemsTestHarness.c +PROD_SRCS_RTEMS += rtemsTestData.c + PROD_vxWorks = dbTestHarness PROD_RTEMS = dbTestHarness @@ -193,3 +195,5 @@ devx$(DEP): $(COMMON_DIR)/xRecord.h scanIoTest$(DEP): $(COMMON_DIR)/xRecord.h xRecord$(DEP): $(COMMON_DIR)/xRecord.h +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 04438854c..9b3b7dacd 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -13,6 +13,8 @@ include $(TOP)/configure/CONFIG PROD_LIBS += Com PROD_SYS_LIBS_WIN32 += ws2_32 advapi32 user32 +PROD_SRCS_RTEMS += rtemsTestData.c + TESTPROD_HOST += epicsUnitTestTest epicsUnitTestTest_SRCS += epicsUnitTestTest.c # Not much point running this on vxWorks or RTEMS... diff --git a/src/libCom/test/rtemsTestData.c b/src/libCom/test/rtemsTestData.c new file mode 100644 index 000000000..7b68976c5 --- /dev/null +++ b/src/libCom/test/rtemsTestData.c @@ -0,0 +1,6 @@ +#include "epicsMemFs.h" + +/* no local files needed for these tests, + * so skip local FS setup + */ +const epicsMemFS *epicsRtemsFSImage = NULL; diff --git a/src/std/filters/test/Makefile b/src/std/filters/test/Makefile index 6e6ad79c6..1c8efd1a1 100644 --- a/src/std/filters/test/Makefile +++ b/src/std/filters/test/Makefile @@ -62,6 +62,8 @@ testHarness_SRCS += epicsRunFilterTests.c filterTestHarness_SRCS += $(testHarness_SRCS) filterTestHarness_SRCS_RTEMS += rtemsTestHarness.c +PROD_SRCS_RTEMS += rtemsTestData.c + PROD_vxWorks = filterTestHarness PROD_RTEMS = filterTestHarness @@ -78,3 +80,6 @@ dbndTest$(DEP): $(COMMON_DIR)/xRecord.h syncTest$(DEP): $(COMMON_DIR)/xRecord.h arrRecord$(DEP): $(COMMON_DIR)/arrRecord.h arrTest$(DEP): $(COMMON_DIR)/arrRecord.h + +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 5a591b230..5619f491a 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -110,6 +110,8 @@ testHarness_SRCS += epicsRunRecordTests.c recordTestHarness_SRCS += $(testHarness_SRCS) recordTestHarness_SRCS_RTEMS += rtemsTestHarness.c +PROD_SRCS_RTEMS += rtemsTestData.c + PROD_vxWorks = recordTestHarness PROD_RTEMS = recordTestHarness @@ -119,3 +121,6 @@ TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunRecordTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) include $(TOP)/configure/RULES + +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) From 12da38a7ca5cff6a77da86cc07fc96417091bfd9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Mar 2017 20:12:02 -0400 Subject: [PATCH 005/147] build/run RTEMS-pc386 tests individually Build and run individual test executable in addition to the test harness. Individual tests run with 'make runtests'. omit epicsUnitTestTest as it has a custom .plt --- src/ioc/db/test/Makefile | 4 ++++ src/libCom/test/Makefile | 4 ++++ src/std/filters/test/Makefile | 4 ++++ src/std/rec/test/Makefile | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index d8ca0f15b..baa381534 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -184,6 +184,10 @@ TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) +ifeq ($(T_A),RTEMS-pc386) +TESTPROD_RTEMS = $(TESTPROD_HOST) +TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) +endif include $(TOP)/configure/RULES diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 9b3b7dacd..0aba60e32 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -230,6 +230,10 @@ TESTSPEC_vxWorks = libComTestHarness.munch; epicsRunLibComTests TESTSPEC_RTEMS = libComTestHarness.boot; epicsRunLibComTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) +ifeq ($(T_A),RTEMS-pc386) +TESTPROD_RTEMS = $(TESTPROD_HOST) +TESTSCRIPTS_RTEMS += $(filter-out epicsUnitTestTest.t, $(TESTS:%=%.t)) +endif # The following are not test programs, they measure performance. diff --git a/src/std/filters/test/Makefile b/src/std/filters/test/Makefile index 1c8efd1a1..6442ba332 100644 --- a/src/std/filters/test/Makefile +++ b/src/std/filters/test/Makefile @@ -71,6 +71,10 @@ TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) +ifeq ($(T_A),RTEMS-pc386) +TESTPROD_RTEMS = $(TESTPROD_HOST) +TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) +endif include $(TOP)/configure/RULES diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 5619f491a..f5f9b4312 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -119,6 +119,10 @@ TESTSPEC_vxWorks = recordTestHarness.munch; epicsRunRecordTests TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunRecordTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) +ifeq ($(T_A),RTEMS-pc386) +TESTPROD_RTEMS = $(TESTPROD_HOST) +TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) +endif include $(TOP)/configure/RULES From 1255cdc9eee919bf8e8ac9be7266fc23c9620203 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 15 Feb 2016 17:09:44 -0500 Subject: [PATCH 006/147] libCom/test: only run epicsUnitTest for host arch custom .plt won't use WINE or QEMU when necessary. --- src/libCom/test/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 0aba60e32..b8014a2ab 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -15,11 +15,16 @@ PROD_SYS_LIBS_WIN32 += ws2_32 advapi32 user32 PROD_SRCS_RTEMS += rtemsTestData.c +ifeq ($(EPICS_HOST_ARCH),$(T_A)) +# skip except for host arch due to custom .plt + TESTPROD_HOST += epicsUnitTestTest epicsUnitTestTest_SRCS += epicsUnitTestTest.c # Not much point running this on vxWorks or RTEMS... TESTS += epicsUnitTestTest +endif + TESTPROD_HOST += epicsTypesTest epicsTypesTest_SRCS += epicsTypesTest.cpp testHarness_SRCS += epicsTypesTest.cpp From c8b60e0f1bcc8c4faf340fb283b61e96869aa0a5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 29 Feb 2016 20:28:52 -0500 Subject: [PATCH 007/147] db/test: dbStressLock skip for RTEMS This test assumes that several threads with equal priority will all run eventually. This isn't true an UP target without time sliced scheduling (eg. RTEMS). --- src/ioc/db/test/dbStressLock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ioc/db/test/dbStressLock.c b/src/ioc/db/test/dbStressLock.c index 376587975..03a8e8b54 100644 --- a/src/ioc/db/test/dbStressLock.c +++ b/src/ioc/db/test/dbStressLock.c @@ -228,6 +228,11 @@ MAIN(dbStressTest) testPlan(80+nworkers*3); +#if defined(__rtems__) + testSkip(80+nworkers*3, "Test assumes time sliced preempting scheduling"); + return testDone(); +#endif + priv = callocMustSucceed(nworkers, sizeof(*priv), "no memory"); testDiag("lock set stress test"); From aace975de13fdd71472fd4aaeddb866d37b885e7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 20 Jun 2015 09:05:28 -0400 Subject: [PATCH 008/147] RTEMS: probe for PCI varient of NE2000 NIC Provided by QEMU --- src/libCom/RTEMS/Makefile | 4 +++ src/libCom/RTEMS/ne2kpci.c | 58 ++++++++++++++++++++++++++++++ src/libCom/RTEMS/rtems_netconfig.c | 10 +++++- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/libCom/RTEMS/ne2kpci.c diff --git a/src/libCom/RTEMS/Makefile b/src/libCom/RTEMS/Makefile index 8652c669b..8d467b260 100644 --- a/src/libCom/RTEMS/Makefile +++ b/src/libCom/RTEMS/Makefile @@ -21,6 +21,10 @@ rtemsCom_SRCS += epicsRtemsInitHookPre.c rtemsCom_SRCS += epicsRtemsInitHookPost.c rtemsCom_SRCS += epicsMemFs.c +ifeq ($(T_A),RTEMS-pc386) +rtemsCom_SRCS += ne2kpci.c +endif + LIBRARY_RTEMS = rtemsCom include $(TOP)/configure/RULES diff --git a/src/libCom/RTEMS/ne2kpci.c b/src/libCom/RTEMS/ne2kpci.c new file mode 100644 index 000000000..909d885f1 --- /dev/null +++ b/src/libCom/RTEMS/ne2kpci.c @@ -0,0 +1,58 @@ +/*************************************************************************\ +* Copyright (c) 2015 Brookhaven Science Associates, 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. +\*************************************************************************/ +/* + * Wrapper around the ISA ne2000 driver to support detection of the PCI variant. + * Can be used with the ne2k_pci device provided by QEMU. + * + * eg. "qemu-system-i386 ... -net nic,model=ne2k_pci" + */ + +#include +#include +#include +#include +#include + +/* The plain ISA driver attach() + * which doesn't (can't?) do any test to see if + * the HW is really present + */ +extern int +rtems_ne_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach); + +int +rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach) +{ + uint8_t irq; + uint32_t bar0; + int B, D, F, ret; + printk("Probing for NE2000 on PCI (aka. Realtek 8029)\n"); + + if(pci_find_device(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, 0, &B, &D, &F)) + { + printk("Not found\n"); + return 0; + } + + printk("Found %d:%d.%d\n", B, D, F); + + ret = pci_read_config_dword(B, D, F, PCI_BASE_ADDRESS_0, &bar0); + ret|= pci_read_config_byte(B, D, F, PCI_INTERRUPT_LINE, &irq); + + if(ret || (bar0&PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO) + { + printk("Failed reading card config\n"); + return 0; + } + + config->irno = irq; + config->port = bar0&PCI_BASE_ADDRESS_IO_MASK; + + printk("Using port=0x%x irq=%u\n", (unsigned)config->port, config->irno); + + return rtems_ne_driver_attach(config, attach); +} diff --git a/src/libCom/RTEMS/rtems_netconfig.c b/src/libCom/RTEMS/rtems_netconfig.c index 832a6646b..d0c500c92 100644 --- a/src/libCom/RTEMS/rtems_netconfig.c +++ b/src/libCom/RTEMS/rtems_netconfig.c @@ -36,11 +36,19 @@ static struct rtems_bsdnet_ifconfig loopback_config = { * application directory and make the appropriate changes. */ #if defined(__i386__) + +extern int +rtems_ne2kpci_driver_attach (struct rtems_bsdnet_ifconfig *config, int attach); +static struct rtems_bsdnet_ifconfig ne2k_driver_config = { + "ne2", /* name */ + rtems_ne2kpci_driver_attach, /* attach function */ + &loopback_config, /* link to next interface */ +}; extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int); static struct rtems_bsdnet_ifconfig fxp_driver_config = { "fxp1", /* name */ rtems_fxp_attach, /* attach function */ - &loopback_config, /* link to next interface */ + &ne2k_driver_config, /* link to next interface */ }; extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int); static struct rtems_bsdnet_ifconfig e3c509_driver_config = { From 6923ca9fdad24d618cb6dcf5d2e48e20ce298a2f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 20 Jun 2015 11:57:43 -0400 Subject: [PATCH 009/147] RTEMS: conditional fixups for pc386 --- src/libCom/RTEMS/Makefile | 3 +++ src/libCom/RTEMS/rtems_init.c | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/libCom/RTEMS/Makefile b/src/libCom/RTEMS/Makefile index 8d467b260..2f12b7bf0 100644 --- a/src/libCom/RTEMS/Makefile +++ b/src/libCom/RTEMS/Makefile @@ -12,6 +12,9 @@ include $(TOP)/configure/CONFIG INC += epicsRtemsInitHooks.h INC += epicsMemFs.h +ifeq ($(RTEMS_QEMU_FIXUPS),YES) +rtems_init_CPPFLAGS += -DQEMU_FIXUPS +endif rtemsCom_SRCS += rtems_init.c rtemsCom_SRCS += rtems_config.c rtemsCom_SRCS += rtems_netconfig.c diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c index 4e8298a29..7dbf2594f 100644 --- a/src/libCom/RTEMS/rtems_init.c +++ b/src/libCom/RTEMS/rtems_init.c @@ -33,6 +33,7 @@ #include #include +#include "epicsVersion.h" #include "epicsThread.h" #include "epicsTime.h" #include "epicsExit.h" @@ -46,6 +47,8 @@ #include "epicsRtemsInitHooks.h" +#define RTEMS_VERSION_INT VERSION_INT(__RTEMS_MAJOR__, __RTEMS_MINOR__, 0, 0) + /* * Prototypes for some functions not in header files */ @@ -695,3 +698,37 @@ Init (rtems_task_argument ignored) epicsThreadSleep(1.0); epicsExit(result); } + +#if defined(QEMU_FIXUPS) +/* Override some hooks (weak symbols) + * if BSP defaults aren't configured for running tests. + */ + + +/* Ensure that stdio goes to serial (so it can be captured) */ +#if defined(__i386__) && !USE_COM1_AS_CONSOLE +#include +extern int BSPPrintkPort; +void bsp_predriver_hook(void) +{ + BSPConsolePort = BSP_CONSOLE_PORT_COM1; + BSPPrintkPort = BSP_CONSOLE_PORT_COM1; +} +#endif + +/* reboot immediately when done. */ +#if defined(__i386__) && BSP_PRESS_KEY_FOR_RESET +void bsp_cleanup(void) +{ +#if RTEMS_VERSION_INT>=VERSION_INT(4,10,0,0) + void bsp_reset(); + bsp_reset(); +#else + rtemsReboot(); +#endif +} +#endif + +#endif /* QEMU_FIXUPS */ + +int cexpdebug __attribute__((weak)); From d5f74fe0062ebc86484c1a8fdbdc72524a46ba64 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 15 Feb 2017 20:40:22 -0500 Subject: [PATCH 010/147] rtems tests for pc386 --- configure/os/CONFIG_SITE.Common.RTEMS-pc386 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure/os/CONFIG_SITE.Common.RTEMS-pc386 b/configure/os/CONFIG_SITE.Common.RTEMS-pc386 index c772c44fc..85effbe96 100644 --- a/configure/os/CONFIG_SITE.Common.RTEMS-pc386 +++ b/configure/os/CONFIG_SITE.Common.RTEMS-pc386 @@ -1,3 +1,5 @@ # # Site-specific overrides for RTEMS-pc386 target # + +CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386 From e8b4f448ea1faaa2dada63bc3c340e9950354f34 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Nov 2015 18:00:10 -0500 Subject: [PATCH 011/147] travis-ci: run tests with RTEMS pc386/qemu --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5079bff0c..743908764 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ env: - CMPLR=clang STATIC=YES - WINE=32 TEST=NO STATIC=YES - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO + - RTEMS=4.10 TEST=YES + - RTEMS=4.9 TEST=YES addons: apt: packages: From 98f656fc968736d8ac4298efbbe39592dac1fb2a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Dec 2017 00:07:26 -0600 Subject: [PATCH 012/147] Remove duplicate variables from lnkCalc.c --- src/std/link/lnkCalc.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index e370c36d2..c63495df0 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -496,12 +496,8 @@ static int lnkCalc_getDBFtype(const struct link *plink) calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) { - calc_link *clink = CONTAINER(plink->value.json.jlink, - struct calc_link, jlink); - + IFDEBUG(10) printf("lnkCalc_getDBFtype(calc@%p)\n", clink); - } return DBF_DOUBLE; } @@ -511,13 +507,9 @@ static long lnkCalc_getElements(const struct link *plink, long *nelements) calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) { - calc_link *clink = CONTAINER(plink->value.json.jlink, - struct calc_link, jlink); - + IFDEBUG(10) printf("lnkCalc_getElements(calc@%p, (%ld))\n", clink, *nelements); - } *nelements = 1; return 0; From 8ae34ba01d4d3a86574afd3e1c9d910cfd2bbcb2 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Dec 2017 00:11:18 -0600 Subject: [PATCH 013/147] Add a "state" link type using the dbState API Includes documentation in links.dbd.pod --- src/std/link/Makefile | 4 +- src/std/link/links.dbd.pod | 29 +++++ src/std/link/lnkState.c | 236 +++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 src/std/link/lnkState.c diff --git a/src/std/link/Makefile b/src/std/link/Makefile index 31d14b825..5ad9777a8 100644 --- a/src/std/link/Makefile +++ b/src/std/link/Makefile @@ -2,7 +2,7 @@ # 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. +# in file LICENSE that is included with this distribution. #************************************************************************* # This is a Makefile fragment, see src/std/Makefile. @@ -13,6 +13,6 @@ DBD += links.dbd dbRecStd_SRCS += lnkConst.c dbRecStd_SRCS += lnkCalc.c +dbRecStd_SRCS += lnkState.c HTMLS += links.html - diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index d94e9e8f0..07e1023f2 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -13,6 +13,8 @@ The following additional link types are available in this release: =item * L +=item * L + =back =head2 Using JSON Links @@ -129,3 +131,30 @@ atomically with the value of the input argument. {calc: {expr:"A*B", args:[{db:"record.VAL"}, 1.5], prec:3}} =cut + +link(state, lnkStateIf) + +=head3 dbState Link C<"state"> + +A dbState link is one that reads or writes a boolean value from/to a named +global flag as implemented by the dbState facility in C. + +The value of the named flag is read or written at the time of the link I/O +operation. The boolean flag data is represented as a C that can only +hold the values zero or one; putting any non-zero numeric value to a link sets +the boolean flag value, putting a zero value clears it. + +These dbState flags can be accessed from the IOC Shell with various dbState +commands, and are also used by the C<"sync"> Channel-Access server-side filter +mechanism. + +=head4 Parameters + +The link address must be a string providing the name of the dbState object, +which will be created when the link is initialized if it doesn't already exist. + +=head4 Example + + {state:"redBeam"} + +=cut diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c new file mode 100644 index 000000000..b1f33a552 --- /dev/null +++ b/src/std/link/lnkState.c @@ -0,0 +1,236 @@ +/*************************************************************************\ +* 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. +\*************************************************************************/ +/* lnkState.c */ + +/* Usage: + * {state:green} + */ + +#include +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "errlog.h" +#include "epicsAssert.h" +#include "epicsString.h" +#include "epicsTypes.h" +#include "dbAccessDefs.h" +#include "dbCommon.h" +#include "dbConvertFast.h" +#include "dbLink.h" +#include "dbJLink.h" +#include "dbStaticLib.h" +#include "dbStaticPvt.h" +#include "dbState.h" +#include "recGbl.h" +#include "epicsExport.h" + + +typedef long (*FASTCONVERT)(); + +#define IFDEBUG(n) if(slink->jlink.debug) + +typedef struct state_link { + jlink jlink; /* embedded object */ + char *name; + int val; + dbStateId state; +} state_link; + +static lset lnkState_lset; + + +/*************************** jlif Routines **************************/ + +static jlink* lnkState_alloc(short dbfType) +{ + state_link *slink = calloc(1, sizeof(struct state_link)); + + IFDEBUG(10) + printf("lnkState_alloc()\n"); + + slink->name = NULL; + slink->state = NULL; + slink->val = 0; + + IFDEBUG(10) + printf("lnkState_alloc -> state@%p\n", slink); + + return &slink->jlink; +} + +static void lnkState_free(jlink *pjlink) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_free(state@%p)\n", slink); + + free(slink->name); + free(slink); +} + +static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_string(state@%p, \"%.*s\")\n", slink, (int) len, val); + + slink->name = epicsStrnDup(val, len); + return jlif_continue; +} + +static struct lset* lnkState_get_lset(const jlink *pjlink) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_get_lset(state@%p)\n", pjlink); + + return &lnkState_lset; +} + +static void lnkState_report(const jlink *pjlink, int level, int indent) +{ + state_link *slink = CONTAINER(pjlink, struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_report(state@%p)\n", slink); + + printf("%*s'state': \"%s\" = %d\n", indent, "", + slink->name, slink->val); +} + +/*************************** lset Routines **************************/ + +static void lnkState_open(struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_open(state@%p)\n", slink); + + slink->state = dbStateCreate(slink->name); +} + +static void lnkState_remove(struct dbLocker *locker, struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_remove(state@%p)\n", slink); + + free(slink->name); + free(slink); + + plink->value.json.jlink = NULL; +} + +static int lnkState_isConn(const struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_isConn(state@%p)\n", slink); + + return !! slink->state; +} + +static int lnkState_getDBFtype(const struct link *plink) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_getDBFtype(state@%p)\n", slink); + + return DBF_LONG; +} + +static long lnkState_getElements(const struct link *plink, long *nelements) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + + IFDEBUG(10) + printf("lnkState_getElements(state@%p, (%ld))\n", + slink, *nelements); + + *nelements = 1; + return 0; +} + +static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + long status; + FASTCONVERT conv = dbFastPutConvertRoutine[DBR_LONG][dbrType]; + + IFDEBUG(10) + printf("lnkState_getValue(state@%p, %d, ...)\n", + slink, dbrType); + + slink->val = dbStateGet(slink->state); + status = conv(&slink->val, pbuffer, NULL); + + return status; +} + +static long lnkState_putValue(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + state_link *slink = CONTAINER(plink->value.json.jlink, + struct state_link, jlink); + long status; + FASTCONVERT conv = dbFastPutConvertRoutine[dbrType][DBR_LONG]; + + IFDEBUG(10) + printf("lnkState_getValue(state@%p, %d, ...)\n", + slink, dbrType); + + if (nRequest == 0) + return 0; + + status = conv(pbuffer, &slink->val, NULL); + (slink->val ? dbStateSet : dbStateClear)(slink->state); + + return status; +} + +/************************* Interface Tables *************************/ + +static lset lnkState_lset = { + 0, 1, /* not Constant, Volatile */ + lnkState_open, lnkState_remove, + NULL, NULL, NULL, + lnkState_isConn, lnkState_getDBFtype, lnkState_getElements, + lnkState_getValue, + NULL, NULL, NULL, + NULL, NULL, + NULL, NULL, + lnkState_putValue, NULL, + NULL, NULL +}; + +static jlif lnkStateIf = { + "state", lnkState_alloc, lnkState_free, + NULL, NULL, NULL, NULL, lnkState_string, + NULL, NULL, NULL, + NULL, NULL, + NULL, lnkState_get_lset, + lnkState_report, NULL +}; +epicsExportAddress(jlif, lnkStateIf); From c0d4835e6699972c95a55bc11e9fa8b0ddeebb52 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Dec 2017 23:45:35 -0600 Subject: [PATCH 014/147] lnkState: Add support for inverting the flag data Determine the truthiness of put data in its original data type. Adjust the link documentation to cover these changes. --- src/std/link/links.dbd.pod | 23 ++++++++---- src/std/link/lnkState.c | 72 +++++++++++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index 07e1023f2..9b802b513 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -137,12 +137,18 @@ link(state, lnkStateIf) =head3 dbState Link C<"state"> A dbState link is one that reads or writes a boolean value from/to a named -global flag as implemented by the dbState facility in C. +global flag as implemented by the dbState facility in C. The link +type can invert the sense of the dbState flag if desired. The value of the named flag is read or written at the time of the link I/O -operation. The boolean flag data is represented as a C that can only -hold the values zero or one; putting any non-zero numeric value to a link sets -the boolean flag value, putting a zero value clears it. +operation. When reading a flag, the value returned by the link will be zero or +one converted to the requested data type. When writing to a flag the boolean +value of the data written is determined in the originating data type. All +strings are regarded as true other than C<""> and C<"0"> which are both false. + +A link can be configured to invert the sense of the flag data by putting an +exclamation mark C before the first character of the flag's name in the link +address. These dbState flags can be accessed from the IOC Shell with various dbState commands, and are also used by the C<"sync"> Channel-Access server-side filter @@ -150,11 +156,14 @@ mechanism. =head4 Parameters -The link address must be a string providing the name of the dbState object, -which will be created when the link is initialized if it doesn't already exist. +The link address must be a string providing the name of the dbState object, with +an optional leading C charater to indicate the flag's value should be +inverted. The dbState object will be created when the link is initialized if it +doesn't already exist. -=head4 Example +=head4 Examples {state:"redBeam"} + {state:"!simEnable"} =cut diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index b1f33a552..e24773727 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -40,7 +40,8 @@ typedef long (*FASTCONVERT)(); typedef struct state_link { jlink jlink; /* embedded object */ char *name; - int val; + short val; + short invert; dbStateId state; } state_link; @@ -58,6 +59,7 @@ static jlink* lnkState_alloc(short dbfType) slink->name = NULL; slink->state = NULL; + slink->invert = 0; slink->val = 0; IFDEBUG(10) @@ -84,6 +86,11 @@ static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) IFDEBUG(10) printf("lnkState_string(state@%p, \"%.*s\")\n", slink, (int) len, val); + if (len > 1 && val[0] == '!') { + slink->invert = 1; + val++; len--; + } + slink->name = epicsStrnDup(val, len); return jlif_continue; } @@ -105,8 +112,8 @@ static void lnkState_report(const jlink *pjlink, int level, int indent) IFDEBUG(10) printf("lnkState_report(state@%p)\n", slink); - printf("%*s'state': \"%s\" = %d\n", indent, "", - slink->name, slink->val); + printf("%*s'state': \"%s\" = %s%s\n", indent, "", + slink->name, slink->invert ? "! " : "", slink->val ? "TRUE" : "FALSE"); } /*************************** lset Routines **************************/ @@ -155,7 +162,7 @@ static int lnkState_getDBFtype(const struct link *plink) IFDEBUG(10) printf("lnkState_getDBFtype(state@%p)\n", slink); - return DBF_LONG; + return DBF_SHORT; } static long lnkState_getElements(const struct link *plink, long *nelements) @@ -177,13 +184,15 @@ static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer, state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); long status; - FASTCONVERT conv = dbFastPutConvertRoutine[DBR_LONG][dbrType]; + short flag; + FASTCONVERT conv = dbFastPutConvertRoutine[DBR_SHORT][dbrType]; IFDEBUG(10) printf("lnkState_getValue(state@%p, %d, ...)\n", slink, dbrType); - slink->val = dbStateGet(slink->state); + flag = dbStateGet(slink->state); + slink->val = slink->invert ^ flag; status = conv(&slink->val, pbuffer, NULL); return status; @@ -194,20 +203,59 @@ static long lnkState_putValue(struct link *plink, short dbrType, { state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); - long status; - FASTCONVERT conv = dbFastPutConvertRoutine[dbrType][DBR_LONG]; + short val; + const char *pstr; IFDEBUG(10) - printf("lnkState_getValue(state@%p, %d, ...)\n", + printf("lnkState_putValue(state@%p, %d, ...)\n", slink, dbrType); if (nRequest == 0) return 0; - status = conv(pbuffer, &slink->val, NULL); - (slink->val ? dbStateSet : dbStateClear)(slink->state); + switch(dbrType) { + case DBR_CHAR: + case DBR_UCHAR: + val = !! *(const epicsInt8 *) pbuffer; + break; - return status; + case DBR_SHORT: + case DBR_USHORT: + val = !! *(const epicsInt16 *) pbuffer; + break; + + case DBR_LONG: + case DBR_ULONG: + val = !! *(const epicsInt32 *) pbuffer; + break; + + case DBR_INT64: + case DBR_UINT64: + val = !! *(const epicsInt64 *) pbuffer; + break; + + case DBR_FLOAT: + val = !! *(const epicsFloat32 *) pbuffer; + break; + + case DBR_DOUBLE: + val = !! *(const epicsFloat64 *) pbuffer; + break; + + case DBR_STRING: /* Only "" and "0" are FALSE */ + pstr = (const char *) pbuffer; + val = (pstr[0] != 0) && ((pstr[0] != '0') || (pstr[1] != 0)); + break; + + default: + return S_db_badDbrtype; + } + slink->val = val; + + val ^= slink->invert; + (val ? dbStateSet : dbStateClear)(slink->state); + + return 0; } /************************* Interface Tables *************************/ From 5e394e4928c3dcd408428a91e4e1adcd5ba87e3e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 20 Jan 2018 19:50:33 -0600 Subject: [PATCH 015/147] dbJLink: Handle NULL returned by jlif::alloc() better It might not mean out-of-memory, adjust error message. Add OOM and dbfType error checks to all jlif::alloc() routines. Change all IFDEBUG() in JLink types to use exported global variables. This allows debug messages to be output from the jlif::alloc() routines, since the jlink field isn't set when they're called. --- src/ioc/db/dbJLink.c | 16 ++++++++++------ src/std/link/links.dbd.pod | 38 ++++++++++++++++++++++---------------- src/std/link/lnkCalc.c | 22 +++++++++++++++++----- src/std/link/lnkConst.c | 28 ++++++++++++++++++---------- src/std/link/lnkState.c | 22 +++++++++++++++++----- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index ea054eee9..0bc8d6ba5 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -2,7 +2,7 @@ * 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. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbJLink.c */ @@ -241,25 +241,29 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { return dbjl_return(parser, jlif_stop); } - dbmfFree(link_name); - pjlink = pjlif->alloc_jlink(parser->dbfType); if (!pjlink) { - errlogPrintf("dbJLinkInit: Out of memory\n"); + errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n", + link_name); + dbmfFree(link_name); 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; } + else + pjlink->parent = NULL; + parser->pjlink = pjlink; parser->key_is_link = 0; + dbmfFree(link_name); + IFDEBUG(8) printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink); diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index 9b802b513..6eb8b77d3 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -33,15 +33,17 @@ database file syntax. =cut + link(const, lnkConstIf) +variable(lnkConst_debug, int) =head3 Constant Link C<"const"> -Constant links provide one or more values at link initalization time, but do not -return any data when their C routine is called. Most record types -support the use of constant links by calling C at -record initialization, which results in the constant value being loaded into the -target field at that time. +Constant links are input links that provide literal values at link initalization +time, but do not return any data when their C routine is called. +Most record types support the use of constant links on their input links by +calling C at record initialization, which results in +the constant value being loaded into the target field at that time. Note that for most record types (the C and C records are the main exceptions) it is pointless to set an input link to a constant link at @@ -72,14 +74,16 @@ converted to the desired double value at initialization, for example: =cut + link(calc, lnkCalcIf) +variable(lnkCalc_debug, int) =head3 Calculation Link C<"calc"> -Calculation links can perform simple mathematical expressions on scalar -(double-precision floating-point) values obtained from other link types and -return a single double-precision floating-point result. The expressions are -evaluated by the EPICS Calc engine, and up to 12 inputs can be provided. +Calculation links are input links that can evaluate mathematical expressions on +scalar (double- precision floating-point) values obtained from child links, and +return a double-precision floating-point result. The expressions are evaluated +by the EPICS Calc engine, and up to 12 inputs can be provided. =head4 Parameters @@ -132,13 +136,15 @@ atomically with the value of the input argument. =cut + link(state, lnkStateIf) +variable(lnkState_debug, int) =head3 dbState Link C<"state"> -A dbState link is one that reads or writes a boolean value from/to a named -global flag as implemented by the dbState facility in C. The link -type can invert the sense of the dbState flag if desired. +A dbState link is one that gets or puts a boolean value from/to a named global +flag as implemented by the dbState facility in C. The link type can +invert the sense of the dbState flag during the get or put if desired. The value of the named flag is read or written at the time of the link I/O operation. When reading a flag, the value returned by the link will be zero or @@ -156,10 +162,10 @@ mechanism. =head4 Parameters -The link address must be a string providing the name of the dbState object, with -an optional leading C charater to indicate the flag's value should be -inverted. The dbState object will be created when the link is initialized if it -doesn't already exist. +The link takes a single parameter which must be a string, providing the name of +the dbState object, with an optional leading C character to indicate that the +flag's value should be inverted. The dbState object will be created when the +link is initialized if it doesn't already exist. =head4 Examples diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index c63495df0..87f3b4a3e 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -40,7 +40,10 @@ typedef long (*FASTCONVERT)(); -#define IFDEBUG(n) if(clink->jlink.debug) +int lnkCalc_debug; +epicsExportAddress(int, lnkCalc_debug); + +#define IFDEBUG(n) if (lnkCalc_debug >= (n)) typedef struct calc_link { jlink jlink; /* embedded object */ @@ -77,10 +80,21 @@ static lset lnkCalc_lset; static jlink* lnkCalc_alloc(short dbfType) { - calc_link *clink = calloc(1, sizeof(struct calc_link)); + calc_link *clink; IFDEBUG(10) - printf("lnkCalc_alloc()\n"); + printf("lnkCalc_alloc(%d)\n", dbfType); + + if (dbfType != DBF_INLINK) { + errlogPrintf("lnkCalc: Only works with input links\n"); + return NULL; + } + + clink = calloc(1, sizeof(struct calc_link)); + if (!clink) { + errlogPrintf("lnkCalc: calloc() failed.\n"); + return NULL; + } clink->nArgs = 0; clink->pstate = ps_init; @@ -355,8 +369,6 @@ static void lnkCalc_end_child(jlink *parent, jlink *child) static struct lset* lnkCalc_get_lset(const jlink *pjlink) { - calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) printf("lnkCalc_get_lset(calc@%p)\n", pjlink); diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c index c2eb032c1..881bf6bff 100644 --- a/src/std/link/lnkConst.c +++ b/src/std/link/lnkConst.c @@ -2,7 +2,7 @@ * 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. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* lnkConst.c */ @@ -22,7 +22,10 @@ #include "epicsExport.h" -#define IFDEBUG(n) if (clink->jlink.debug) +int lnkConst_debug; +epicsExportAddress(int, lnkConst_debug); + +#define IFDEBUG(n) if (lnkConst_debug >= (n)) typedef long (*FASTCONVERT)(); @@ -48,10 +51,21 @@ static lset lnkConst_lset; static jlink* lnkConst_alloc(short dbfType) { - const_link *clink = calloc(1, sizeof(*clink)); + const_link *clink; IFDEBUG(10) - printf("lnkConst_alloc()\n"); + printf("lnkConst_alloc(%d)\n", dbfType); + + if (dbfType != DBF_INLINK) { + errlogPrintf("lnkConst: Only works with input links\n"); + return NULL; + } + + clink = calloc(1, sizeof(*clink)); + if (!clink) { + errlogPrintf("lnkConst: calloc() failed.\n"); + return NULL; + } clink->type = s0; clink->nElems = 0; @@ -146,7 +160,6 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) static jlif_result lnkConst_boolean(jlink *pjlink, int val) { - const_link *clink = CONTAINER(pjlink, const_link, jlink); IFDEBUG(10) printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val); @@ -276,8 +289,6 @@ static jlif_result lnkConst_start_array(jlink *pjlink) static jlif_result lnkConst_end_array(jlink *pjlink) { - const_link *clink = CONTAINER(pjlink, const_link, jlink); - IFDEBUG(10) printf("lnkConst_end_array(const@%p)\n", pjlink); @@ -286,8 +297,6 @@ static jlif_result lnkConst_end_array(jlink *pjlink) static struct lset* lnkConst_get_lset(const jlink *pjlink) { - const_link *clink = CONTAINER(pjlink, const_link, jlink); - IFDEBUG(10) printf("lnkConst_get_lset(const@%p)\n", pjlink); @@ -629,4 +638,3 @@ static jlif lnkConstIf = { lnkConst_report, NULL }; epicsExportAddress(jlif, lnkConstIf); - diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index e24773727..160dc78ca 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -35,7 +35,10 @@ typedef long (*FASTCONVERT)(); -#define IFDEBUG(n) if(slink->jlink.debug) +int lnkState_debug; +epicsExportAddress(int, lnkState_debug); + +#define IFDEBUG(n) if (lnkState_debug >= (n)) typedef struct state_link { jlink jlink; /* embedded object */ @@ -52,10 +55,21 @@ static lset lnkState_lset; static jlink* lnkState_alloc(short dbfType) { - state_link *slink = calloc(1, sizeof(struct state_link)); + state_link *slink; IFDEBUG(10) - printf("lnkState_alloc()\n"); + printf("lnkState_alloc(%d)\n", dbfType); + + if (dbfType == DBF_FWDLINK) { + errlogPrintf("lnkState: DBF_FWDLINK not supported\n"); + return NULL; + } + + slink = calloc(1, sizeof(struct state_link)); + if (!slink) { + errlogPrintf("lnkState: calloc() failed.\n"); + return NULL; + } slink->name = NULL; slink->state = NULL; @@ -97,8 +111,6 @@ static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) static struct lset* lnkState_get_lset(const jlink *pjlink) { - state_link *slink = CONTAINER(pjlink, struct state_link, jlink); - IFDEBUG(10) printf("lnkState_get_lset(state@%p)\n", pjlink); From 1fa5d9d3b633f5b6fcabe8c1b41aeb1430847837 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 20 Jan 2018 20:01:31 -0600 Subject: [PATCH 016/147] Cleanup warnings in lnkConst.c --- src/std/link/lnkConst.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c index 881bf6bff..ee93830ff 100644 --- a/src/std/link/lnkConst.c +++ b/src/std/link/lnkConst.c @@ -583,8 +583,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, static long lnkConst_getNelements(const struct link *plink, long *nelements) { - const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink); - IFDEBUG(10) printf("lnkConst_getNelements(const@%p, (%ld))\n", plink->value.json.jlink, *nelements); @@ -596,8 +594,6 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements) static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer, long *pnRequest) { - const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink); - IFDEBUG(10) printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n", plink->value.json.jlink, dbrType, pbuffer, From 20404003bf89517863753a8a9bd10ac95e219fca Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 20 Jan 2018 22:48:20 -0600 Subject: [PATCH 017/147] More timestamp support for lnkCalc Link now remembers the last timestamp read if a timestamp input was nominated, and implements getTimestamp() to return this. Also displays the timestamp value in the report output. --- src/std/link/lnkCalc.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index 87f3b4a3e..cc08e84f8 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -26,6 +26,7 @@ #include "epicsAssert.h" #include "epicsString.h" #include "epicsTypes.h" +#include "epicsTime.h" #include "dbAccessDefs.h" #include "dbCommon.h" #include "dbConvertFast.h" @@ -70,6 +71,7 @@ typedef struct calc_link { short tinp; struct link inp[CALCPERFORM_NARGS]; double arg[CALCPERFORM_NARGS]; + epicsTimeStamp time; double val; } calc_link; @@ -400,9 +402,13 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent) printf("%*s Minor expression: \"%s\"\n", indent, "", clink->minor); - if (clink->tinp >= 0 && clink->tinp < clink->nArgs) - printf("%*s Timestamp input \"%c\"\n", indent, "", - clink->tinp + 'A'); + if (clink->tinp >= 0) { + char timeStr[40]; + epicsTimeToStrftime(timeStr, 40, "%Y-%m-%d %H:%M:%S.%09f", + &clink->time); + printf("%*s Timestamp input %c: %s\n", indent, "", + clink->tinp + 'A', timeStr); + } for (i = 0; i < clink->nArgs; i++) { struct link *plink = &clink->inp[i]; @@ -564,14 +570,17 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer, struct link *child = &clink->inp[i]; long nReq = 1; - if (i == clink->tinp && - dbLinkIsConstant(&prec->tsel) && - prec->tse == epicsTimeEventDeviceTime) { - struct lcvt vt = {&clink->arg[i], &prec->time}; + if (i == clink->tinp) { + struct lcvt vt = {&clink->arg[i], &clink->time}; status = dbLinkDoLocked(child, readLocked, &vt); if (status == S_db_noLSET) status = readLocked(child, &vt); + + if (dbLinkIsConstant(&prec->tsel) && + prec->tse == epicsTimeEventDeviceTime) { + prec->time = clink->time; + } } else dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq); @@ -663,6 +672,22 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status, return 0; } +static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstamp) +{ + calc_link *clink = CONTAINER(plink->value.json.jlink, + struct calc_link, jlink); + + IFDEBUG(10) + printf("lnkCalc_getTimestamp(calc@%p)\n", clink); + + if (clink->tinp >= 0) { + *pstamp = clink->time; + return 0; + } + + return -1; +} + static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv) { return rtn(plink, priv); @@ -679,7 +704,7 @@ static lset lnkCalc_lset = { lnkCalc_getValue, NULL, NULL, NULL, lnkCalc_getPrecision, lnkCalc_getUnits, - lnkCalc_getAlarm, NULL, + lnkCalc_getAlarm, lnkCalc_getTimestamp, NULL, NULL, NULL, doLocked }; From d87ac0319b6409a169e7a5fcebb8534792094e40 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 30 Sep 2017 15:51:51 -0500 Subject: [PATCH 018/147] Replace the base:jlinkDebug info-item with a global variable The info item only works in dbPutString() which means dbLoadRecords() but not dbPutField(). --- src/ioc/db/dbJLink.c | 20 ++++++++++++++++---- src/ioc/dbStatic/dbStaticLib.c | 2 -- src/ioc/dbStatic/dbStaticPvt.h | 3 +-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index 0bc8d6ba5..feedf35a1 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -26,7 +26,9 @@ #include "dbStaticLib.h" #include "link.h" -#define IFDEBUG(n) if(parser->parse_debug) +int dbJLinkDebug = 0; + +#define IFDEBUG(n) if (dbJLinkDebug >= (n)) typedef struct parseContext { jlink *pjlink; @@ -34,7 +36,6 @@ typedef struct parseContext { short dbfType; short jsonDepth; unsigned key_is_link:1; - unsigned parse_debug:1; unsigned lset_debug:1; } parseContext; @@ -59,6 +60,9 @@ static int dbjl_return(parseContext *parser, jlif_result result) { pjlink->pif->free_jlink(pjlink); } + IFDEBUG(10) + printf(" returning %d %s\n", result, + result == jlif_stop ? "*** STOP ***" : "Continue"); return result; } @@ -352,7 +356,6 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, 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) @@ -369,8 +372,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, return S_db_noMemory; ys = yajl_parse(yh, (const unsigned char *) json, jlen); - if (ys == yajl_status_ok) + IFDEBUG(10) + printf("dbJLinkInit: yajl_parse() returned %d\n", ys); + + if (ys == yajl_status_ok) { ys = yajl_complete_parse(yh); + IFDEBUG(10) + printf("dbJLinkInit: yajl_complete_parse() returned %d\n", ys); + } switch (ys) { unsigned char *err; @@ -382,6 +391,9 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, break; case yajl_status_error: + IFDEBUG(10) + printf(" jsonDepth=%d, product=%p, pjlink=%p\n", + parser->jsonDepth, parser->product, parser->pjlink); err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen); errlogPrintf("dbJLinkInit: %s\n", err); yajl_free_error(yh, err); diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 6e9997ad1..7549a0da6 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -2613,8 +2613,6 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring) if(dbFindInfo(&infoentry, "base:lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0) opts |= LINK_DEBUG_LSET; - if(dbFindInfo(&infoentry, "base:jlinkDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0) - opts |= LINK_DEBUG_JPARSE; dbFinishEntry(&infoentry); } diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h index 58d32c28c..b1ad70de6 100644 --- a/src/ioc/dbStatic/dbStaticPvt.h +++ b/src/ioc/dbStatic/dbStaticPvt.h @@ -5,7 +5,7 @@ * 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. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbStaticPvt.h */ /* @@ -60,7 +60,6 @@ typedef struct dbLinkInfo { long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec); #define LINK_DEBUG_LSET 1 -#define LINK_DEBUG_JPARSE 2 /* Parse link string. no record locks needed. * on success caller must free pinfo->target From 54c47f02de8813b578ded1c48c080d7eef347367 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 30 Sep 2017 15:52:21 -0500 Subject: [PATCH 019/147] Export dbJLinkDebug as a shell variable --- src/ioc/db/dbJLink.c | 4 +++- src/ioc/misc/dbCore.dbd | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index feedf35a1..13470fe9a 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -25,8 +25,10 @@ #include "dbLock.h" #include "dbStaticLib.h" #include "link.h" +#include "epicsExport.h" -int dbJLinkDebug = 0; +epicsShareDef int dbJLinkDebug = 0; +epicsExportAddress(int, dbJLinkDebug); #define IFDEBUG(n) if (dbJLinkDebug >= (n)) diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index 921b3818e..6bd0b6bab 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -12,6 +12,9 @@ variable(asCaDebug,int) # CA server debug flag (very verbose) range[0,5] variable(CASDEBUG,int) +# Link parsing debug +variable(dbJLinkDebug,int) + # Static database access variables variable(dbRecordsOnceOnly,int) variable(dbRecordsAbcSorted,int) From 8f64af96fd75dab7ae130184547c4572448c94ef Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 5 Mar 2018 20:53:45 -0600 Subject: [PATCH 020/147] Remove final traces of link debug info tags --- src/ioc/db/dbAccess.c | 3 +-- src/ioc/db/dbJLink.c | 7 ++----- src/ioc/db/dbJLink.h | 8 +++----- src/ioc/db/test/dbPutLinkTest.c | 4 ++-- src/ioc/dbStatic/dbStaticLib.c | 19 ++++--------------- src/ioc/dbStatic/dbStaticPvt.h | 4 +--- 6 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 973a66836..6e43959e3 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -1036,7 +1036,7 @@ static long dbPutFieldLink(DBADDR *paddr, return S_db_badDbrtype; } - status = dbParseLink(pstring, pfldDes->field_type, &link_info, 0); + status = dbParseLink(pstring, pfldDes->field_type, &link_info); if (status) return status; @@ -1343,4 +1343,3 @@ done: paddr->pfield = pfieldsave; return status; } - diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index 13470fe9a..10a4e62d2 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -38,7 +38,6 @@ typedef struct parseContext { short dbfType; short jsonDepth; unsigned key_is_link:1; - unsigned lset_debug:1; } parseContext; #define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine) @@ -87,7 +86,6 @@ static int dbjl_value(parseContext *parser, jlif_result result) { } else if (parent->pif->end_child) { parent->pif->end_child(parent, pjlink); } - pjlink->debug = 0; parser->pjlink = parent; @@ -257,7 +255,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { pjlink->pif = pjlif; pjlink->parseDepth = 0; - pjlink->debug = !!parser->lset_debug; + if (parser->pjlink) { /* We're starting a child link, save its parent */ pjlink->parent = parser->pjlink; @@ -345,7 +343,7 @@ static yajl_callbacks dbjl_callbacks = { }; long dbJLinkParse(const char *json, size_t jlen, short dbfType, - jlink **ppjlink, unsigned opts) + jlink **ppjlink) { parseContext context, *parser = &context; yajl_alloc_funcs dbjl_allocs; @@ -358,7 +356,6 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, parser->dbfType = dbfType; parser->jsonDepth = 0; parser->key_is_link = 0; - parser->lset_debug = !!(opts&LINK_DEBUG_LSET); IFDEBUG(10) printf("dbJLinkInit(\"%.*s\", %d, %p)\n", diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h index 61b59670b..954b69be5 100644 --- a/src/ioc/db/dbJLink.h +++ b/src/ioc/db/dbJLink.h @@ -2,7 +2,7 @@ * 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. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbJLink.h */ @@ -35,7 +35,6 @@ 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; @@ -98,7 +97,7 @@ typedef struct jlif { 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) + * dbJLinkReport(child, level-1, indent+4) * for each child. */ @@ -113,7 +112,7 @@ typedef struct jlif { } jlif; epicsShareFunc long dbJLinkParse(const char *json, size_t len, short dbfType, - jlink **ppjlink, unsigned opts); + jlink **ppjlink); epicsShareFunc long dbJLinkInit(struct link *plink); epicsShareFunc void dbJLinkFree(jlink *); @@ -130,4 +129,3 @@ epicsShareFunc long dbJLinkMapAll(char *recname, jlink_map_fn rtn, void *ctx); #endif #endif /* INC_dbJLink_H */ - diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index d6748a9eb..00634fd66 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -87,7 +87,7 @@ static void testLinkParse(void) for (;td->str; td++) { int i, N; testDiag("Parsing \"%s\"", td->str); - testOk(dbParseLink(td->str, DBF_INLINK, &info, 0) == 0, "Parser returned OK"); + testOk(dbParseLink(td->str, DBF_INLINK, &info) == 0, "Parser returned OK"); if (!testOk(info.ltype == td->info.ltype, "Link type value")) testDiag("Expected %d, got %d", td->info.ltype, info.ltype); if (td->info.target) @@ -147,7 +147,7 @@ static void testLinkFailParse(void) eltc(1); for(;*td; td++) { - testOk(dbParseLink(*td, DBF_INLINK, &info, 0) == S_dbLib_badField, + testOk(dbParseLink(*td, DBF_INLINK, &info) == S_dbLib_badField, "dbParseLink correctly rejected \"%s\"", *td); } diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 7549a0da6..4f14c5596 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -2205,7 +2205,7 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec) if(!plink->text) continue; - if(dbParseLink(plink->text, pflddes->field_type, &link_info, 0)!=0) { + if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) { /* This was already parsed once when ->text was set. * Any syntax error messages were printed at that time. */ @@ -2234,7 +2234,7 @@ void dbFreeLinkInfo(dbLinkInfo *pinfo) pinfo->target = NULL; } -long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts) +long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo) { char *pstr; size_t len; @@ -2270,7 +2270,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts) /* Check for braces => JSON */ if (*str == '{' && str[len-1] == '}') { - if (dbJLinkParse(str, len, ftype, &pinfo->jlink, opts)) + if (dbJLinkParse(str, len, ftype, &pinfo->jlink)) goto fail; pinfo->ltype = JSON_LINK; @@ -2605,19 +2605,8 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring) case DBF_FWDLINK: { dbLinkInfo link_info; DBLINK *plink = (DBLINK *)pfield; - DBENTRY infoentry; - unsigned opts = 0; - if(pdbentry->precnode && ellCount(&pdbentry->precnode->infoList)) { - dbCopyEntryContents(pdbentry, &infoentry); - - if(dbFindInfo(&infoentry, "base:lsetDebug")==0 && epicsStrCaseCmp(dbGetInfoString(&infoentry), "YES")==0) - opts |= LINK_DEBUG_LSET; - - dbFinishEntry(&infoentry); - } - - status = dbParseLink(pstring, pflddes->field_type, &link_info, opts); + status = dbParseLink(pstring, pflddes->field_type, &link_info); if (status) break; if (plink->type==CONSTANT && plink->value.constantStr==NULL) { diff --git a/src/ioc/dbStatic/dbStaticPvt.h b/src/ioc/dbStatic/dbStaticPvt.h index b1ad70de6..85fc02217 100644 --- a/src/ioc/dbStatic/dbStaticPvt.h +++ b/src/ioc/dbStatic/dbStaticPvt.h @@ -59,12 +59,10 @@ typedef struct dbLinkInfo { long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec); -#define LINK_DEBUG_LSET 1 - /* Parse link string. no record locks needed. * on success caller must free pinfo->target */ -epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo, unsigned opts); +epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo); /* Check if link type allow the parsed link value pinfo * to be assigned to the given link. * Record containing plink must be locked. From 97ea68d40c65d4d1e5ec2e36050475204ca69c27 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 9 Mar 2018 22:42:59 -0600 Subject: [PATCH 021/147] Added DBF_OUTLINK support to lnkCalc New out key specifying a child link to put the calculated result to. --- src/std/link/links.dbd.pod | 35 +++++++- src/std/link/lnkCalc.c | 168 ++++++++++++++++++++++++++++++++----- 2 files changed, 180 insertions(+), 23 deletions(-) diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index 6eb8b77d3..6b48c13fb 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -80,10 +80,30 @@ variable(lnkCalc_debug, int) =head3 Calculation Link C<"calc"> -Calculation links are input links that can evaluate mathematical expressions on -scalar (double- precision floating-point) values obtained from child links, and -return a double-precision floating-point result. The expressions are evaluated -by the EPICS Calc engine, and up to 12 inputs can be provided. +A calculation link is an input link that can evaluate mathematical expressions +on scalar (double-precision floating-point) values obtained from up to 12 child +input links, and returns a double-precision floating-point result. The +expression is evaluated by the EPICS Calc engine, and the result is returned as +the value of the link. + +Two additional expressions may also be provided and are evaluated to determine +whether the record owning the link should be placed in alarm state. In both +cases the result of the main calculation is available to these expressions as +C (attempts to assign to C inside either expression will have no +lasting effect). If the C expression evaluates to a non-zero value the +record will be placed in C alarm. If not and the C expression +evaluates to non-zero the record will be placed in C alarm state. + +A calculation link can also be an output link, with the scalar output value +being converted to a double and provided to the expression as C. Up to 12 +additional input links can also be read and provided to the expression as above. +The result of the calculation is forwarded to a child output link specified in +the link's C parameter. + +For an output link the main expression is actually optional; if not provided the +converted value will be forwarded to the output link unchanged. The two alarm +expressions may still be used to put the output link into alarm state as +described above. =head4 Parameters @@ -94,6 +114,7 @@ The link address is a JSON map with the following keys: =item expr The primary expression to be evaluated, given as a string. +This is optional for output links, required for input links. =item major @@ -110,6 +131,12 @@ to the inputs C, C, C, ... C. Each input argument may be either a numeric literal or an embedded JSON link inside C<{}> braces. The same input values are provided to the two alarm expressions as to the primary expression. +=item out + +A JSON link inside C<{}> braces which specifies the destination of C +operations after any expressions have been evaluated. +This key is required for output links, not used by input links. + =item units An optional string specifying the engineering units for the result of the diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index cc08e84f8..de76948a9 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -6,13 +6,9 @@ \*************************************************************************/ /* lnkCalc.c */ -/* Current usage - * {calc:{expr:"A", args:[{...}, ...]}} +/* Usage + * {calc:{expr:"A*B", args:[{...}, ...], units:"mm"}} * First link in 'args' is 'A', second is 'B', and so forth. - * - * TODO: - * Support setting individual input links instead of the args list. - * {calc:{expr:"K", K:{...}}} */ #include @@ -49,10 +45,11 @@ epicsExportAddress(int, lnkCalc_debug); typedef struct calc_link { jlink jlink; /* embedded object */ int nArgs; + short dbfType; enum { ps_init, ps_expr, ps_major, ps_minor, - ps_args, + ps_args, ps_out, ps_prec, ps_units, ps_time, @@ -70,6 +67,7 @@ typedef struct calc_link { char *units; short tinp; struct link inp[CALCPERFORM_NARGS]; + struct link out; double arg[CALCPERFORM_NARGS]; epicsTimeStamp time; double val; @@ -87,8 +85,8 @@ static jlink* lnkCalc_alloc(short dbfType) IFDEBUG(10) printf("lnkCalc_alloc(%d)\n", dbfType); - if (dbfType != DBF_INLINK) { - errlogPrintf("lnkCalc: Only works with input links\n"); + if (dbfType == DBF_FWDLINK) { + errlogPrintf("lnkCalc: No support for forward links\n"); return NULL; } @@ -99,6 +97,7 @@ static jlink* lnkCalc_alloc(short dbfType) } clink->nArgs = 0; + clink->dbfType = dbfType; clink->pstate = ps_init; clink->prec = 15; /* standard value for a double */ clink->tinp = -1; @@ -120,6 +119,8 @@ static void lnkCalc_free(jlink *pjlink) for (i = 0; i < clink->nArgs; i++) dbJLinkFree(clink->inp[i].value.json.jlink); + dbJLinkFree(clink->out.value.json.jlink); + free(clink->expr); free(clink->major); free(clink->minor); @@ -253,7 +254,7 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) IFDEBUG(10) printf("lnkCalc_start_map(calc@%p)\n", clink); - if (clink->pstate == ps_args) + if (clink->pstate == ps_args || clink->pstate == ps_out) return jlif_key_child_link; if (clink->pstate != ps_init) { @@ -271,7 +272,21 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) IFDEBUG(10) printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key); - if (len == 4) { + /* FIXME: These errors messages are wrong when a key is duplicated. + * The key is known, we just don't allow it more than once. + */ + + if (len == 3) { + if (!strncmp(key, "out", len) && + clink->dbfType == DBF_OUTLINK && + clink->out.type == 0) + clink->pstate = ps_out; + else { + errlogPrintf("lnkCalc: Unknown key \"%.3s\"\n", key); + return jlif_stop; + } + } + else if (len == 4) { if (!strncmp(key, "expr", len) && !clink->post_expr) clink->pstate = ps_expr; else if (!strncmp(key, "args", len) && !clink->nArgs) @@ -314,8 +329,14 @@ static jlif_result lnkCalc_end_map(jlink *pjlink) if (clink->pstate == ps_error) return jlif_stop; - else if (!clink->post_expr) { - errlogPrintf("lnkCalc: no expression ('expr' key)\n"); + else if (clink->dbfType == DBF_INLINK && + !clink->post_expr) { + errlogPrintf("lnkCalc: No expression ('expr' key)\n"); + return jlif_stop; + } + else if (clink->dbfType == DBF_OUTLINK && + clink->out.type != JSON_LINK) { + errlogPrintf("lnkCalc: No output link ('out' key)\n"); return jlif_stop; } @@ -355,15 +376,27 @@ static void lnkCalc_end_child(jlink *parent, jlink *child) calc_link *clink = CONTAINER(parent, struct calc_link, jlink); struct link *plink; - if (clink->nArgs == CALCPERFORM_NARGS) { - dbJLinkFree(child); - errlogPrintf("lnkCalc: Too many input args, limit is %d\n", - CALCPERFORM_NARGS); + if (clink->pstate == ps_args) { + if (clink->nArgs == CALCPERFORM_NARGS) { + errlogPrintf("lnkCalc: Too many input args, limit is %d\n", + CALCPERFORM_NARGS); + goto errOut; + } + + plink = &clink->inp[clink->nArgs++]; + } + else if (clink->pstate == ps_out) { + plink = &clink->out; + } + else { + errlogPrintf("lnkCalc: Unexpected child link, parser state = %d\n", + clink->pstate); +errOut: clink->pstate = ps_error; + dbJLinkFree(child); return; } - plink = &clink->inp[clink->nArgs++]; plink->type = JSON_LINK; plink->value.json.string = NULL; plink->value.json.jlink = child; @@ -421,6 +454,12 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent) if (child) dbJLinkReport(child, level - 1, indent + 4); } + + if (clink->out.type == JSON_LINK) { + printf("%*s Output:\n", indent, ""); + + dbJLinkReport(clink->out.value.json.jlink, level - 1, indent + 4); + } } } @@ -439,6 +478,10 @@ long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) if (status) return status; } + + if (clink->out.type == JSON_LINK) { + return dbJLinkMapChildren(&clink->out, rtn, ctx); + } return 0; } @@ -460,6 +503,10 @@ static void lnkCalc_open(struct link *plink) dbJLinkInit(child); dbLoadLink(child, DBR_DOUBLE, &clink->arg[i]); } + + if (clink->out.type == JSON_LINK) { + dbJLinkInit(&clink->out); + } } static void lnkCalc_remove(struct dbLocker *locker, struct link *plink) @@ -477,6 +524,10 @@ static void lnkCalc_remove(struct dbLocker *locker, struct link *plink) dbRemoveLink(locker, child); } + if (clink->out.type == JSON_LINK) { + dbRemoveLink(locker, &clink->out); + } + free(clink->expr); free(clink->major); free(clink->minor); @@ -506,6 +557,14 @@ static int lnkCalc_isConn(const struct link *plink) connected = 0; } + if (clink->out.type == JSON_LINK) { + struct link *child = &clink->out; + + if (dbLinkIsVolatile(child) && + !dbIsLinkConnected(child)) + connected = 0; + } + return connected; } @@ -626,6 +685,77 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer, return status; } +static long lnkCalc_putValue(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + calc_link *clink = CONTAINER(plink->value.json.jlink, + struct calc_link, jlink); + dbCommon *prec = plink->precord; + int i; + long status; + FASTCONVERT conv = dbFastGetConvertRoutine[dbrType][DBR_DOUBLE]; + + IFDEBUG(10) + printf("lnkCalc_putValue(calc@%p, %d, ...)\n", clink, dbrType); + + /* Any link errors will trigger a LINK/INVALID alarm in the child link */ + for (i = 0; i < clink->nArgs; i++) { + struct link *child = &clink->inp[i]; + long nReq = 1; + + if (i == clink->tinp) { + struct lcvt vt = {&clink->arg[i], &clink->time}; + + status = dbLinkDoLocked(child, readLocked, &vt); + if (status == S_db_noLSET) + status = readLocked(child, &vt); + + if (dbLinkIsConstant(&prec->tsel) && + prec->tse == epicsTimeEventDeviceTime) { + prec->time = clink->time; + } + } + else + dbGetLink(child, DBR_DOUBLE, &clink->arg[i], NULL, &nReq); + } + clink->stat = 0; + clink->sevr = 0; + + /* Get the value being output as VAL */ + status = conv(pbuffer, &clink->val, NULL); + + if (!status && clink->post_expr) + status = calcPerform(clink->arg, &clink->val, clink->post_expr); + + if (!status && clink->post_major) { + double alval = clink->val; + + status = calcPerform(clink->arg, &alval, clink->post_major); + if (!status && alval) { + clink->stat = LINK_ALARM; + clink->sevr = MAJOR_ALARM; + recGblSetSevr(prec, clink->stat, clink->sevr); + } + } + + if (!status && clink->post_minor) { + double alval = clink->val; + + status = calcPerform(clink->arg, &alval, clink->post_minor); + if (!status && alval) { + clink->stat = LINK_ALARM; + clink->sevr = MINOR_ALARM; + recGblSetSevr(prec, clink->stat, clink->sevr); + } + } + + if (!status) { + status = dbPutLink(&clink->out, DBR_DOUBLE, &clink->val, 1); + } + + return status; +} + static long lnkCalc_getPrecision(const struct link *plink, short *precision) { calc_link *clink = CONTAINER(plink->value.json.jlink, @@ -705,7 +835,7 @@ static lset lnkCalc_lset = { NULL, NULL, NULL, lnkCalc_getPrecision, lnkCalc_getUnits, lnkCalc_getAlarm, lnkCalc_getTimestamp, - NULL, NULL, + lnkCalc_putValue, NULL, NULL, doLocked }; From ca2003bb6338e9ee153fdd7cbc6e52328946f476 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 31 Mar 2018 15:42:35 +0100 Subject: [PATCH 022/147] dbLink: Clarify meaning of lset isConstant and isVolatile flags Modify dbIsLinkConnected() to check lset->isVolatile first. --- src/ioc/db/dbLink.c | 13 ++++++++++++- src/ioc/db/dbLink.h | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c index c90dcb3df..ed46a9b51 100644 --- a/src/ioc/db/dbLink.c +++ b/src/ioc/db/dbLink.c @@ -265,8 +265,19 @@ int dbIsLinkConnected(const struct link *plink) { lset *plset = plink->lset; - if (!plset || !plset->isConnected) + if (!plset) return FALSE; + if (!plset->isVolatile) + return TRUE; + + if (!plset->isConnected) { + struct dbCommon *precord = plink->precord; + + errlogPrintf("dbLink: Link type for '%s.%s' is volatile but has no" + " lset::isConnected() method\n", + precord->name, link_field_name(plink)); + return FALSE; + } return plset->isConnected(plink); } diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h index ad4ac2f45..d6f39ca36 100644 --- a/src/ioc/db/dbLink.h +++ b/src/ioc/db/dbLink.h @@ -31,8 +31,8 @@ typedef long (*dbLinkUserCallback)(struct link *plink, void *priv); typedef struct lset { /* Characteristics of the link type */ - const unsigned isConstant:1; - const unsigned isVolatile:1; + const unsigned isConstant:1; /* 1 means value doesn't change */ + const unsigned isVolatile:1; /* 0 means link always connected */ /* Activation */ void (*openLink)(struct link *plink); From c2c32e58766f6cc6878f12d714fcb9ffa2710809 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 31 Mar 2018 15:48:58 +0100 Subject: [PATCH 023/147] lnkState: Mark as non-volatile, remove lset::isConnected() method --- src/std/link/lnkState.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index 160dc78ca..8792a1f64 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -155,17 +155,6 @@ static void lnkState_remove(struct dbLocker *locker, struct link *plink) plink->value.json.jlink = NULL; } -static int lnkState_isConn(const struct link *plink) -{ - state_link *slink = CONTAINER(plink->value.json.jlink, - struct state_link, jlink); - - IFDEBUG(10) - printf("lnkState_isConn(state@%p)\n", slink); - - return !! slink->state; -} - static int lnkState_getDBFtype(const struct link *plink) { state_link *slink = CONTAINER(plink->value.json.jlink, @@ -273,10 +262,10 @@ static long lnkState_putValue(struct link *plink, short dbrType, /************************* Interface Tables *************************/ static lset lnkState_lset = { - 0, 1, /* not Constant, Volatile */ + 0, 0, /* not constant, always connected */ lnkState_open, lnkState_remove, NULL, NULL, NULL, - lnkState_isConn, lnkState_getDBFtype, lnkState_getElements, + NULL, lnkState_getDBFtype, lnkState_getElements, lnkState_getValue, NULL, NULL, NULL, NULL, NULL, From 7cef334b64899bb1b3040d6875fb723ca9da9578 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 25 Apr 2018 21:42:44 -0500 Subject: [PATCH 024/147] Added C++ extern "C" wrapper to dbState.h --- src/ioc/db/dbState.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ioc/db/dbState.h b/src/ioc/db/dbState.h index abd23259e..c7cd81c52 100644 --- a/src/ioc/db/dbState.h +++ b/src/ioc/db/dbState.h @@ -15,6 +15,10 @@ #include "shareLib.h" +#ifdef __cplusplus +extern "C" { +#endif + /** @file dbState.h * @brief Generic IOC state facility * @@ -89,4 +93,9 @@ epicsShareFunc void dbStateShow(dbStateId id, unsigned int level); */ epicsShareFunc void dbStateShowAll(unsigned int level); + +#ifdef __cplusplus +} +#endif + #endif // INCdbStateH From 877d38e79a5653cd530b0dfedb469387cdce5141 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 2 May 2018 00:06:12 -0500 Subject: [PATCH 025/147] Added Doxygen annotations for the Link Support API Haven't actually tried processing them yet though. --- src/ioc/db/dbLink.h | 298 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 291 insertions(+), 7 deletions(-) diff --git a/src/ioc/db/dbLink.h b/src/ioc/db/dbLink.h index d6f39ca36..f9ea5e2ff 100644 --- a/src/ioc/db/dbLink.h +++ b/src/ioc/db/dbLink.h @@ -27,54 +27,337 @@ extern "C" { struct dbLocker; +/** @file dbLink.h + * @brief Link Support API + * + * Link support run-time API, all link types provide an lset which is used by + * the IOC database to control and operate the link. This file also declares the + * dbLink routines that IOC, record and device code can call to perform link + * operations. + */ + +/** @brief callback routine for locked link operations + * + * Called by the lset::doLocked method to permit multiple link operations + * while the link instance is locked. + * + * @param plink the link + * @param priv context for the callback routine + */ typedef long (*dbLinkUserCallback)(struct link *plink, void *priv); +/** @brief Link Support Entry Table + * + * This structure provides information about and methods for an individual link + * type. A pointer to this structure is included in every link's lset field, and + * is used to perform operations on the link. For JSON links the pointer is + * obtained by calling pjlink->pif->get_lset() at link initialization time, + * immediately before calling dbLinkOpen() to activate the link. + */ typedef struct lset { /* Characteristics of the link type */ - const unsigned isConstant:1; /* 1 means value doesn't change */ - const unsigned isVolatile:1; /* 0 means link always connected */ - /* Activation */ + /** @brief link constancy + * + * 1 means this is a constant link type whose value doesn't change. + * The link's value will be obtained using one of the methods loadScalar, + * loadLS or loadArray. + */ + const unsigned isConstant:1; + + /** @brief link volatility + * + * 0 means the link is always connected. + */ + const unsigned isVolatile:1; + + /** @brief activate link + * + * Optional, called whenever a JSON link is initialized or added at runtime. + * + * @param plink the link + */ void (*openLink)(struct link *plink); - /* Destructor */ + /** @brief deactivate link + * + * Optional, called whenever a link address is changed at runtime, or the + * IOC is shutting down. + * + * @param locker + * @param plink the link + */ void (*removeLink)(struct dbLocker *locker, struct link *plink); - /* Const init, data type hinting */ + /* Constant link initialization and data type hinting */ + + /** @brief load constant scalar from link type + * + * Usually called during IOC initialization, constant link types must copy a + * scalar value of the indicated data type to the buffer provided and return + * 0. A non-constant link type can use this method call as an early hint + * that subsequent calls to dbGetLink() will request scalar data of the + * indicated type, although the type might change. + * + * @param plink the link + * @param dbrType data type code + * @param pbuffer where to put the value + * @returns 0 if a value was loaded, non-zero otherwise + */ long (*loadScalar)(struct link *plink, short dbrType, void *pbuffer); + + /** @brief load constant long string from link type + * + * Usually called during IOC initialization, constant link types must copy a + * nil-terminated string up to size characters long to the buffer provided, + * and write the length of that string to the plen location. A non-constant + * link type can use this as an early hint that subsequent calls to + * dbGetLink() will request long string data, although this might change. + * + * @param plink the link + * @param pbuffer where to put the string + * @param size length of pbuffer in chars + * @param plen set to number of chars written + * @returns status value + */ long (*loadLS)(struct link *plink, char *pbuffer, epicsUInt32 size, epicsUInt32 *plen); + + /** @brief load constant array from link type + * + * Usually called during IOC initialization, constant link types must copy + * an array value of the indicated data type to the buffer provided, update + * the pnRequest location to indicate how many elements were loaded, and + * return 0. A non-constant link type can use this method call as an early + * hint that subsequent calls to dbGetLink() will request array data of the + * indicated type and max size, although the request might change. + * + * @param plink the link + * @param dbrType data type code + * @param pbuffer where to put the value + * @param pnRequest Max elements on entry, actual on exit + * @returns 0 if elements were loaded, non-zero otherwise + */ long (*loadArray)(struct link *plink, short dbrType, void *pbuffer, long *pnRequest); /* Metadata */ + + /** @brief return link connection status + * + * Return an indication whether this link is connected or not. This routine + * is polled by the calcout and some external record types. Not required for + * non-volatile link types, which are by definition always connected. + * + * @param plink the link + * @returns 1 if connected, 0 if disconnected + */ int (*isConnected)(const struct link *plink); + + /** @brief get data type of link destination + * + * Called on both input and output links by long string support code to + * decide whether to use DBR_CHAR/DBR_UCHAR or DBR_STRING for a subsequent + * dbPutLink() or dbGetLink() call. Optional, but if not provided long + * strings cannot be transported over this link type, and no warning or + * error will appear to explain why. Not required for constant link types. + * + * @param plink the link + * @returns DBF_* type code, or -1 on error/disconnected link + */ int (*getDBFtype)(const struct link *plink); - long (*getElements)(const struct link *plink, long *nelements); /* Get data */ + + /** @brief get array size of an input link + * + * Called on input links by the compress record type for memory allocation + * purposes, before using the dbGetLink() routine to fetch the actual + * array data. + * + * @param plink the link + * @param pnElements where to put the answer + * @returns status value + */ + long (*getElements)(const struct link *plink, long *pnElements); + + /** @brief get value from an input link + * + * Called to fetch data from the link, which must be converted into the + * given data type and placed in the buffer indicated. The actual number of + * elements retrieved should be updated in the pnRequest location. If this + * method returns an error status value, the link's record will be placed + * into an Invalid severity / Link Alarm state by the dbGetLink() routine + * that calls this method. + * + * @param plink the link + * @param dbrType data type code + * @param pbuffer where to put the value + * @param pnRequest max elements on entry, actual on exit + * @returns status value + */ long (*getValue)(struct link *plink, short dbrType, void *pbuffer, long *pnRequest); + + /** @brief get the control range for an output link + * + * Called to fetch the control range for the link target, as a pair of + * double values for the lowest and highest values that the target will + * accept. This method is not used at all by the IOC or built-in record + * types, although external record types may require it. + * + * @param plink the link + * @param lo lowest accepted value + * @param hi highest accepted value + * @returns status value + */ long (*getControlLimits)(const struct link *plink, double *lo, double *hi); + + /** @brief get the display range from an input link + * + * Called to fetch the display range for an input link target, as a pair of + * double values for the lowest and highest values that the PV expects to + * return. This method is used by several built-in record types to obtain + * the display range for their generic input links. + * + * @param plink the link + * @param lo lowest accepted value + * @param hi highest accepted value + * @returns status value + */ long (*getGraphicLimits)(const struct link *plink, double *lo, double *hi); + + /** @brief get the alarm limits from an input link + * + * Called to fetch the alarm limits for an input link target, as four + * double values for the warning and alarm levels that the PV checks its + * value against. This method is used by several built-in record types to + * obtain the alarm limits for their generic input links. + * + * @param plink the link + * @param lolo low alarm value + * @param lo low warning value + * @param hi high warning value + * @param hihi high alarm value + * @returns status value + */ long (*getAlarmLimits)(const struct link *plink, double *lolo, double *lo, double *hi, double *hihi); + + /** @brief get the precision from an input link + * + * Called to fetch the precision for an input link target. This method is + * used by several built-in record types to obtain the precision for their + * generic input links. + * + * @param plink the link + * @param precision where to put the answer + * @returns status value + */ long (*getPrecision)(const struct link *plink, short *precision); + + /** @brief get the units string from an input link + * + * Called to fetch the units string for an input link target. This method is + * used by several built-in record types to obtain the units string for + * their generic input links. + * + * @param plink the link + * @param units where to put the answer + * @param unitsSize buffer size for the answer + * @returns status value + */ long (*getUnits)(const struct link *plink, char *units, int unitsSize); + + /** @brief get the alarm condition from an input link + * + * Called to fetch the alarm status and severity for an input link target. + * Either status or severity pointers may be NULL when that value is not + * needed by the calling code. This method is used by several built-in + * record types to obtain the alarm condition for their generic input links. + * + * @param plink the link + * @param status where to put the alarm status (or NULL) + * @param severity where to put the severity (or NULL) + * @returns status value + */ long (*getAlarm)(const struct link *plink, epicsEnum16 *status, epicsEnum16 *severity); + + /** @brief get the time-stamp from an input link + * + * Called to fetch the time-stamp for an input link target. This method is + * used by many built-in device supports to obtain the precision for their + * generic input links. + * + * @param plink the link + * @param pstamp where to put the answer + * @returns status value + */ long (*getTimeStamp)(const struct link *plink, epicsTimeStamp *pstamp); /* Put data */ + + /** @brief put a value to an output link + * + * Called to send nRequest elements of type dbrType found at pbuffer to an + * output link target. + * + * @param plink the link + * @param dbrType data type code + * @param pbuffer where to put the value + * @param nRequest number of elements to send + * @returns status value + */ long (*putValue)(struct link *plink, short dbrType, const void *pbuffer, long nRequest); + + /** @brief put a value to an output link with asynchronous completion + * + * Called to send nRequest elements of type dbrType found at pbuffer to an + * output link target. If the return status is zero, the link type will + * later indicate the put has completed by calling dbLinkAsyncComplete() + * from a background thread, which will be used to continue the record + * process operation from where it left off. + * + * @param plink the link + * @param dbrType data type code + * @param pbuffer where to put the value + * @param nRequest number of elements to send + * @returns status value + */ long (*putAsync)(struct link *plink, short dbrType, const void *pbuffer, long nRequest); /* Process */ + + /** @brief trigger processing of a forward link + * + * Called to trigger processing of the record pointed to by a forward link. + * This routine is optional, but if not provided no warning message will be + * shown when called by dbScanFwdLink(). JSON link types that do not support + * this operation should return NULL from their jlif::alloc_jlink() method + * if it gets called with a dbfType of DBF_FWDLINK. + * + * @param plink the link + */ void (*scanForward)(struct link *plink); /* Atomicity */ + + /** @brief execute a callback routine with link locked + * + * Called on an input link when multiple link attributes need to be fetched + * in an atomic fashion. The link type must call the callback routine and + * prevent any background I/O from updating any cached link data until that + * routine returns. This method is used by most input device support to + * fetch the timestamp along with the value when the record's TSE field is + * set to epicsTimeEventDeviceTime. + * + * @param plink the link + * @param rtn routine to execute + * @returns status value + */ long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv); } lset; @@ -97,9 +380,10 @@ epicsShareFunc long dbLoadLink(struct link *plink, short dbrType, epicsShareFunc long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer, long *pnRequest); -epicsShareFunc long dbGetNelements(const struct link *plink, long *nelements); +epicsShareFunc long dbGetNelements(const struct link *plink, long *pnElements); epicsShareFunc int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */ epicsShareFunc int dbGetLinkDBFtype(const struct link *plink); + epicsShareFunc long dbGetLink(struct link *, short dbrType, void *pbuffer, long *options, long *nRequest); epicsShareFunc long dbGetControlLimits(const struct link *plink, double *low, From a4fcd2296a3e3f25bc858a9a29d1d64108f92d79 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 22 Jan 2018 21:14:31 -0800 Subject: [PATCH 026/147] propagate PUTF through DB_LINK and use to RPRO async For async records to be usable in user triggered (eg. via RSRV) scan chains, queuing must be handled properly in the event that a second dbPutField() is made before the scan chain has completed (eg. a double click on an OPI). We change the meaning of PUTF so that it is propagated through DB links to indicate the pass through the scan chain directly triggered by a dbPutField(). propagation is broken if a busy async record is found, and that record is instead scheduled to re-process on completion. --- src/ioc/db/dbAccess.c | 22 ++++++++-- src/ioc/db/dbDbLink.c | 94 +++++++++++++++++++++++++++++++++++-------- src/ioc/db/dbDbLink.h | 5 +++ 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 973a66836..716adee1e 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -23,6 +23,8 @@ #include #include +#define EPICS_PRIVATE_API + #include "alarm.h" #include "cantProceed.h" #include "cvtFast.h" @@ -49,6 +51,7 @@ #include "dbFldTypes.h" #include "dbFldTypes.h" #include "dbLink.h" +#include "dbDbLink.h" /* for dbDbLinkPUTF() */ #include "dbLockPvt.h" #include "dbNotify.h" #include "dbScan.h" @@ -449,13 +452,26 @@ int dbGetFieldIndex(const struct dbAddr *paddr) */ long dbScanPassive(dbCommon *pfrom, dbCommon *pto) { + long status; + epicsUInt8 pact_save; + /* if not passive just return success */ if (pto->scan != 0) return 0; + pact_save = pfrom->pact; + pfrom->pact = 1; + + dbDbLinkPUTF(pfrom, pto); + if (pfrom && pfrom->ppn) dbNotifyAdd(pfrom,pto); - return dbProcess(pto); + + status = dbProcess(pto); + + pfrom->pact = pact_save; + + return status; } /* @@ -523,7 +539,7 @@ long dbProcess(dbCommon *precord) unsigned short monitor_mask; if (*ptrace) - printf("%s: Active %s\n", context, precord->name); + printf("%s: Active%s %s\n", context, precord->rpro ? " Q" : "", precord->name); /* raise scan alarm after MAX_LOCK times */ if ((precord->stat == SCAN_ALARM) || @@ -1210,7 +1226,7 @@ long dbPutField(DBADDR *paddr, short dbrType, dbrType < DBR_PUT_ACKT)) { if (precord->pact) { if (precord->tpro) - printf("%s: Active %s\n", + printf("%s: Active Q %s\n", epicsThreadGetNameSelf(), precord->name); precord->rpro = TRUE; } else { diff --git a/src/ioc/db/dbDbLink.c b/src/ioc/db/dbDbLink.c index 105799876..5a129c2d3 100644 --- a/src/ioc/db/dbDbLink.c +++ b/src/ioc/db/dbDbLink.c @@ -18,6 +18,8 @@ #include #include +#define EPICS_PRIVATE_API + #include "alarm.h" #include "cantProceed.h" #include "cvtFast.h" @@ -43,17 +45,81 @@ #include "dbNotify.h" #include "dbScan.h" #include "dbStaticLib.h" +#include "dbServer.h" #include "devSup.h" #include "link.h" #include "recGbl.h" #include "recSup.h" #include "special.h" +#include "dbDbLink.h" /***************************** Database Links *****************************/ /* Forward definition */ static lset dbDb_lset; +/* call before each call of dbProcess() (also dbScanPassive()) + * + * PUTF - This flag is set in dbPutField() prior to calling dbProcess(). + * It is normally cleared at the end of processing in recGblFwdLink(). + * It may also be cleared in dbProcess() if DISA==DISV (scan disabled), + * or by this function. + * If PUTF==1 before a call to dbProcess(prec), then afterwards + * PACT | !PUTF must be true. + * + * RPRO - Set by dbPutField() or this function when the record to be processed + * is found to be busy (PACT==1). + * Cleared in recGblFwdLink() when a record is scheduled for re-processing, + * or DISA==DISV. + */ +static +void propPUTF(struct link *plink) +{ + struct pv_link *ppv_link = &plink->value.pv_link; + DBADDR *paddr = ppv_link->pvt; + dbCommon *psrc = plink->precord, + *pdst = paddr->precord; + + dbDbLinkPUTF(psrc, pdst); +} + +void dbDbLinkPUTF(dbCommon *psrc, dbCommon *pdst) +{ + char context[40] = ""; + int trace = *dbLockSetAddrTrace(psrc); + + if (trace && dbServerClient(context, sizeof(context))) { + /* No client, use thread name */ + strncpy(context, epicsThreadGetNameSelf(), sizeof(context)); + context[sizeof(context) - 1] = 0; + } + + if(!pdst->pact) { + /* normal propagation of PUTF from src to target */ + if(trace) + printf("%s: %s -> %s prop PUTF=%u\n", context, psrc->name, pdst->name, psrc->putf); + + assert(!pdst->putf); + pdst->putf = psrc->putf; + } else if(psrc->putf) { + /* found a busy async record, + * we were originally triggered by a dbPutField() + * so queue for reprocessing on completion, + * but only this one time. + */ + if(trace) + printf("%s: %s -> %s prop RPRO=1\n", context, psrc->name, pdst->name); + pdst->putf = FALSE; + pdst->rpro = TRUE; + } else { + /* busy async record, but not originally triggered + * by dbPutField(). Do nothing. + */ + if(trace) + printf("%s: %s -> %s prop DROP\n", context, psrc->name, pdst->name); + } +} + long dbDbInitLink(struct link *plink, short dbfType) { DBADDR dbaddr; @@ -138,11 +204,7 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, /* 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; } @@ -312,20 +374,18 @@ static long dbDbPutValue(struct link *plink, short dbrType, 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; + epicsUInt8 pact_save = psrce->pact; - if (psrce && psrce->ppn) - dbNotifyAdd(psrce, pdest); - pact = psrce->pact; - psrce->pact = TRUE; - status = dbProcess(pdest); - psrce->pact = pact; - } + psrce->pact = 1; + + if (psrce && psrce->ppn) + dbNotifyAdd(psrce, pdest); + + propPUTF(plink); + + status = dbProcess(pdest); + + psrce->pact = pact_save; } return status; } diff --git a/src/ioc/db/dbDbLink.h b/src/ioc/db/dbDbLink.h index c36772004..e19685427 100644 --- a/src/ioc/db/dbDbLink.h +++ b/src/ioc/db/dbDbLink.h @@ -23,11 +23,16 @@ extern "C" { struct link; struct dbLocker; +struct dbCommon; epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType); epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, DBADDR *ptarget); +#ifdef EPICS_PRIVATE_API +void dbDbLinkPUTF(dbCommon *psrc, dbCommon *pdst); +#endif + #ifdef __cplusplus } #endif From d94c8d1e376e6957550cd02c0441496a71dc1770 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 14 May 2018 19:08:14 -0700 Subject: [PATCH 027/147] start asyncproctest --- src/std/rec/test/Makefile | 9 +++++ src/std/rec/test/asyncproctest.c | 67 +++++++++++++++++++++++++++++++ src/std/rec/test/asyncproctest.db | 33 +++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 src/std/rec/test/asyncproctest.c create mode 100644 src/std/rec/test/asyncproctest.db diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index 3099cbe23..91443a2b0 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -105,6 +105,15 @@ regressTest_SRCS += regressTest_registerRecordDeviceDriver.cpp TESTFILES += $(COMMON_DIR)/regressTest.dbd ../regressArray1.db ../regressHex.db ../regressLinkMS.db TESTS += regressTest +TARGETS += $(COMMON_DIR)/asyncproctest.dbd +DBDDEPENDS_FILES += asyncproctest.dbd$(DEP) +asyncproctest_DBD += base.dbd +TESTPROD_HOST += asyncproctest +asyncproctest_SRCS += asyncproctest.c +asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp +TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db +#TESTS += asyncproctest # full of races... + # epicsRunRecordTests runs all the test programs in a known working order. testHarness_SRCS += epicsRunRecordTests.c diff --git a/src/std/rec/test/asyncproctest.c b/src/std/rec/test/asyncproctest.c new file mode 100644 index 000000000..1987c05f4 --- /dev/null +++ b/src/std/rec/test/asyncproctest.c @@ -0,0 +1,67 @@ +/*************************************************************************\ +* Copyright (c) 2018 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* This test covers some situations where asynchronous records are + * dbProcess()'d while busy (PACT==1). + */ + +#include +#include +#include +#include +#include +#include + +void asyncproctest_registerRecordDeviceDriver(struct dbBase *); + +MAIN(asyncproctest) +{ + testPlan(0); + + testdbPrepare(); + + testdbReadDatabase("asyncproctest.dbd", NULL, NULL); + asyncproctest_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase("asyncproctest.db", NULL, "TPRO=1"); + + testIocInitOk(); + testDiag("===== Chain 1 ======"); + + testdbPutFieldOk("chain1.B", DBF_LONG, 6); + testdbPutFieldOk("chain1.B", DBF_LONG, 7); + + epicsThreadSleep(1.0); + + testdbGetFieldEqual("chain1", DBF_LONG, 7); + testdbGetFieldEqual("chain1.A", DBF_LONG, 2); + + testDiag("===== Chain 2 ======"); + + testdbPutFieldOk("chain2:1.B", DBF_LONG, 6); + testdbPutFieldOk("chain2:1.B", DBF_LONG, 7); + + epicsThreadSleep(1.0); + + testdbGetFieldEqual("chain2:1", DBF_LONG, 7); + testdbGetFieldEqual("chain2:2", DBF_LONG, 7); + testdbGetFieldEqual("chain2:1.A", DBF_LONG, 2); + testdbGetFieldEqual("chain2:2.A", DBF_LONG, 2); + + testDiag("===== Chain 3 ======"); + + testdbPutFieldOk("chain3.B", DBF_LONG, 6); + testdbPutFieldOk("chain3.B", DBF_LONG, 7); + + epicsThreadSleep(1.0); + + testdbGetFieldEqual("chain3", DBF_LONG, 7); + testdbGetFieldEqual("chain3.A", DBF_LONG, 2); + + testIocShutdownOk(); + + testdbCleanup(); + + return testDone(); +} diff --git a/src/std/rec/test/asyncproctest.db b/src/std/rec/test/asyncproctest.db new file mode 100644 index 000000000..e2fc946d8 --- /dev/null +++ b/src/std/rec/test/asyncproctest.db @@ -0,0 +1,33 @@ + +# simple case +# stand alone async record +record(calcout, "chain1") { + field(CALC, "A:=A+1;B") + field(ODLY, "0.1") + field(TPRO, "$(TPRO=)") +} + + +# original problem case +# async record chained after syncronous record +record(calcout, "chain2:1") { + field(CALC, "A:=A+1;B") + # DOLY=0 synchronous + field(OUT , "chain2:2.B PP") + field(TPRO, "$(TPRO=)") +} + +record(calcout, "chain2:2") { + field(CALC, "A:=A+1;B") + field(ODLY, "0.1") + field(TPRO, "$(TPRO=)") +} + +# ANJ's error case +# async record FLNK's to itself +record(calcout, "chain3") { + field(CALC, "A:=A+1;B") + field(ODLY, "0.1") + field(FLNK, "chain3") + field(TPRO, "$(TPRO=)") +} From 805e62b29c4e441a27f28d64e511224c3eb049eb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Oct 2017 10:30:53 -0500 Subject: [PATCH 028/147] ioc/dbStatic: add typed_dset --- src/ioc/dbStatic/devSup.h | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/ioc/dbStatic/devSup.h b/src/ioc/dbStatic/devSup.h index bd900cae4..aa3aa5c3d 100644 --- a/src/ioc/dbStatic/devSup.h +++ b/src/ioc/dbStatic/devSup.h @@ -21,6 +21,7 @@ /* structures defined elsewhere */ struct dbCommon; struct devSup; +struct ioscan_head; /* aka IOSCANPVT */ #ifdef __cplusplus extern "C" { @@ -38,6 +39,73 @@ typedef struct dset { /* device support entry table */ /*other functions are record dependent*/ } dset; +/** Type safe alternative to 'struct dset' + * + * Recommended usage + @code + long my_drv_init_record(dbCommon *prec); + long my_drv_get_iointr_info(int deattach, dbCommon *prec, IOCSCANPVT* pscan); + long my_longin_read(longinRecord *prec); + typedef struct { + typed_dset common; + long (*read)(longinRecord *prec); + } my_longin_dset; + static const my_longin_dset devLiMyDrvName = {{ + 5, // 4 from typed_dset + 1 more + NULL, + NULL, + &my_drv_init_record, + &my_drv_get_iointr_info + }, + &my_longin_read + }; + epicsExportAddress(dset, devLiMyDrvName); + @endcode + */ +typedef struct typed_dset { + /** Number of function pointers which follow. Must be >=4 */ + long number; + /** Called from dbior() */ + long (*report)(int lvl); + /** Called twice during iocInit(). + * First with phase=0 early, before init_record() and array field alloc. + * Again with phase=1 after init_record() + */ + long (*init)(int phase); + /** Called once per record instance */ + long (*init_record)(struct dbCommon *prec); + /** Called when SCAN="I/O Intr" on startup, or after SCAN is changed. + * + * Caller must assign third arguement (IOCSCANPVT*). eg. + @code + struct mpvt { + IOSCANPVT drvlist; + }; + ... + // init code calls + scanIoInit(&pvt->drvlist); + ... + long my_get_ioint_info(int deattach, struct dbCommon *prec, IOCSCANPVT* pscan) { + if(prec->dpvt) + *pscan = &((mypvt*)prec->dpvt)->drvlist; + @endcode + * + * When a particular record instance can/will only used a single scan list, then + * the 'detach' argument should be ignored. + * + * If this is not the case, then the following should be noted. + * get_ioint_info() called with deattach=0 to fetch the scan list to which this record will be added. + * Again with detach=1 to fetch the scan list from which this record will be removed. + * Calls will be balanced. + * A call with detach=0 will be matched by a call with detach=1. + * + * @note get_ioint_info() will be called during IOC shutdown if the del_record() + * extended callback is provided. (from 3.15.0.1) + */ + long (*get_ioint_info)(int deattach, struct dbCommon *prec, struct ioscan_head** pscan); + /*other functions are record dependent*/ +} typed_dset; + typedef struct dsxt { /* device support extension table */ long (*add_record)(struct dbCommon *precord); long (*del_record)(struct dbCommon *precord); From fef15d6c91e202b22b95ff369c19ce9e37109483 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Oct 2017 10:35:08 -0500 Subject: [PATCH 029/147] ioc/dbStatic: add typed_drvet --- src/ioc/dbStatic/drvSup.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ioc/dbStatic/drvSup.h b/src/ioc/dbStatic/drvSup.h index 5778038e7..59a566938 100644 --- a/src/ioc/dbStatic/drvSup.h +++ b/src/ioc/dbStatic/drvSup.h @@ -28,6 +28,20 @@ typedef struct drvet { /* driver entry table */ }drvet; #define DRVETNUMBER ( (sizeof(struct drvet) -sizeof(long))/sizeof(DRVSUPFUN) ) +typedef struct typed_drvet { + /** Number of function pointers which follow. Must be >=2 */ + long number; + /** Called from dbior() */ + long (*report)(int lvl); + /** Called during iocInit() */ +#ifdef __cplusplus + long (*init)(); +#else + long (*init)(void); +#endif + /*other functions are device dependent*/ +} typed_drvet; + #define S_drv_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/ #define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/ From c0cbbd8bee930e69eac8e4a7d58a0403b9906864 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Oct 2017 10:44:47 -0500 Subject: [PATCH 030/147] ioc/dbStatic: add dbGetDevLink() --- src/ioc/db/dbAccess.c | 12 ++++++++++++ src/ioc/dbStatic/devSup.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 973a66836..e1e354370 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -709,6 +709,18 @@ void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry) pdbentry->precnode = ppvt->recnode; } +struct link* dbGetDevLink(struct dbCommon* prec) +{ + DBLINK *plink = 0; + DBENTRY entry; + dbInitEntryFromRecord(prec, &entry); + if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) { + plink = (DBLINK*)entry.pfield; + } + dbFinishEntry(&entry); + return plink; +} + long dbValueSize(short dbr_type) { /* sizes for value associated with each DBR request type */ diff --git a/src/ioc/dbStatic/devSup.h b/src/ioc/dbStatic/devSup.h index aa3aa5c3d..63ffb36ce 100644 --- a/src/ioc/dbStatic/devSup.h +++ b/src/ioc/dbStatic/devSup.h @@ -22,6 +22,7 @@ struct dbCommon; struct devSup; struct ioscan_head; /* aka IOSCANPVT */ +struct link; /* aka DBLINK */ #ifdef __cplusplus extern "C" { @@ -112,6 +113,12 @@ typedef struct dsxt { /* device support extension table */ /* Recordtypes are *not* allowed to extend this table */ } dsxt; +/** Fetch INP or OUT link (or NULL if record type has neither). + * + * Recommended for use in device support init_record() + */ +epicsShareFunc struct link* dbGetDevLink(struct dbCommon* prec); + epicsShareExtern dsxt devSoft_DSXT; /* Allow anything table */ epicsShareFunc void devExtend(dsxt *pdsxt); From 1ca85352662766bd37317b16d1c05d455c2c25c6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Oct 2017 11:13:43 -0500 Subject: [PATCH 031/147] std/rec/test: test # Conflicts: # src/std/rec/test/linkInitTest.c --- src/std/rec/test/linkInitTest.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c index 7225beb1c..09ff40942 100644 --- a/src/std/rec/test/linkInitTest.c +++ b/src/std/rec/test/linkInitTest.c @@ -7,11 +7,14 @@ #include #include "dbAccess.h" +#include "devSup.h" #include "alarm.h" #include "dbUnitTest.h" #include "errlog.h" #include "epicsThread.h" +#include "longinRecord.h" + #include "testMain.h" void recTestIoc_registerRecordDeviceDriver(struct dbBase *); @@ -28,12 +31,21 @@ static void startTestIoc(const char *dbfile) eltc(1); } +/* testing here instead of ioc/db/test as xRecord has no INP/OUT */ +static void testdbGetDevLink(void) +{ + longinRecord *rec = (longinRecord*)testdbRecordPtr("li1"); + testOk1(dbGetDevLink((dbCommon*)rec) == &rec->inp); +} + static void testLongStringInit() { testDiag("testLongStringInit"); startTestIoc("linkInitTest.db"); + testdbGetDevLink(); + { const char buf[] = "!----------------------------------------------!"; testdbGetArrFieldEqual("longstr1.VAL$", DBF_CHAR, NELEMENTS(buf)+2, NELEMENTS(buf), buf); @@ -230,7 +242,7 @@ void testInt64Inputs(void) MAIN(linkInitTest) { - testPlan(77); + testPlan(78); testLongStringInit(); testCalcInit(); From 2b1d5ae4e38f6a6a99802dcb74c4083e8e96caa0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Oct 2017 11:46:09 -0500 Subject: [PATCH 032/147] add release note --- documentation/RELEASE_NOTES.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index a4a09c7da..e172f12cd 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -17,6 +17,16 @@ --> +

Typed Device and Driver Support callbacks

+ +

Two new structures (typed_dset and typed_drvet) are added +for use instead of dset and drvet. +The existing structures are not changed. +See comments in devSup.h for usage information.

+ +

A helper function DBLINK* dbGetDevLink(dbCommon*) is added to fetch +a pointer to the INP or OUT field of a record.

+

Restore use of ledlib for VxWorks command editing

The epicsReadline refactoring work described below unfortunately disabled the From 1893cb4f54264d137e7a6eb0c3a8c2193f9d2f89 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 14 May 2018 19:51:27 -0700 Subject: [PATCH 033/147] add USE_TYPED_DRVET and USE_TYPED_DSET options --- src/ioc/dbStatic/devSup.h | 38 ++++++++++++++++++++++---------------- src/ioc/dbStatic/drvSup.h | 28 +++++++++++++++------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/ioc/dbStatic/devSup.h b/src/ioc/dbStatic/devSup.h index 63ffb36ce..7520b7a71 100644 --- a/src/ioc/dbStatic/devSup.h +++ b/src/ioc/dbStatic/devSup.h @@ -24,22 +24,6 @@ struct devSup; struct ioscan_head; /* aka IOSCANPVT */ struct link; /* aka DBLINK */ -#ifdef __cplusplus -extern "C" { - typedef long (*DEVSUPFUN)(void *); /* ptr to device support function*/ -#else - typedef long (*DEVSUPFUN)(); /* ptr to device support function*/ -#endif - -typedef struct dset { /* device support entry table */ - long number; /*number of support routines*/ - DEVSUPFUN report; /*print report*/ - DEVSUPFUN init; /*init support layer*/ - DEVSUPFUN init_record; /*init device for particular record*/ - DEVSUPFUN get_ioint_info; /* get io interrupt information*/ - /*other functions are record dependent*/ -} dset; - /** Type safe alternative to 'struct dset' * * Recommended usage @@ -113,6 +97,28 @@ typedef struct dsxt { /* device support extension table */ /* Recordtypes are *not* allowed to extend this table */ } dsxt; +#ifdef __cplusplus +extern "C" { + typedef long (*DEVSUPFUN)(void *); /* ptr to device support function*/ +#else + typedef long (*DEVSUPFUN)(); /* ptr to device support function*/ +#endif + +#ifndef USE_TYPED_DSET + +typedef struct dset { /* device support entry table */ + long number; /*number of support routines*/ + DEVSUPFUN report; /*print report*/ + DEVSUPFUN init; /*init support layer*/ + DEVSUPFUN init_record; /*init device for particular record*/ + DEVSUPFUN get_ioint_info; /* get io interrupt information*/ + /*other functions are record dependent*/ +} dset; + +#else +typedef typed_dset dset; +#endif /* USE_TYPED_DSET */ + /** Fetch INP or OUT link (or NULL if record type has neither). * * Recommended for use in device support init_record() diff --git a/src/ioc/dbStatic/drvSup.h b/src/ioc/dbStatic/drvSup.h index 59a566938..943105f31 100644 --- a/src/ioc/dbStatic/drvSup.h +++ b/src/ioc/dbStatic/drvSup.h @@ -18,7 +18,19 @@ #include "errMdef.h" -typedef long (*DRVSUPFUN) (); /* ptr to driver support function*/ +typedef struct typed_drvet { + /** Number of function pointers which follow. Must be >=2 */ + long number; + /** Called from dbior() */ + long (*report)(int lvl); + /** Called during iocInit() */ + long (*init)(void); + /*other functions are device dependent*/ +} typed_drvet; + +typedef long (*DRVSUPFUN) (); /* ptr to driver support function for use with plain/untyped drvet */ + +#ifndef USE_TYPED_DRVET typedef struct drvet { /* driver entry table */ long number; /*number of support routines*/ @@ -28,19 +40,9 @@ typedef struct drvet { /* driver entry table */ }drvet; #define DRVETNUMBER ( (sizeof(struct drvet) -sizeof(long))/sizeof(DRVSUPFUN) ) -typedef struct typed_drvet { - /** Number of function pointers which follow. Must be >=2 */ - long number; - /** Called from dbior() */ - long (*report)(int lvl); - /** Called during iocInit() */ -#ifdef __cplusplus - long (*init)(); #else - long (*init)(void); -#endif - /*other functions are device dependent*/ -} typed_drvet; +typedef typed_drvet drvet; +#endif /* USE_TYPED_DRVET */ #define S_drv_noDrvSup (M_drvSup| 1) /*SDR_DRVSUP: Driver support missing*/ #define S_drv_noDrvet (M_drvSup| 3) /*Missing driver support entry table*/ From 3b89515664bb140f6f05089da98aabaa9d4dad1b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 14 May 2018 23:43:13 -0500 Subject: [PATCH 034/147] dbJLink: Pass the correct dbfType to child links API change for link types that support child links, they must now indicate whether a child link is an input, output or forward link by the return value from their parse_start_map() method. The original jlif_key_child_link enumeration has been replaced by 3 new values: jlif_key_child_inlink, jlif_key_child_outlink and jlif_key_child_fwdlink Previously we were passing the dbfType of the record link field to all child links within it, which was wrong. --- src/ioc/db/dbJLink.c | 68 +++++++++++++++++++++++++----------------- src/ioc/db/dbJLink.h | 7 +++-- src/std/link/lnkCalc.c | 8 +++-- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index 10a4e62d2..a5fd2bed6 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -37,7 +37,6 @@ typedef struct parseContext { jlink *product; short dbfType; short jsonDepth; - unsigned key_is_link:1; } parseContext; #define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine) @@ -47,8 +46,8 @@ static int dbjl_return(parseContext *parser, jlif_result result) { 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } if (result == jlif_stop && pjlink) { @@ -73,8 +72,8 @@ static int dbjl_value(parseContext *parser, jlif_result result) { 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } if (result == jlif_stop || pjlink->parseDepth > 0) @@ -163,29 +162,45 @@ static int dbjl_start_map(void *ctx) { 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); + printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n", + parser->jsonDepth, parser->dbfType); } 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } 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; + switch (result) { + case jlif_key_child_inlink: + parser->dbfType = DBF_INLINK; result = jlif_continue; + break; + case jlif_key_child_outlink: + parser->dbfType = DBF_OUTLINK; + result = jlif_continue; + break; + case jlif_key_child_fwdlink: + parser->dbfType = DBF_FWDLINK; + result = jlif_continue; + break; + case jlif_continue: + break; + default: + errlogPrintf("dbJLinkInit: Bad return %d from '%s'::parse_start_map()\n", + result, pjlink->pif->name); + result = jlif_stop; + break; } IFDEBUG(10) @@ -201,7 +216,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { linkSup *linkSup; jlif *pjlif; - if (!parser->key_is_link) { + if (parser->dbfType == 0) { if (!pjlink) { errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n", (int) len, key); @@ -211,8 +226,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } assert(pjlink->parseDepth > 0); @@ -223,8 +238,8 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t 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); + printf(" jsonDepth=%d, parseDepth=00, dbfType=%d\n", + parser->jsonDepth, parser->dbfType); } link_name = dbmfStrndup((const char *) key, len); @@ -264,7 +279,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { pjlink->parent = NULL; parser->pjlink = pjlink; - parser->key_is_link = 0; + parser->dbfType = 0; dbmfFree(link_name); @@ -282,9 +297,9 @@ static int dbjl_end_map(void *ctx) { 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", + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, - parser->key_is_link); + parser->dbfType); } parser->jsonDepth--; @@ -306,8 +321,8 @@ static int dbjl_start_array(void *ctx) { 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } assert(pjlink); @@ -324,8 +339,8 @@ static int dbjl_end_array(void *ctx) { 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); + printf(" jsonDepth=%d, parseDepth=%d, dbfType=%d\n", + parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->dbfType); } assert(pjlink); @@ -355,15 +370,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, parser->product = NULL; parser->dbfType = dbfType; parser->jsonDepth = 0; - parser->key_is_link = 0; 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); + printf("dbJLinkInit: jsonDepth=%d, dbfType=%d\n", + parser->jsonDepth, parser->dbfType); yajl_set_default_alloc_funcs(&dbjl_allocs); yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser); diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h index 954b69be5..a94d10ab8 100644 --- a/src/ioc/db/dbJLink.h +++ b/src/ioc/db/dbJLink.h @@ -24,7 +24,7 @@ typedef enum { typedef enum { jlif_key_stop = jlif_stop, jlif_key_continue = jlif_continue, - jlif_key_child_link + jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink } jlif_key_result; struct link; @@ -71,8 +71,9 @@ typedef struct jlif { /* 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). + /* Optional, parser saw an open-brace '{'. Return jlif_key_child_inlink, + * jlif_key_child_outlink, or jlif_key_child_fwdlink to expect a child + * link next (extra key/value pairs may follow) */ jlif_result (*parse_map_key)(jlink *, const char *key, size_t len); diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index de76948a9..987d3bd06 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -254,8 +254,10 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) IFDEBUG(10) printf("lnkCalc_start_map(calc@%p)\n", clink); - if (clink->pstate == ps_args || clink->pstate == ps_out) - return jlif_key_child_link; + if (clink->pstate == ps_args) + return jlif_key_child_inlink; + if (clink->pstate == ps_out) + return jlif_key_child_outlink; if (clink->pstate != ps_init) { errlogPrintf("lnkCalc: Unexpected map\n"); @@ -463,7 +465,7 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent) } } -long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) +static long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); int i; From fd30989f63f3afe2e773441725d44a735901a1fc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2018 23:23:54 -0500 Subject: [PATCH 035/147] Add jlif::start_child() method --- src/ioc/db/dbJLink.c | 21 +++++++++++++-------- src/ioc/db/dbJLink.h | 9 ++++++++- src/ioc/db/test/jlinkz.c | 3 ++- src/ioc/db/test/xLink.c | 5 ++--- src/std/link/lnkCalc.c | 2 +- src/std/link/lnkConst.c | 2 +- src/std/link/lnkState.c | 2 +- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index a5fd2bed6..df0c2d822 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -215,6 +215,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { char *link_name; linkSup *linkSup; jlif *pjlif; + jlink *child; if (parser->dbfType == 0) { if (!pjlink) { @@ -260,31 +261,35 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { return dbjl_return(parser, jlif_stop); } - pjlink = pjlif->alloc_jlink(parser->dbfType); - if (!pjlink) { + child = pjlif->alloc_jlink(parser->dbfType); + if (!child) { errlogPrintf("dbJLinkInit: Link type '%s' allocation failed. \n", link_name); dbmfFree(link_name); return dbjl_return(parser, jlif_stop); } - pjlink->pif = pjlif; - pjlink->parseDepth = 0; + child->pif = pjlif; + child->parseDepth = 0; + child->debug = 0; if (parser->pjlink) { /* We're starting a child link, save its parent */ - pjlink->parent = parser->pjlink; + child->parent = pjlink; + + if (pjlink->pif->start_child) + pjlink->pif->start_child(pjlink, child); } else - pjlink->parent = NULL; + child->parent = NULL; - parser->pjlink = pjlink; + parser->pjlink = child; parser->dbfType = 0; dbmfFree(link_name); IFDEBUG(8) - printf("dbjl_map_key: New %s@%p\n", pjlink ? pjlink->pif->name : "", pjlink); + printf("dbjl_map_key: New %s@%p\n", child ? child->pif->name : "", child); return jlif_continue; } diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h index a94d10ab8..54c793175 100644 --- a/src/ioc/db/dbJLink.h +++ b/src/ioc/db/dbJLink.h @@ -90,7 +90,8 @@ typedef struct jlif { 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 */ + * the child link has finished parsing successfully + */ struct lset* (*get_lset)(const jlink *); /* Required, return lset for this link instance */ @@ -107,6 +108,12 @@ typedef struct jlif { * Stop immediately and return status if non-zero. */ + void (*start_child)(jlink *parent, jlink *child); + /* Optional, called with pointer to the new child link after + * parse_start_map() returned a jlif_key_child_link value and + * the child link has been allocated (but not parsed yet) + */ + /* Link types must NOT extend this table with their own routines, * this space is reserved for extensions to the jlink interface. */ diff --git a/src/ioc/db/test/jlinkz.c b/src/ioc/db/test/jlinkz.c index dd6919ffb..fc98ff3b3 100644 --- a/src/ioc/db/test/jlinkz.c +++ b/src/ioc/db/test/jlinkz.c @@ -246,7 +246,8 @@ static jlif jlifZ = { NULL, /* end child */ &z_lset, NULL, /* report */ - NULL /* map child */ + NULL, /* map child */ + NULL /* start child */ }; epicsExportAddress(jlif, jlifZ); diff --git a/src/ioc/db/test/xLink.c b/src/ioc/db/test/xLink.c index 12175f44e..2d7c3c043 100644 --- a/src/ioc/db/test/xLink.c +++ b/src/ioc/db/test/xLink.c @@ -2,7 +2,7 @@ * 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. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* xLink.c */ @@ -82,7 +82,6 @@ static jlif xlinkIf = { NULL, NULL, NULL, NULL, NULL, NULL, xlink_get_lset, - NULL, NULL + NULL, NULL, NULL }; epicsExportAddress(jlif, xlinkIf); - diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index 987d3bd06..6b68ac990 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -847,6 +847,6 @@ static jlif lnkCalcIf = { lnkCalc_start_map, lnkCalc_map_key, lnkCalc_end_map, lnkCalc_start_array, lnkCalc_end_array, lnkCalc_end_child, lnkCalc_get_lset, - lnkCalc_report, lnkCalc_map_children + lnkCalc_report, lnkCalc_map_children, NULL }; epicsExportAddress(jlif, lnkCalcIf); diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c index ee93830ff..3b9392cfa 100644 --- a/src/std/link/lnkConst.c +++ b/src/std/link/lnkConst.c @@ -631,6 +631,6 @@ static jlif lnkConstIf = { NULL, NULL, NULL, lnkConst_start_array, lnkConst_end_array, NULL, lnkConst_get_lset, - lnkConst_report, NULL + lnkConst_report, NULL, NULL }; epicsExportAddress(jlif, lnkConstIf); diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index 8792a1f64..518a37029 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -280,6 +280,6 @@ static jlif lnkStateIf = { NULL, NULL, NULL, NULL, NULL, NULL, lnkState_get_lset, - lnkState_report, NULL + lnkState_report, NULL, NULL }; epicsExportAddress(jlif, lnkStateIf); From f2ceb3bbbf51ffb84d76021dfa1005381c97301f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2018 23:26:53 -0500 Subject: [PATCH 036/147] dbJLink: Add jlif result enum state name strings --- src/ioc/db/dbJLink.c | 18 ++++++++++++++++++ src/ioc/db/dbJLink.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index df0c2d822..1c448dd4d 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -39,6 +39,19 @@ typedef struct parseContext { short jsonDepth; } parseContext; +epicsShareDef const char *jlif_result_name[2] = { + "jlif_stop", + "jlif_continue", +}; + +epicsShareDef const char *jlif_key_result_name[5] = { + "jlif_key_stop", + "jlif_key_continue", + "jlif_key_child_inlink", + "jlif_key_child_outlink", + "jlif_key_child_fwdlink" +}; + #define CALL_OR_STOP(routine) !(routine) ? jlif_stop : (routine) static int dbjl_return(parseContext *parser, jlif_result result) { @@ -423,6 +436,11 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, } yajl_free(yh); + + IFDEBUG(10) + printf("dbJLinkInit: returning status=0x%lx\n\n", + status); + return status; } diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h index 54c793175..7080ed7cb 100644 --- a/src/ioc/db/dbJLink.h +++ b/src/ioc/db/dbJLink.h @@ -21,12 +21,16 @@ typedef enum { jlif_continue = 1 } jlif_result; +epicsShareExtern const char *jlif_result_name[2]; + typedef enum { jlif_key_stop = jlif_stop, jlif_key_continue = jlif_continue, jlif_key_child_inlink, jlif_key_child_outlink, jlif_key_child_fwdlink } jlif_key_result; +epicsShareExtern const char *jlif_key_result_name[5]; + struct link; struct lset; struct jlif; From 8cdcaf5a875de59f90d6e42d22b1a4ca88242ca4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2018 23:32:48 -0500 Subject: [PATCH 037/147] dbJLink: Restore the jlink::debug flag, add debug and trace link types --- src/ioc/db/dbJLink.h | 1 + src/std/link/Makefile | 1 + src/std/link/links.dbd.pod | 36 ++ src/std/link/lnkDebug.c | 1044 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1082 insertions(+) create mode 100644 src/std/link/lnkDebug.c diff --git a/src/ioc/db/dbJLink.h b/src/ioc/db/dbJLink.h index 7080ed7cb..bd1a6c8a2 100644 --- a/src/ioc/db/dbJLink.h +++ b/src/ioc/db/dbJLink.h @@ -39,6 +39,7 @@ 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 to request debug output to console */ /* Link types extend or embed this structure for private storage */ } jlink; diff --git a/src/std/link/Makefile b/src/std/link/Makefile index 5ad9777a8..9b6abd705 100644 --- a/src/std/link/Makefile +++ b/src/std/link/Makefile @@ -14,5 +14,6 @@ DBD += links.dbd dbRecStd_SRCS += lnkConst.c dbRecStd_SRCS += lnkCalc.c dbRecStd_SRCS += lnkState.c +dbRecStd_SRCS += lnkDebug.c HTMLS += links.html diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index 6b48c13fb..bf13bf7a9 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -15,6 +15,10 @@ The following additional link types are available in this release: =item * L +=item * L + +=item * L + =back =head2 Using JSON Links @@ -200,3 +204,35 @@ link is initialized if it doesn't already exist. {state:"!simEnable"} =cut + + +link(debug, lnkDebugIf) +variable(lnkDebug_debug, int) + +=head3 Debug Link C<"debug"> + +The debug link type exists to enable debugging of other link types; it provides +no functionality itself other than to turn on the debug flag for the child link +that is its only parameter and pass all link operations down to that link. + +=head4 Example + + {debug:{state:"redBeam"}} + +=cut + + +link(trace, lnkTraceIf) + +=head3 Trace Link C<"trace"> + +The trace link type is a relative of the debug link type that also traces the +operation of its child link. At creation it turns on the debug flag of its child +link, then it prints the method arguments and return values of all link +operations before / after passing control down to the child link. + +=head4 Example + + {trace:{state:"redBeam"}} + +=cut diff --git a/src/std/link/lnkDebug.c b/src/std/link/lnkDebug.c new file mode 100644 index 000000000..9ede69cb2 --- /dev/null +++ b/src/std/link/lnkDebug.c @@ -0,0 +1,1044 @@ +/*************************************************************************\ +* Copyright (c) 2018 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. +\*************************************************************************/ +/* lnkDebug.c */ + +/* Usage + * {debug:{...:...}} + */ + +#include +#include +#include + +#include "alarm.h" +#include "dbDefs.h" +#include "dbAccessDefs.h" +#include "dbLink.h" +#include "dbJLink.h" +#include "dbStaticLib.h" +#include "errlog.h" +#include "epicsTime.h" + +#include "epicsExport.h" + +/* This is for debugging the debug link-type */ +int lnkDebug_debug; +epicsExportAddress(int, lnkDebug_debug); + +#define IFDEBUG(n) if (lnkDebug_debug >= (n)) + +typedef struct debug_link { + jlink jlink; /* embedded object */ + short dbfType; + unsigned trace:1; + const jlif *child_jlif; + const lset *child_lset; + jlif jlif; + lset lset; + struct link child_link; +} debug_link; + + +/********************* Delegating jlif Routines *********************/ + +static void delegate_free(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + struct link *plink = &dlink->child_link; + + if (dlink->trace) + printf("Link trace: Calling %s::free_jlink(%p)\n", + pif->name, pjlink); + + pif->free_jlink(pjlink); + plink->type = 0; + plink->value.json.jlink = NULL; + + if (dlink->trace) + printf("Link trace: %s::free_jlink(%p) returned\n", + pif->name, pjlink); +} + +static jlif_result delegate_null(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_null(%p)\n", + pif->name, pjlink); + + res = pif->parse_null(pjlink); + + if (dlink->trace) + printf("Link trace: %s::parse_null(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_boolean(jlink *pjlink, int val) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_boolean(%p, %d)\n", + pif->name, pjlink, val); + + res = pif->parse_boolean(pjlink, val); + + if (dlink->trace) + printf("Link trace: %s::parse_boolean(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_integer(jlink *pjlink, long long num) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_integer(%p, %lld)\n", + pif->name, pjlink, num); + + res = pif->parse_integer(pjlink, num); + + if (dlink->trace) + printf("Link trace: %s::parse_integer(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_double(jlink *pjlink, double num) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_double(%p, %g)\n", + pif->name, pjlink, num); + + res = pif->parse_double(pjlink, num); + + if (dlink->trace) + printf("Link trace: %s::parse_double(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_string(jlink *pjlink, const char *val, size_t len) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_string(%p, \"%.*s\")\n", + pif->name, pjlink, (int) len, val); + + res = pif->parse_string(pjlink, val, len); + + if (dlink->trace) + printf("Link trace: %s::parse_string(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_key_result delegate_start_map(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_key_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_start_map(%p)\n", + pif->name, pjlink); + + res = pif->parse_start_map(pjlink); + + if (dlink->trace) + printf("Link trace: %s::parse_start_map(%p) returned %s\n", + pif->name, pjlink, jlif_key_result_name[res]); + + return res; +} + +static jlif_result delegate_map_key(jlink *pjlink, const char *key, size_t len) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_map_key(%p, \"%.*s\")\n", + pif->name, pjlink, (int) len, key); + + res = pif->parse_map_key(pjlink, key, len); + + if (dlink->trace) + printf("Link trace: %s::parse_map_key(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_end_map(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_end_map(%p)\n", + pif->name, pjlink); + + res = pif->parse_end_map(pjlink); + + if (dlink->trace) + printf("Link trace: %s::parse_end_map(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_start_array(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_(%p)\n", + pif->name, pjlink); + + res = pif->parse_start_array(pjlink); + + if (dlink->trace) + printf("Link trace: %s::parse_start_array(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static jlif_result delegate_end_array(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + jlif_result res; + + if (dlink->trace) + printf("Link trace: Calling %s::parse_end_array(%p)\n", + pif->name, pjlink); + + res = pif->parse_end_array(pjlink); + + if (dlink->trace) + printf("Link trace: %s::parse_end_array(%p) returned %s\n", + pif->name, pjlink, jlif_result_name[res]); + + return res; +} + +static void delegate_start_child(jlink *pjlink, jlink *child) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + + if (dlink->trace) + printf("Link trace: Calling %s::start_child(%p, %p)\n", + pif->name, pjlink, child); + + pif->start_child(pjlink, child); + + if (dlink->trace) + printf("Link trace: %s::start_child(%p) returned\n", + pif->name, pjlink); +} + +static void delegate_end_child(jlink *pjlink, jlink *child) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + + if (dlink->trace) + printf("Link trace: Calling %s::end_child(%p, %p)\n", + pif->name, pjlink, child); + + pif->end_child(pjlink, child); + + if (dlink->trace) + printf("Link trace: %s::end_child(%p) returned\n", + pif->name, pjlink); +} + +static struct lset* delegate_get_lset(const jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + + if (dlink->trace) + printf("Link trace: NOT calling %s::get_lset(%p)\n", + dlink->child_jlif->name, pjlink); + + return &dlink->lset; +} + +static void delegate_report(const jlink *pjlink, int level, int indent) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + + if (dlink->trace) + printf("Link trace: Calling %s::report(%p, %d, %d)\n", + pif->name, pjlink, level, indent); + + pif->report(pjlink, level, indent); + + if (dlink->trace) + printf("Link trace: %s::report(%p) returned\n", + pif->name, pjlink); +} + +static long delegate_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) +{ + debug_link *dlink = CONTAINER(pjlink->parent, struct debug_link, jlink); + const jlif *pif = dlink->child_jlif; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::map_children(%p, %p, %p)\n", + pif->name, pjlink, rtn, ctx); + + res = pif->map_children(pjlink, rtn, ctx); + + if (dlink->trace) + printf("Link trace: %s::map_children(%p) returned %ld\n", + pif->name, pjlink, res); + + return res; +} + + +/********************* Delegating lset Routines *********************/ + +static void delegate_openLink(struct link *plink) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + + if (dlink->trace) + printf("Link trace: Calling %s::openLink(%p = jlink %p)\n", + dlink->child_jlif->name, clink, clink->value.json.jlink); + + clset->openLink(clink); + + if (dlink->trace) + printf("Link trace: %s::openLink(%p) returned\n", + dlink->child_jlif->name, clink); +} + +static void delegate_removeLink(struct dbLocker *locker, struct link *plink) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + + if (dlink->trace) + printf("Link trace: Calling %s::removeLink(%p, %p)\n", + dlink->child_jlif->name, locker, clink); + + clset->removeLink(locker, clink); + + if (dlink->trace) + printf("Link trace: %s::removeLink(%p) returned\n", + dlink->child_jlif->name, clink); +} + +static long delegate_loadScalar(struct link *plink, short dbrType, void *pbuffer) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::loadScalar(%p, %s, %p)\n", + dlink->child_jlif->name, clink, + dbGetFieldTypeString(dbrType), pbuffer); + + res = clset->loadScalar(clink, dbrType, pbuffer); + + if (dlink->trace) + printf("Link trace: %s::loadScalar(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + + return res; +} + +static long delegate_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size, + epicsUInt32 *plen) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::loadLS(%p, %p, %u)\n", + dlink->child_jlif->name, clink, pbuffer, size); + + res = clset->loadLS(clink, pbuffer, size, plen); + + if (dlink->trace) { + printf("Link trace: %s::loadLS(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Loaded: %u byte(s) \"%s\"\n", *plen, pbuffer); + } + + return res; +} + +static long delegate_loadArray(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::loadArray(%p, %s, %p, %ld)\n", + dlink->child_jlif->name, clink, + dbGetFieldTypeString(dbrType), pbuffer, pnRequest ? *pnRequest : 0l); + + res = clset->loadArray(clink, dbrType, pbuffer, pnRequest); + + if (dlink->trace) { + printf("Link trace: %s::loadArray(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Loaded: %ld element(s)\n", pnRequest ? *pnRequest : 1l); + } + + return res; +} + +static int delegate_isConnected(const struct link *plink) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + int res; + + if (dlink->trace) + printf("Link trace: Calling %s::isConnected(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->isConnected(clink); + + if (dlink->trace) + printf("Link trace: %s::isConnected(%p) returned %d (%s)\n", + dlink->child_jlif->name, clink, res, + res == 0 ? "No" : res == 1 ? "Yes" : "Bad value"); + + return res; +} + +static int delegate_getDBFtype(const struct link *plink) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + int res; + + if (dlink->trace) + printf("Link trace: Calling %s::getDBFtype(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getDBFtype(clink); + + if (dlink->trace) + printf("Link trace: %s::getDBFtype(%p) returned %d (%s)\n", + dlink->child_jlif->name, clink, res, + res == -1 ? "Link disconnected" : dbGetFieldTypeString(res)); + + return res; +} + +static long delegate_getElements(const struct link *plink, long *pnElements) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getElements(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getElements(clink, pnElements); + + if (dlink->trace) { + printf("Link trace: %s::getElements(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Result: %ld element(s)\n", *pnElements); + } + + return res; +} + +static long delegate_getValue(struct link *plink, short dbrType, void *pbuffer, + long *pnRequest) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getValue(%p, %s, %p, %ld)\n", + dlink->child_jlif->name, clink, + dbGetFieldTypeString(dbrType), pbuffer, pnRequest ? *pnRequest : 0l); + + res = clset->getValue(clink, dbrType, pbuffer, pnRequest); + + if (dlink->trace) { + printf("Link trace: %s::getValue(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: %ld element(s)\n", pnRequest ? *pnRequest : 1l); + } + + return res; +} + +static long delegate_getControlLimits(const struct link *plink, + double *lo, double *hi) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getControlLimits(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getControlLimits(clink, lo, hi); + + if (dlink->trace) { + printf("Link trace: %s::getControlLimits(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: Lo = %g, Hi = %g\n", *lo, *hi); + } + + return res; +} + +static long delegate_getGraphicLimits(const struct link *plink, + double *lo, double *hi) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getGraphicLimits(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getGraphicLimits(clink, lo, hi); + + if (dlink->trace) { + printf("Link trace: %s::getGraphicLimits(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: Lo = %g, Hi = %g\n", *lo, *hi); + } + + return res; +} + +static long delegate_getAlarmLimits(const struct link *plink, + double *lolo, double *lo, double *hi, double *hihi) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getAlarmLimits(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getAlarmLimits(clink, lolo, lo, hi, hihi); + + if (dlink->trace) { + printf("Link trace: %s::getAlarmLimits(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: Lolo = %g, Lo = %g, Hi = %g, Hihi = %g\n", + *lolo, *lo, *hi, *hihi); + } + + return res; +} + +static long delegate_getPrecision(const struct link *plink, short *precision) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getPrecision(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getPrecision(clink, precision); + + if (dlink->trace) { + printf("Link trace: %s::getPrecision(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: prec = %d\n", *precision); + } + + return res; +} + +static long delegate_getUnits(const struct link *plink, char *units, int unitsSize) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getUnits(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getUnits(clink, units, unitsSize); + + if (dlink->trace) { + printf("Link trace: %s::getUnits(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got: Units = '%s'\n", units); + } + + return res; +} + +static long delegate_getAlarm(const struct link *plink, epicsEnum16 *stat, + epicsEnum16 *sevr) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getAlarm(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getAlarm(clink, stat, sevr); + + if (dlink->trace) { + printf("Link trace: %s::getAlarm(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) + printf(" Got:%s%s%s%s\n", + stat ? " Status = " : "", + stat && (*stat < ALARM_NSEV) ? + epicsAlarmConditionStrings[*stat] : "Bad-status", + sevr ? " Severity = " : "", + sevr && (*sevr < ALARM_NSTATUS) ? + epicsAlarmSeverityStrings[*sevr] : "Bad-severity" + ); + } + + return res; +} + +static long delegate_getTimeStamp(const struct link *plink, epicsTimeStamp *pstamp) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::getTimeStamp(%p)\n", + dlink->child_jlif->name, clink); + + res = clset->getTimeStamp(clink, pstamp); + + if (dlink->trace) { + printf("Link trace: %s::getTimeStamp(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + if (res == 0) { + char timeStr[32]; + + epicsTimeToStrftime(timeStr, sizeof(timeStr), + "%Y-%m-%d %H:%M:%S.%09f", pstamp); + printf(" Got: Timestamp = '%s'\n", timeStr); + } + } + + return res; +} + +static long delegate_putValue(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::putValue(%p, %s, %p, %ld)\n", + dlink->child_jlif->name, clink, + dbGetFieldTypeString(dbrType), pbuffer, nRequest); + + res = clset->putValue(clink, dbrType, pbuffer, nRequest); + + if (dlink->trace) + printf("Link trace: %s::putValue(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + + return res; +} + +static long delegate_putAsync(struct link *plink, short dbrType, + const void *pbuffer, long nRequest) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::putAsync(%p, %s, %p, %ld)\n", + dlink->child_jlif->name, clink, + dbGetFieldTypeString(dbrType), pbuffer, nRequest); + + res = clset->putAsync(clink, dbrType, pbuffer, nRequest); + + if (dlink->trace) + printf("Link trace: %s::putAsync(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + + return res; +} + +static void delegate_scanForward(struct link *plink) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + + if (dlink->trace) + printf("Link trace: Calling %s::scanForward(%p)\n", + dlink->child_jlif->name, clink); + + clset->scanForward(clink); + + if (dlink->trace) + printf("Link trace: %s::scanForward(%p) returned\n", + dlink->child_jlif->name, clink); +} + +static long delegate_doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv) +{ + debug_link *dlink = CONTAINER(plink->value.json.jlink, + struct debug_link, jlink); + struct link *clink = &dlink->child_link; + const lset *clset = dlink->child_lset; + long res; + + if (dlink->trace) + printf("Link trace: Calling %s::doLocked(%p, %p, %p)\n", + dlink->child_jlif->name, clink, rtn, priv); + + res = clset->doLocked(clink, rtn, priv); + + if (dlink->trace) + printf("Link trace: %s::doLocked(%p) returned %ld (0x%lx)\n", + dlink->child_jlif->name, clink, res, res); + + return res; +} + + +/************************ Debug jlif Routines ***********************/ + +static jlink* lnkDebug_alloc(short dbfType) +{ + debug_link *dlink; + + IFDEBUG(10) + printf("lnkDebug_alloc(%s)\n", dbGetFieldTypeString(dbfType)); + + dlink = calloc(1, sizeof(struct debug_link)); + if (!dlink) { + errlogPrintf("lnkDebug: calloc() failed.\n"); + return NULL; + } + + dlink->dbfType = dbfType; + + IFDEBUG(10) + printf("lnkDebug_alloc -> debug@%p\n", dlink); + + return &dlink->jlink; +} + +static jlink* lnkTrace_alloc(short dbfType) +{ + debug_link *dlink; + + IFDEBUG(10) + printf("lnkTrace_alloc(%s)\n", dbGetFieldTypeString(dbfType)); + + dlink = calloc(1, sizeof(struct debug_link)); + if (!dlink) { + errlogPrintf("lnkTrace: calloc() failed.\n"); + return NULL; + } + + dlink->dbfType = dbfType; + dlink->trace = 1; + + IFDEBUG(10) + printf("lnkTrace_alloc -> debug@%p\n", dlink); + + return &dlink->jlink; +} + +static void lnkDebug_free(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_free(debug@%p)\n", dlink); + + dbJLinkFree(dlink->child_link.value.json.jlink); + + free(dlink); +} + +static jlif_key_result lnkDebug_start_map(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_start_map(debug@%p)\n", dlink); + + switch (dlink->dbfType) { + case DBF_INLINK: + return jlif_key_child_inlink; + case DBF_OUTLINK: + return jlif_key_child_outlink; + case DBF_FWDLINK: + return jlif_key_child_outlink; + } + return jlif_stop; +} + +static jlif_result lnkDebug_end_map(jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_end_map(debug@%p)\n", dlink); + + return jlif_continue; +} + +static void lnkDebug_start_child(jlink *parent, jlink *child) +{ + debug_link *dlink = CONTAINER(parent, struct debug_link, jlink); + const jlif *pif = child->pif; + const jlif delegate_jlif = { + pif->name, + pif->alloc_jlink, /* Never used */ + delegate_free, + pif->parse_null ? delegate_null : NULL, + pif->parse_boolean ? delegate_boolean : NULL, + pif->parse_integer ? delegate_integer : NULL, + pif->parse_double ? delegate_double : NULL, + pif->parse_string ? delegate_string : NULL, + pif->parse_start_map ? delegate_start_map : NULL, + pif->parse_map_key ? delegate_map_key : NULL, + pif->parse_end_map ? delegate_end_map : NULL, + pif->parse_start_array ? delegate_start_array : NULL, + pif->parse_end_array ? delegate_end_array : NULL, + pif->end_child ? delegate_end_child : NULL, + delegate_get_lset, + pif->report ? delegate_report : NULL, + pif->map_children ? delegate_map_children : NULL, + pif->start_child ? delegate_start_child : NULL + }; + + IFDEBUG(10) + printf("lnkDebug_start_child(debug@%p, %s@%p)\n", dlink, + child->pif->name, child); + + dlink->child_jlif = pif; + memcpy(&dlink->jlif, &delegate_jlif, sizeof(jlif)); + + child->debug = 1; + child->pif = &dlink->jlif; /* Replace Child's interface table */ + + IFDEBUG(15) + printf("lnkDebug_start_child: pif %p => %p\n", pif, child->pif); + + if (dlink->trace) + printf("Link trace: %s::alloc_jlink(%s) returned %p\n", + pif->name, dbGetFieldTypeString(dlink->dbfType), child); +} + +static void lnkDebug_end_child(jlink *parent, jlink *child) +{ + debug_link *dlink = CONTAINER(parent, struct debug_link, jlink); + struct link *plink = &dlink->child_link; + const lset *plset = dlink->child_jlif->get_lset(child); + lset delegate_lset = { + plset->isConstant, + plset->isVolatile, + plset->openLink ? delegate_openLink : NULL, + plset->removeLink ? delegate_removeLink : NULL, + plset->loadScalar ? delegate_loadScalar : NULL, + plset->loadLS ? delegate_loadLS : NULL, + plset->loadArray ? delegate_loadArray : NULL, + plset->isConnected ? delegate_isConnected : NULL, + plset->getDBFtype ? delegate_getDBFtype : NULL, + plset->getElements ? delegate_getElements : NULL, + plset->getValue ? delegate_getValue : NULL, + plset->getControlLimits ? delegate_getControlLimits : NULL, + plset->getGraphicLimits ? delegate_getGraphicLimits : NULL, + plset->getAlarmLimits ? delegate_getAlarmLimits : NULL, + plset->getPrecision ? delegate_getPrecision : NULL, + plset->getUnits ? delegate_getUnits : NULL, + plset->getAlarm ? delegate_getAlarm : NULL, + plset->getTimeStamp ? delegate_getTimeStamp : NULL, + plset->putValue ? delegate_putValue : NULL, + plset->putAsync ? delegate_putAsync : NULL, + plset->scanForward ? delegate_scanForward : NULL, + plset->doLocked ? delegate_doLocked : NULL + }; + + IFDEBUG(10) + printf("lnkDebug_end_child(debug@%p, %s@%p)\n", dlink, + child->pif->name, child); + + plink->type = JSON_LINK; + plink->value.json.string = NULL; + plink->value.json.jlink = child; + + dlink->child_lset = plset; + memcpy(&dlink->lset, &delegate_lset, sizeof(lset)); + + IFDEBUG(15) + printf("lnkDebug_end_child: lset %p => %p\n", plset, &dlink->lset); +} + +static struct lset* lnkDebug_get_lset(const jlink *pjlink) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_get_lset(debug@%p)\n", pjlink); + + return &dlink->lset; +} + +static void lnkDebug_report(const jlink *pjlink, int level, int indent) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_report(debug@%p)\n", dlink); + + if (dlink->trace) + printf("%*s'trace':\n", indent, ""); + else + printf("%*s'debug':\n", indent, ""); + + if (dlink->child_link.type == JSON_LINK) { + dbJLinkReport(dlink->child_link.value.json.jlink, level, indent + 2); + } +} + +long lnkDebug_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) +{ + debug_link *dlink = CONTAINER(pjlink, struct debug_link, jlink); + + IFDEBUG(10) + printf("lnkDebug_map_children(debug@%p)\n", dlink); + + if (dlink->child_link.type == JSON_LINK) { + return dbJLinkMapChildren(&dlink->child_link, rtn, ctx); + } + return 0; +} + + +/************************* Interface Tables *************************/ + +static jlif lnkDebugIf = { + "debug", lnkDebug_alloc, lnkDebug_free, + NULL, NULL, NULL, NULL, NULL, + lnkDebug_start_map, NULL, lnkDebug_end_map, + NULL, NULL, lnkDebug_end_child, lnkDebug_get_lset, + lnkDebug_report, lnkDebug_map_children, lnkDebug_start_child +}; +epicsExportAddress(jlif, lnkDebugIf); + +static jlif lnkTraceIf = { + "trace", lnkTrace_alloc, lnkDebug_free, + NULL, NULL, NULL, NULL, NULL, + lnkDebug_start_map, NULL, lnkDebug_end_map, + NULL, NULL, lnkDebug_end_child, lnkDebug_get_lset, + lnkDebug_report, lnkDebug_map_children, lnkDebug_start_child +}; +epicsExportAddress(jlif, lnkTraceIf); From 89b9e240b0c81938629037803bd08e5818d86884 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2018 23:43:39 -0500 Subject: [PATCH 038/147] Link types: Remove debug tracing now provided by debug link type --- src/std/link/links.dbd.pod | 3 -- src/std/link/lnkCalc.c | 88 ------------------------------- src/std/link/lnkConst.c | 104 +++++++------------------------------ src/std/link/lnkState.c | 59 +-------------------- 4 files changed, 22 insertions(+), 232 deletions(-) diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index bf13bf7a9..b5ed582f2 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -39,7 +39,6 @@ database file syntax. link(const, lnkConstIf) -variable(lnkConst_debug, int) =head3 Constant Link C<"const"> @@ -80,7 +79,6 @@ converted to the desired double value at initialization, for example: link(calc, lnkCalcIf) -variable(lnkCalc_debug, int) =head3 Calculation Link C<"calc"> @@ -169,7 +167,6 @@ atomically with the value of the input argument. link(state, lnkStateIf) -variable(lnkState_debug, int) =head3 dbState Link C<"state"> diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index 6b68ac990..fa1a363fe 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -37,11 +37,6 @@ typedef long (*FASTCONVERT)(); -int lnkCalc_debug; -epicsExportAddress(int, lnkCalc_debug); - -#define IFDEBUG(n) if (lnkCalc_debug >= (n)) - typedef struct calc_link { jlink jlink; /* embedded object */ int nArgs; @@ -82,9 +77,6 @@ static jlink* lnkCalc_alloc(short dbfType) { calc_link *clink; - IFDEBUG(10) - printf("lnkCalc_alloc(%d)\n", dbfType); - if (dbfType == DBF_FWDLINK) { errlogPrintf("lnkCalc: No support for forward links\n"); return NULL; @@ -102,9 +94,6 @@ static jlink* lnkCalc_alloc(short dbfType) clink->prec = 15; /* standard value for a double */ clink->tinp = -1; - IFDEBUG(10) - printf("lnkCalc_alloc -> calc@%p\n", clink); - return &clink->jlink; } @@ -113,9 +102,6 @@ static void lnkCalc_free(jlink *pjlink) calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); int i; - IFDEBUG(10) - printf("lnkCalc_free(calc@%p)\n", clink); - for (i = 0; i < clink->nArgs; i++) dbJLinkFree(clink->inp[i].value.json.jlink); @@ -135,9 +121,6 @@ static jlif_result lnkCalc_integer(jlink *pjlink, long long num) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_integer(calc@%p, %lld)\n", clink, num); - if (clink->pstate == ps_prec) { clink->prec = num; return jlif_continue; @@ -163,9 +146,6 @@ static jlif_result lnkCalc_double(jlink *pjlink, double num) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_double(calc@%p, %g)\n", clink, num); - if (clink->pstate != ps_args) { return jlif_stop; errlogPrintf("lnkCalc: Unexpected double %g\n", num); @@ -188,9 +168,6 @@ static jlif_result lnkCalc_string(jlink *pjlink, const char *val, size_t len) char *inbuf, *postbuf; short err; - IFDEBUG(10) - printf("lnkCalc_string(calc@%p, \"%.*s\")\n", clink, (int) len, val); - if (clink->pstate == ps_units) { clink->units = epicsStrnDup(val, len); return jlif_continue; @@ -251,9 +228,6 @@ static jlif_key_result lnkCalc_start_map(jlink *pjlink) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_start_map(calc@%p)\n", clink); - if (clink->pstate == ps_args) return jlif_key_child_inlink; if (clink->pstate == ps_out) @@ -271,9 +245,6 @@ static jlif_result lnkCalc_map_key(jlink *pjlink, const char *key, size_t len) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_map_key(calc@%p, \"%.*s\")\n", pjlink, (int) len, key); - /* FIXME: These errors messages are wrong when a key is duplicated. * The key is known, we just don't allow it more than once. */ @@ -326,9 +297,6 @@ static jlif_result lnkCalc_end_map(jlink *pjlink) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_end_map(calc@%p)\n", clink); - if (clink->pstate == ps_error) return jlif_stop; else if (clink->dbfType == DBF_INLINK && @@ -349,9 +317,6 @@ static jlif_result lnkCalc_start_array(jlink *pjlink) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_start_array(calc@%p)\n", clink); - if (clink->pstate != ps_args) { errlogPrintf("lnkCalc: Unexpected array\n"); return jlif_stop; @@ -364,9 +329,6 @@ static jlif_result lnkCalc_end_array(jlink *pjlink) { calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_end_array(calc@%p)\n", clink); - if (clink->pstate == ps_error) return jlif_stop; @@ -406,9 +368,6 @@ errOut: static struct lset* lnkCalc_get_lset(const jlink *pjlink) { - IFDEBUG(10) - printf("lnkCalc_get_lset(calc@%p)\n", pjlink); - return &lnkCalc_lset; } @@ -417,9 +376,6 @@ static void lnkCalc_report(const jlink *pjlink, int level, int indent) calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); int i; - IFDEBUG(10) - printf("lnkCalc_report(calc@%p)\n", clink); - printf("%*s'calc': \"%s\" = %.*g %s\n", indent, "", clink->expr, clink->prec, clink->val, clink->units ? clink->units : ""); @@ -470,9 +426,6 @@ static long lnkCalc_map_children(jlink *pjlink, jlink_map_fn rtn, void *ctx) calc_link *clink = CONTAINER(pjlink, struct calc_link, jlink); int i; - IFDEBUG(10) - printf("lnkCalc_map_children(calc@%p)\n", clink); - for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; long status = dbJLinkMapChildren(child, rtn, ctx); @@ -495,9 +448,6 @@ static void lnkCalc_open(struct link *plink) struct calc_link, jlink); int i; - IFDEBUG(10) - printf("lnkCalc_open(calc@%p)\n", clink); - for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; @@ -517,9 +467,6 @@ static void lnkCalc_remove(struct dbLocker *locker, struct link *plink) struct calc_link, jlink); int i; - IFDEBUG(10) - printf("lnkCalc_remove(calc@%p)\n", clink); - for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; @@ -548,9 +495,6 @@ static int lnkCalc_isConn(const struct link *plink) int connected = 1; int i; - IFDEBUG(10) - printf("lnkCalc_isConn(calc@%p)\n", clink); - for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; @@ -572,24 +516,11 @@ static int lnkCalc_isConn(const struct link *plink) static int lnkCalc_getDBFtype(const struct link *plink) { - calc_link *clink = CONTAINER(plink->value.json.jlink, - struct calc_link, jlink); - - IFDEBUG(10) - printf("lnkCalc_getDBFtype(calc@%p)\n", clink); - return DBF_DOUBLE; } static long lnkCalc_getElements(const struct link *plink, long *nelements) { - calc_link *clink = CONTAINER(plink->value.json.jlink, - struct calc_link, jlink); - - IFDEBUG(10) - printf("lnkCalc_getElements(calc@%p, (%ld))\n", - clink, *nelements); - *nelements = 1; return 0; } @@ -622,10 +553,6 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer, long status; FASTCONVERT conv = dbFastPutConvertRoutine[DBR_DOUBLE][dbrType]; - IFDEBUG(10) - printf("lnkCalc_getValue(calc@%p, %d, ...)\n", - clink, dbrType); - /* Any link errors will trigger a LINK/INVALID alarm in the child link */ for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; @@ -697,9 +624,6 @@ static long lnkCalc_putValue(struct link *plink, short dbrType, long status; FASTCONVERT conv = dbFastGetConvertRoutine[dbrType][DBR_DOUBLE]; - IFDEBUG(10) - printf("lnkCalc_putValue(calc@%p, %d, ...)\n", clink, dbrType); - /* Any link errors will trigger a LINK/INVALID alarm in the child link */ for (i = 0; i < clink->nArgs; i++) { struct link *child = &clink->inp[i]; @@ -763,9 +687,6 @@ static long lnkCalc_getPrecision(const struct link *plink, short *precision) calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_getPrecision(calc@%p)\n", clink); - *precision = clink->prec; return 0; } @@ -775,9 +696,6 @@ static long lnkCalc_getUnits(const struct link *plink, char *units, int len) calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_getUnits(calc@%p)\n", clink); - if (clink->units) { strncpy(units, clink->units, --len); units[len] = '\0'; @@ -793,9 +711,6 @@ static long lnkCalc_getAlarm(const struct link *plink, epicsEnum16 *status, calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_getAlarm(calc@%p)\n", clink); - if (status) *status = clink->stat; if (severity) @@ -809,9 +724,6 @@ static long lnkCalc_getTimestamp(const struct link *plink, epicsTimeStamp *pstam calc_link *clink = CONTAINER(plink->value.json.jlink, struct calc_link, jlink); - IFDEBUG(10) - printf("lnkCalc_getTimestamp(calc@%p)\n", clink); - if (clink->tinp >= 0) { *pstamp = clink->time; return 0; diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c index 3b9392cfa..cb948fcb3 100644 --- a/src/std/link/lnkConst.c +++ b/src/std/link/lnkConst.c @@ -22,11 +22,6 @@ #include "epicsExport.h" -int lnkConst_debug; -epicsExportAddress(int, lnkConst_debug); - -#define IFDEBUG(n) if (lnkConst_debug >= (n)) - typedef long (*FASTCONVERT)(); typedef struct const_link { @@ -53,9 +48,6 @@ static jlink* lnkConst_alloc(short dbfType) { const_link *clink; - IFDEBUG(10) - printf("lnkConst_alloc(%d)\n", dbfType); - if (dbfType != DBF_INLINK) { errlogPrintf("lnkConst: Only works with input links\n"); return NULL; @@ -71,9 +63,6 @@ static jlink* lnkConst_alloc(short dbfType) clink->nElems = 0; clink->value.pmem = NULL; - IFDEBUG(10) - printf("lnkConst_alloc -> const@%p\n", clink); - return &clink->jlink; } @@ -81,9 +70,6 @@ static void lnkConst_free(jlink *pjlink) { const_link *clink = CONTAINER(pjlink, const_link, jlink); - IFDEBUG(10) - printf("lnkConst_free(const@%p) type=%d\n", pjlink, clink->type); - switch (clink->type) { int i; case ac40: @@ -109,16 +95,13 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) const_link *clink = CONTAINER(pjlink, const_link, jlink); int newElems = clink->nElems + 1; - IFDEBUG(10) - printf("lnkConst_integer(const@%p, %lld)\n", pjlink, num); - switch (clink->type) { void *buf; case s0: clink->type = si64; clink->value.scalar_integer = num; - IFDEBUG(12) + if (pjlink->debug) printf(" si64 := %lld\n", num); break; @@ -132,7 +115,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) clink->value.pmem = buf; clink->value.pintegers[clink->nElems] = num; - IFDEBUG(12) + if (pjlink->debug) printf(" ai64 += %lld\n", num); break; @@ -143,7 +126,7 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) clink->value.pmem = buf; clink->value.pdoubles[clink->nElems] = num; - IFDEBUG(12) + if (pjlink->debug) printf(" af64 += %lld\n", num); break; @@ -160,9 +143,6 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) static jlif_result lnkConst_boolean(jlink *pjlink, int val) { - IFDEBUG(10) - printf("lnkConst_boolean(const@%p, %d)\n", pjlink, val); - return lnkConst_integer(pjlink, val); } @@ -171,9 +151,6 @@ static jlif_result lnkConst_double(jlink *pjlink, double num) const_link *clink = CONTAINER(pjlink, const_link, jlink); int newElems = clink->nElems + 1; - IFDEBUG(10) - printf("lnkConst_double(const@%p, %g)\n", pjlink, num); - switch (clink->type) { epicsFloat64 *f64buf; int i; @@ -225,9 +202,6 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) const_link *clink = CONTAINER(pjlink, const_link, jlink); int newElems = clink->nElems + 1; - IFDEBUG(10) - printf("lnkConst_string(const@%p, \"%.*s\")\n", clink, (int) len, val); - switch (clink->type) { char **vec, *str; @@ -275,9 +249,6 @@ static jlif_result lnkConst_start_array(jlink *pjlink) { const_link *clink = CONTAINER(pjlink, const_link, jlink); - IFDEBUG(10) - printf("lnkConst_start_array(const@%p)\n", pjlink); - if (clink->type != s0) { errlogPrintf("lnkConst: Embedded array value\n"); return jlif_stop; @@ -289,17 +260,11 @@ static jlif_result lnkConst_start_array(jlink *pjlink) static jlif_result lnkConst_end_array(jlink *pjlink) { - IFDEBUG(10) - printf("lnkConst_end_array(const@%p)\n", pjlink); - return jlif_continue; } static struct lset* lnkConst_get_lset(const jlink *pjlink) { - IFDEBUG(10) - printf("lnkConst_get_lset(const@%p)\n", pjlink); - return &lnkConst_lset; } @@ -327,9 +292,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent) }; const char * const dtype = type_names[clink->type & 3]; - IFDEBUG(10) - printf("lnkConst_report(const@%p)\n", clink); - if (clink->type > a0) { const char * const plural = clink->nElems > 1 ? "s" : ""; @@ -391,11 +353,6 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent) static void lnkConst_remove(struct dbLocker *locker, struct link *plink) { - const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink); - - IFDEBUG(10) - printf("lnkConst_remove(const@%p)\n", clink); - lnkConst_free(plink->value.json.jlink); } @@ -404,55 +361,51 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink); long status; - IFDEBUG(10) - printf("lnkConst_loadScalar(const@%p, %d, %p)\n", - clink, dbrType, pbuffer); - switch (clink->type) { case si64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" si64 %lld\n", clink->value.scalar_integer); status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (&clink->value.scalar_integer, pbuffer, NULL); break; case sf64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" sf64 %g\n", clink->value.scalar_double); status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] (&clink->value.scalar_double, pbuffer, NULL); break; case sc40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" sc40 '%s'\n", clink->value.scalar_string); status = dbFastPutConvertRoutine[DBF_STRING][dbrType] (clink->value.scalar_string, pbuffer, NULL); break; case ai64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]); status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (clink->value.pintegers, pbuffer, NULL); break; case af64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]); status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] (clink->value.pdoubles, pbuffer, NULL); break; case ac40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); status = dbFastPutConvertRoutine[DBF_STRING][dbrType] (clink->value.pstrings[0], pbuffer, NULL); break; default: - IFDEBUG(12) + if (clink->jlink.debug) printf(" Bad type %d\n", clink->type); status = S_db_badField; break; @@ -467,27 +420,23 @@ static long lnkConst_loadLS(struct link *plink, char *pbuffer, epicsUInt32 size, const_link *clink = CONTAINER(plink->value.json.jlink, const_link, jlink); const char *pstr; - IFDEBUG(10) - printf("lnkConst_loadLS(const@%p, %p, %d, %d)\n", - clink, pbuffer, size, *plen); - if(!size) return 0; switch (clink->type) { case sc40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" sc40 '%s'\n", clink->value.scalar_string); pstr = clink->value.scalar_string; break; case ac40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); pstr = clink->value.pstrings[0]; break; default: - IFDEBUG(12) + if (clink->jlink.debug) printf(" Bad type %d\n", clink->type); return S_db_badField; } @@ -508,10 +457,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, FASTCONVERT conv; long status; - IFDEBUG(10) - printf("lnkConst_loadArray(const@%p, %d, %p, (%ld))\n", - clink, dbrType, pbuffer, *pnReq); - if (nElems > *pnReq) nElems = *pnReq; @@ -519,28 +464,28 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, int i; case si64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" si64 %lld\n", clink->value.scalar_integer); status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (&clink->value.scalar_integer, pdest, NULL); break; case sf64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" sf64 %g\n", clink->value.scalar_double); status = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType] (&clink->value.scalar_double, pdest, NULL); break; case sc40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" sc40 '%s'\n", clink->value.scalar_string); status = dbFastPutConvertRoutine[DBF_STRING][dbrType] (clink->value.scalar_string, pbuffer, NULL); break; case ai64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" ai64 [%lld, ...]\n", clink->value.pintegers[0]); conv = dbFastPutConvertRoutine[DBF_INT64][dbrType]; for (i = 0; i < nElems; i++) { @@ -551,7 +496,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, break; case af64: - IFDEBUG(12) + if (clink->jlink.debug) printf(" af64 [%g, ...]\n", clink->value.pdoubles[0]); conv = dbFastPutConvertRoutine[DBF_DOUBLE][dbrType]; for (i = 0; i < nElems; i++) { @@ -562,7 +507,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, break; case ac40: - IFDEBUG(12) + if (clink->jlink.debug) printf(" ac40 ['%s', ...]\n", clink->value.pstrings[0]); conv = dbFastPutConvertRoutine[DBF_STRING][dbrType]; for (i = 0; i < nElems; i++) { @@ -573,7 +518,7 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, break; default: - IFDEBUG(12) + if (clink->jlink.debug) printf(" Bad type %d\n", clink->type); status = S_db_badField; } @@ -583,10 +528,6 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, static long lnkConst_getNelements(const struct link *plink, long *nelements) { - IFDEBUG(10) - printf("lnkConst_getNelements(const@%p, (%ld))\n", - plink->value.json.jlink, *nelements); - *nelements = 0; return 0; } @@ -594,11 +535,6 @@ static long lnkConst_getNelements(const struct link *plink, long *nelements) static long lnkConst_getValue(struct link *plink, short dbrType, void *pbuffer, long *pnRequest) { - IFDEBUG(10) - printf("lnkConst_getValue(const@%p, %d, %p, ... (%ld))\n", - plink->value.json.jlink, dbrType, pbuffer, - pnRequest ? *pnRequest : 0); - if (pnRequest) *pnRequest = 0; return 0; diff --git a/src/std/link/lnkState.c b/src/std/link/lnkState.c index 518a37029..b8791bd3b 100644 --- a/src/std/link/lnkState.c +++ b/src/std/link/lnkState.c @@ -35,11 +35,6 @@ typedef long (*FASTCONVERT)(); -int lnkState_debug; -epicsExportAddress(int, lnkState_debug); - -#define IFDEBUG(n) if (lnkState_debug >= (n)) - typedef struct state_link { jlink jlink; /* embedded object */ char *name; @@ -57,9 +52,6 @@ static jlink* lnkState_alloc(short dbfType) { state_link *slink; - IFDEBUG(10) - printf("lnkState_alloc(%d)\n", dbfType); - if (dbfType == DBF_FWDLINK) { errlogPrintf("lnkState: DBF_FWDLINK not supported\n"); return NULL; @@ -76,9 +68,6 @@ static jlink* lnkState_alloc(short dbfType) slink->invert = 0; slink->val = 0; - IFDEBUG(10) - printf("lnkState_alloc -> state@%p\n", slink); - return &slink->jlink; } @@ -86,9 +75,6 @@ static void lnkState_free(jlink *pjlink) { state_link *slink = CONTAINER(pjlink, struct state_link, jlink); - IFDEBUG(10) - printf("lnkState_free(state@%p)\n", slink); - free(slink->name); free(slink); } @@ -97,9 +83,6 @@ static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) { state_link *slink = CONTAINER(pjlink, struct state_link, jlink); - IFDEBUG(10) - printf("lnkState_string(state@%p, \"%.*s\")\n", slink, (int) len, val); - if (len > 1 && val[0] == '!') { slink->invert = 1; val++; len--; @@ -111,9 +94,6 @@ static jlif_result lnkState_string(jlink *pjlink, const char *val, size_t len) static struct lset* lnkState_get_lset(const jlink *pjlink) { - IFDEBUG(10) - printf("lnkState_get_lset(state@%p)\n", pjlink); - return &lnkState_lset; } @@ -121,9 +101,6 @@ static void lnkState_report(const jlink *pjlink, int level, int indent) { state_link *slink = CONTAINER(pjlink, struct state_link, jlink); - IFDEBUG(10) - printf("lnkState_report(state@%p)\n", slink); - printf("%*s'state': \"%s\" = %s%s\n", indent, "", slink->name, slink->invert ? "! " : "", slink->val ? "TRUE" : "FALSE"); } @@ -135,9 +112,6 @@ static void lnkState_open(struct link *plink) state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); - IFDEBUG(10) - printf("lnkState_open(state@%p)\n", slink); - slink->state = dbStateCreate(slink->name); } @@ -146,9 +120,6 @@ static void lnkState_remove(struct dbLocker *locker, struct link *plink) state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); - IFDEBUG(10) - printf("lnkState_remove(state@%p)\n", slink); - free(slink->name); free(slink); @@ -157,24 +128,11 @@ static void lnkState_remove(struct dbLocker *locker, struct link *plink) static int lnkState_getDBFtype(const struct link *plink) { - state_link *slink = CONTAINER(plink->value.json.jlink, - struct state_link, jlink); - - IFDEBUG(10) - printf("lnkState_getDBFtype(state@%p)\n", slink); - return DBF_SHORT; } static long lnkState_getElements(const struct link *plink, long *nelements) { - state_link *slink = CONTAINER(plink->value.json.jlink, - struct state_link, jlink); - - IFDEBUG(10) - printf("lnkState_getElements(state@%p, (%ld))\n", - slink, *nelements); - *nelements = 1; return 0; } @@ -184,19 +142,10 @@ static long lnkState_getValue(struct link *plink, short dbrType, void *pbuffer, { state_link *slink = CONTAINER(plink->value.json.jlink, struct state_link, jlink); - long status; - short flag; FASTCONVERT conv = dbFastPutConvertRoutine[DBR_SHORT][dbrType]; - IFDEBUG(10) - printf("lnkState_getValue(state@%p, %d, ...)\n", - slink, dbrType); - - flag = dbStateGet(slink->state); - slink->val = slink->invert ^ flag; - status = conv(&slink->val, pbuffer, NULL); - - return status; + slink->val = slink->invert ^ dbStateGet(slink->state); + return conv(&slink->val, pbuffer, NULL); } static long lnkState_putValue(struct link *plink, short dbrType, @@ -207,10 +156,6 @@ static long lnkState_putValue(struct link *plink, short dbrType, short val; const char *pstr; - IFDEBUG(10) - printf("lnkState_putValue(state@%p, %d, ...)\n", - slink, dbrType); - if (nRequest == 0) return 0; From 5796f717efd9c0fc35a7272a151d50c63e61b359 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 2 Jun 2018 00:40:41 -0500 Subject: [PATCH 039/147] Update Release Notes with link-updates changes --- documentation/RELEASE_NOTES.html | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index f5936bcc2..8be6a340e 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -17,6 +17,38 @@ --> +

Link type enhancements

+ +

This release adds three new link types: "state", "debug" and "trace". The +"state" link type gets and puts boolean values from/to the dbState library that +was added in the 3.15.1 release. The "debug" link type sets the +jlink::debug flag in its child link, while the "trace" link type +also causes the arguments and return values for all calls to the child link's +jlif and lset routines to be printed on stdout. The debug flag can no longer be +set using an info tag. The addition of the "trace" link type has allowed over +200 lines of conditional diagnostic printf() calls to be removed from the other +link types.

+ +

The "calc" link type can now be used for output links as well as input links. +This allows modification of the output value and even combining it with values +from other input links. See the separate JSON Link types document for +details.

+ +

A new start_child() method was added to the end of the jlif +interface table.

+ +

The lset methods have now been properly documented in the +dbLink.h header file using Doxygen annotations, although we do not run Doxygen +on the source tree yet to generate API documentation.

+ +

Link types that utilize child links must now indicate whether the child will +be used for input, output or forward linking by the return value from its +parse_start_map() method. The jlif_key_result enum now +contains 3 values jlif_key_child_inlink, +jlif_key_child_outlink and jlif_key_child_fwdlink +instead of the single jlif_key_child_link that was previously used +for this.

+

Restore use of ledlib for VxWorks command editing

The epicsReadline refactoring work described below unfortunately disabled the From c6c25ab43d7d0ffd87077b37fbacc2b4154ae5f5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 2 Jun 2018 23:28:20 -0500 Subject: [PATCH 040/147] New src/std/link/test directory with tests for the state link type --- src/Makefile | 6 +- src/std/link/test/Makefile | 53 +++++++++++ src/std/link/test/epicsRunLinkTests.c | 28 ++++++ src/std/link/test/ioRecord.c | 22 +++++ src/std/link/test/ioRecord.db | 1 + src/std/link/test/ioRecord.dbd | 14 +++ src/std/link/test/lnkStateTest.c | 130 ++++++++++++++++++++++++++ src/std/link/test/rtemsTestHarness.c | 14 +++ 8 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 src/std/link/test/Makefile create mode 100644 src/std/link/test/epicsRunLinkTests.c create mode 100644 src/std/link/test/ioRecord.c create mode 100644 src/std/link/test/ioRecord.db create mode 100644 src/std/link/test/ioRecord.dbd create mode 100644 src/std/link/test/lnkStateTest.c create mode 100644 src/std/link/test/rtemsTestHarness.c diff --git a/src/Makefile b/src/Makefile index 257099840..482e14843 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,7 +4,7 @@ # 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. +# in the file LICENSE that is included with this distribution. #************************************************************************* TOP = .. @@ -72,9 +72,11 @@ std_DEPEND_DIRS = ioc libCom/RTEMS DIRS += std/filters/test std/filters/test_DEPEND_DIRS = std +DIRS += std/link/test +std/link/test_DEPEND_DIRS = std + DIRS += std/rec/test std/rec/test_DEPEND_DIRS = std include $(TOP)/configure/RULES_DIRS - diff --git a/src/std/link/test/Makefile b/src/std/link/test/Makefile new file mode 100644 index 000000000..30aec6038 --- /dev/null +++ b/src/std/link/test/Makefile @@ -0,0 +1,53 @@ +#************************************************************************* +# Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne +# 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 + +TESTLIBRARY = Recs + +Recs_SRCS += ioRecord.c +Recs_LIBS += dbCore ca Com + +PROD_LIBS = Recs dbRecStd dbCore ca Com + +DBDDEPENDS_FILES += linkTest.dbd$(DEP) +TARGETS += $(COMMON_DIR)/linkTest.dbd +linkTest_DBD += menuGlobal.dbd +linkTest_DBD += menuConvert.dbd +linkTest_DBD += menuScan.dbd +linkTest_DBD += links.dbd +linkTest_DBD += ioRecord.dbd +TESTFILES += $(COMMON_DIR)/linkTest.dbd + +testHarness_SRCS += linkTest_registerRecordDeviceDriver.cpp + +TESTPROD_HOST += lnkStateTest +lnkStateTest_SRCS += lnkStateTest.c +lnkStateTest_SRCS += linkTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += lnkStateTest.c +TESTFILES += ../ioRecord.db +TESTS += lnkStateTest + +# epicsRunLinkTests runs all the test programs in a known working order. +testHarness_SRCS += epicsRunLinkTests.c + +linkTestHarness_SRCS += $(testHarness_SRCS) +linkTestHarness_SRCS_RTEMS += rtemsTestHarness.c + +PROD_vxWorks = linkTestHarness +PROD_RTEMS = linkTestHarness + +TESTSPEC_vxWorks = linkTestHarness.munch; epicsRunLinkTests +TESTSPEC_RTEMS = linkTestHarness.boot; epicsRunLinkTests + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + +include $(TOP)/configure/RULES + +ioRecord$(DEP): $(COMMON_DIR)/ioRecord.h +lnkStateTest$(DEP): $(COMMON_DIR)/ioRecord.h diff --git a/src/std/link/test/epicsRunLinkTests.c b/src/std/link/test/epicsRunLinkTests.c new file mode 100644 index 000000000..2cfc7a8a0 --- /dev/null +++ b/src/std/link/test/epicsRunLinkTests.c @@ -0,0 +1,28 @@ +/*************************************************************************\ +* Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Run filter tests as a batch. + */ + +#include "epicsUnitTest.h" +#include "epicsExit.h" +#include "dbmf.h" + +int lnkStateTest(void); +int lnkCalcTest(void); + +void epicsRunLinkTests(void) +{ + testHarness(); + + runTest(lnkStateTest); + + dbmfFreeChunks(); + + epicsExit(0); /* Trigger test harness */ +} diff --git a/src/std/link/test/ioRecord.c b/src/std/link/test/ioRecord.c new file mode 100644 index 000000000..1807c9171 --- /dev/null +++ b/src/std/link/test/ioRecord.c @@ -0,0 +1,22 @@ +/*************************************************************************\ +* Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. + \*************************************************************************/ + +/* + * Author: Andrew Johnson + */ + +#include +#include + +#define GEN_SIZE_OFFSET +#include "ioRecord.h" +#undef GEN_SIZE_OFFSET + +#include + +static rset ioRSET; +epicsExportAddress(rset,ioRSET); diff --git a/src/std/link/test/ioRecord.db b/src/std/link/test/ioRecord.db new file mode 100644 index 000000000..7a95a1025 --- /dev/null +++ b/src/std/link/test/ioRecord.db @@ -0,0 +1 @@ +record(io, io) {} diff --git a/src/std/link/test/ioRecord.dbd b/src/std/link/test/ioRecord.dbd new file mode 100644 index 000000000..efaec10a0 --- /dev/null +++ b/src/std/link/test/ioRecord.dbd @@ -0,0 +1,14 @@ +# This is a soft record type with both input and output links + +recordtype(io) { + include "dbCommon.dbd" + field(VAL, DBF_LONG) { + prompt("Value") + } + field(INPUT, DBF_INLINK) { + prompt("Input Link") + } + field(OUTPUT, DBF_OUTLINK) { + prompt("Output Link") + } +} diff --git a/src/std/link/test/lnkStateTest.c b/src/std/link/test/lnkStateTest.c new file mode 100644 index 000000000..a2d514e6b --- /dev/null +++ b/src/std/link/test/lnkStateTest.c @@ -0,0 +1,130 @@ +/*************************************************************************\ +* Copyright (c) 2018 Andrew Johnson +* EPICS BASE is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include + +#include "dbAccess.h" +#include "alarm.h" +#include "dbUnitTest.h" +#include "errlog.h" +#include "epicsThread.h" +#include "dbLink.h" +#include "dbState.h" +#include "ioRecord.h" + +#include "testMain.h" + +void linkTest_registerRecordDeviceDriver(struct dbBase *); + +static void startTestIoc(const char *dbfile) +{ + testdbPrepare(); + testdbReadDatabase("linkTest.dbd", NULL, NULL); + linkTest_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase(dbfile, NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); +} + +static void testState() +{ + dbStateId red; + ioRecord *pio; + DBLINK *pinp, *pout; + long status; + + testDiag("testing lnkState"); + + startTestIoc("ioRecord.db"); + + pio = (ioRecord *) testdbRecordPtr("io"); + pinp = &pio->input; + pout = &pio->output; + + red = dbStateFind("red"); + testOk(!red, "No state red exists"); + + testdbPutFieldOk("io.INPUT", DBF_STRING, "{\"state\":\"red\"}"); + if (testOk1(pinp->type == JSON_LINK)) + testDiag("Link was set to '%s'", pinp->value.json.string); + red = dbStateFind("red"); + testOk(!!red, "state red exists"); + + { + epicsInt16 i16; + + dbStateSet(red); + status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL); + testOk(!status, "dbGetLink succeeded"); + testOk(i16, "Got TRUE"); + + testdbPutFieldOk("io.INPUT", DBF_STRING, "{\"state\":\"!red\"}"); + if (testOk1(pinp->type == JSON_LINK)) + testDiag("Link was set to '%s'", pinp->value.json.string); + + status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL); + testOk(!status, "dbGetLink succeeded"); + testOk(!i16, "Got FALSE"); + + testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"red\"}"); + if (testOk1(pout->type == JSON_LINK)) + testDiag("Link was set to '%s'", pout->value.json.string); + + i16 = 0; + status = dbPutLink(pout, DBF_SHORT, &i16, 1); + testOk(!status, "dbPutLink %d succeeded", i16); + testOk(!dbStateGet(red), "state was cleared"); + + i16 = 0x8000; + status = dbPutLink(pout, DBF_SHORT, &i16, 1); + testOk(!status, "dbPutLink 0x%hx succeeded", i16); + testOk(dbStateGet(red), "state was set"); + } + + status = dbPutLink(pout, DBF_STRING, "", 1); + testOk(!status, "dbPutLink '' succeeded"); + testOk(!dbStateGet(red), "state was cleared"); + + status = dbPutLink(pout, DBF_STRING, "FALSE", 1); /* Not really... */ + testOk(!status, "dbPutLink 'FALSE' succeeded"); + testOk(dbStateGet(red), "state was set"); + + status = dbPutLink(pout, DBF_STRING, "0", 1); + testOk(!status, "dbPutLink '0' succeeded"); + testOk(!dbStateGet(red), "state was cleared"); + + { + epicsFloat64 f64 = 0.1; + + status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); + testOk(!status, "dbPutLink %g succeeded", f64); + testOk(dbStateGet(red), "state was set"); + + testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"!red\"}"); + if (testOk1(pout->type == JSON_LINK)) + testDiag("Link was set to '%s'", pout->value.json.string); + + status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); + testOk(!status, "dbPutLink %g succeeded", f64); + testOk(!dbStateGet(red), "state was cleared"); + } + + testIocShutdownOk(); + + testdbCleanup(); +} + + +MAIN(lnkStateTest) +{ + testPlan(0); + + testState(); + + return testDone(); +} diff --git a/src/std/link/test/rtemsTestHarness.c b/src/std/link/test/rtemsTestHarness.c new file mode 100644 index 000000000..7397f74d6 --- /dev/null +++ b/src/std/link/test/rtemsTestHarness.c @@ -0,0 +1,14 @@ +/*************************************************************************\ +* Copyright (c) 2018 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +extern void epicsRunLinkTests(void); + +int main(int argc, char **argv) +{ + epicsRunLinkTests(); /* calls epicsExit(0) */ + return 0; +} From bcfdc8d3688e92cc4e99a7d9afc956c687eee49c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 2 Jun 2018 23:59:14 -0500 Subject: [PATCH 041/147] lnkStateTest: set testPlan --- src/std/link/test/lnkStateTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/std/link/test/lnkStateTest.c b/src/std/link/test/lnkStateTest.c index a2d514e6b..ba686d9e4 100644 --- a/src/std/link/test/lnkStateTest.c +++ b/src/std/link/test/lnkStateTest.c @@ -122,7 +122,7 @@ static void testState() MAIN(lnkStateTest) { - testPlan(0); + testPlan(28); testState(); From ffe6fceffaa24f8cefdae05bb91a8ba36bd4cce8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 10:01:33 -0500 Subject: [PATCH 042/147] dbJLink: Some extra checks at parse/init time --- src/ioc/db/dbJLink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index 1c448dd4d..3acf75660 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -207,7 +207,8 @@ static int dbjl_start_map(void *ctx) { parser->dbfType = DBF_FWDLINK; result = jlif_continue; break; - case jlif_continue: + case jlif_key_stop: + case jlif_key_continue: break; default: errlogPrintf("dbJLinkInit: Bad return %d from '%s'::parse_start_map()\n", @@ -446,13 +447,14 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, long dbJLinkInit(struct link *plink) { - jlink *pjlink; - assert(plink); - pjlink = plink->value.json.jlink; - if (pjlink) - plink->lset = pjlink->pif->get_lset(pjlink); + if (plink->type == JSON_LINK) { + jlink *pjlink = plink->value.json.jlink; + + if (pjlink) + plink->lset = pjlink->pif->get_lset(pjlink); + } dbLinkOpen(plink); return 0; From 36f23f3aece56990faa6cf43cbb8f15eccdd8417 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 10:46:29 -0500 Subject: [PATCH 043/147] lnkDebug fix: Initialize child link's precord pointer --- src/std/link/lnkDebug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/std/link/lnkDebug.c b/src/std/link/lnkDebug.c index 9ede69cb2..96ce5e5c1 100644 --- a/src/std/link/lnkDebug.c +++ b/src/std/link/lnkDebug.c @@ -346,6 +346,7 @@ static void delegate_openLink(struct link *plink) printf("Link trace: Calling %s::openLink(%p = jlink %p)\n", dlink->child_jlif->name, clink, clink->value.json.jlink); + clink->precord = plink->precord; clset->openLink(clink); if (dlink->trace) From 2fb46fc541bd07835c5820fe09bd3cd5ff8e78b6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 11:03:20 -0500 Subject: [PATCH 044/147] lnkDebug: Fix typo in getAlarm range checks --- src/std/link/lnkDebug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/std/link/lnkDebug.c b/src/std/link/lnkDebug.c index 96ce5e5c1..3238a0b62 100644 --- a/src/std/link/lnkDebug.c +++ b/src/std/link/lnkDebug.c @@ -684,10 +684,10 @@ static long delegate_getAlarm(const struct link *plink, epicsEnum16 *stat, if (res == 0) printf(" Got:%s%s%s%s\n", stat ? " Status = " : "", - stat && (*stat < ALARM_NSEV) ? + stat && (*stat < ALARM_NSTATUS) ? epicsAlarmConditionStrings[*stat] : "Bad-status", sevr ? " Severity = " : "", - sevr && (*sevr < ALARM_NSTATUS) ? + sevr && (*sevr < ALARM_NSEV) ? epicsAlarmSeverityStrings[*sevr] : "Bad-severity" ); } From 6e3aa77c42bd8f4b764b30d8a055ece6aeeb745d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 11:18:40 -0500 Subject: [PATCH 045/147] lnkCalc fix: Don't evaluate minor expression when major returned true --- src/std/link/lnkCalc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/std/link/lnkCalc.c b/src/std/link/lnkCalc.c index fa1a363fe..2ac568840 100644 --- a/src/std/link/lnkCalc.c +++ b/src/std/link/lnkCalc.c @@ -600,7 +600,7 @@ static long lnkCalc_getValue(struct link *plink, short dbrType, void *pbuffer, } } - if (!status && clink->post_minor) { + if (!status && !clink->sevr && clink->post_minor) { double alval = clink->val; status = calcPerform(clink->arg, &alval, clink->post_minor); @@ -664,7 +664,7 @@ static long lnkCalc_putValue(struct link *plink, short dbrType, } } - if (!status && clink->post_minor) { + if (!status && !clink->sevr && clink->post_minor) { double alval = clink->val; status = calcPerform(clink->arg, &alval, clink->post_minor); From 3b77d9be8cb3cf7e5e26339302b098155abcee16 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 12:34:19 -0500 Subject: [PATCH 046/147] lnkStateTest: Show status value in test output --- src/std/link/test/lnkStateTest.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/std/link/test/lnkStateTest.c b/src/std/link/test/lnkStateTest.c index ba686d9e4..d3da06f5c 100644 --- a/src/std/link/test/lnkStateTest.c +++ b/src/std/link/test/lnkStateTest.c @@ -60,7 +60,7 @@ static void testState() dbStateSet(red); status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL); - testOk(!status, "dbGetLink succeeded"); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); testOk(i16, "Got TRUE"); testdbPutFieldOk("io.INPUT", DBF_STRING, "{\"state\":\"!red\"}"); @@ -68,7 +68,7 @@ static void testState() testDiag("Link was set to '%s'", pinp->value.json.string); status = dbGetLink(pinp, DBF_SHORT, &i16, NULL, NULL); - testOk(!status, "dbGetLink succeeded"); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); testOk(!i16, "Got FALSE"); testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"red\"}"); @@ -77,32 +77,32 @@ static void testState() i16 = 0; status = dbPutLink(pout, DBF_SHORT, &i16, 1); - testOk(!status, "dbPutLink %d succeeded", i16); + testOk(!status, "dbPutLink %d succeeded (status = %ld)", i16, status); testOk(!dbStateGet(red), "state was cleared"); i16 = 0x8000; status = dbPutLink(pout, DBF_SHORT, &i16, 1); - testOk(!status, "dbPutLink 0x%hx succeeded", i16); + testOk(!status, "dbPutLink 0x%hx succeeded (status = %ld)", i16, status); testOk(dbStateGet(red), "state was set"); } status = dbPutLink(pout, DBF_STRING, "", 1); - testOk(!status, "dbPutLink '' succeeded"); + testOk(!status, "dbPutLink '' succeeded (status = %ld)", status); testOk(!dbStateGet(red), "state was cleared"); status = dbPutLink(pout, DBF_STRING, "FALSE", 1); /* Not really... */ - testOk(!status, "dbPutLink 'FALSE' succeeded"); + testOk(!status, "dbPutLink 'FALSE' succeeded (status = %ld)", status); testOk(dbStateGet(red), "state was set"); status = dbPutLink(pout, DBF_STRING, "0", 1); - testOk(!status, "dbPutLink '0' succeeded"); + testOk(!status, "dbPutLink '0' succeeded (status = %ld)", status); testOk(!dbStateGet(red), "state was cleared"); { epicsFloat64 f64 = 0.1; status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); - testOk(!status, "dbPutLink %g succeeded", f64); + testOk(!status, "dbPutLink %g succeeded (status = %ld)", f64, status); testOk(dbStateGet(red), "state was set"); testdbPutFieldOk("io.OUTPUT", DBF_STRING, "{\"state\":\"!red\"}"); @@ -110,7 +110,7 @@ static void testState() testDiag("Link was set to '%s'", pout->value.json.string); status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); - testOk(!status, "dbPutLink %g succeeded", f64); + testOk(!status, "dbPutLink %g succeeded (status = %ld)", f64, status); testOk(!dbStateGet(red), "state was cleared"); } From b02944805996fa8dcf7856cae420a334d95b8beb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 3 Jun 2018 12:35:56 -0500 Subject: [PATCH 047/147] Added lnkCalcTest --- src/std/link/test/Makefile | 8 +- src/std/link/test/epicsRunLinkTests.c | 1 + src/std/link/test/lnkCalcTest.c | 164 ++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/std/link/test/lnkCalcTest.c diff --git a/src/std/link/test/Makefile b/src/std/link/test/Makefile index 30aec6038..2a6507e07 100644 --- a/src/std/link/test/Makefile +++ b/src/std/link/test/Makefile @@ -23,6 +23,7 @@ linkTest_DBD += menuScan.dbd linkTest_DBD += links.dbd linkTest_DBD += ioRecord.dbd TESTFILES += $(COMMON_DIR)/linkTest.dbd +TESTFILES += ../ioRecord.db testHarness_SRCS += linkTest_registerRecordDeviceDriver.cpp @@ -30,9 +31,14 @@ TESTPROD_HOST += lnkStateTest lnkStateTest_SRCS += lnkStateTest.c lnkStateTest_SRCS += linkTest_registerRecordDeviceDriver.cpp testHarness_SRCS += lnkStateTest.c -TESTFILES += ../ioRecord.db TESTS += lnkStateTest +TESTPROD_HOST += lnkCalcTest +lnkCalcTest_SRCS += lnkCalcTest.c +lnkCalcTest_SRCS += linkTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += lnkCalcTest.c +TESTS += lnkCalcTest + # epicsRunLinkTests runs all the test programs in a known working order. testHarness_SRCS += epicsRunLinkTests.c diff --git a/src/std/link/test/epicsRunLinkTests.c b/src/std/link/test/epicsRunLinkTests.c index 2cfc7a8a0..a0f3b7c72 100644 --- a/src/std/link/test/epicsRunLinkTests.c +++ b/src/std/link/test/epicsRunLinkTests.c @@ -21,6 +21,7 @@ void epicsRunLinkTests(void) testHarness(); runTest(lnkStateTest); + runTest(lnkCalcTest); dbmfFreeChunks(); diff --git a/src/std/link/test/lnkCalcTest.c b/src/std/link/test/lnkCalcTest.c new file mode 100644 index 000000000..c0d76dda3 --- /dev/null +++ b/src/std/link/test/lnkCalcTest.c @@ -0,0 +1,164 @@ +/*************************************************************************\ +* Copyright (c) 2018 Andrew Johnson +* EPICS BASE is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include + +#include "dbAccess.h" +#include "alarm.h" +#include "dbUnitTest.h" +#include "errlog.h" +#include "epicsThread.h" +#include "dbLink.h" +#include "dbState.h" +#include "recGbl.h" +#include "testMain.h" +#include "ioRecord.h" + +#define testPutLongStr(PV, VAL) \ + testdbPutArrFieldOk(PV, DBF_CHAR, sizeof(VAL), VAL); + +void linkTest_registerRecordDeviceDriver(struct dbBase *); + +static void startTestIoc(const char *dbfile) +{ + testdbPrepare(); + testdbReadDatabase("linkTest.dbd", NULL, NULL); + linkTest_registerRecordDeviceDriver(pdbbase); + testdbReadDatabase(dbfile, NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); +} + +static void testCalc() +{ + ioRecord *pio; + DBLINK *pinp, *pout; + long status; + epicsFloat64 f64; + + startTestIoc("ioRecord.db"); + + pio = (ioRecord *) testdbRecordPtr("io"); + pinp = &pio->input; + pout = &pio->output; + + testDiag("testing lnkCalc input"); + + { + dbStateId red; + + testPutLongStr("io.INPUT", "{\"calc\":{" + "\"expr\":\"a\"," + "\"args\":[{\"state\":\"red\"}]" + "}}"); + if (testOk1(pinp->type == JSON_LINK)) + testDiag("Link was set to '%s'", pinp->value.json.string); + red = dbStateFind("red"); + testOk(!!red, "State red was created"); + + dbStateSet(red); + status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); + testOk(f64, "Got TRUE (%g)", f64); + + dbStateClear(red); + status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); + testOk(!f64, "Got FALSE (%g)", f64); + } + + { + dbStateId major = dbStateCreate("major"); + dbStateId minor = dbStateCreate("minor"); + epicsEnum16 stat, sevr; + + testPutLongStr("io.INPUT", "{\"calc\":{" + "\"expr\":\"0\"," + "\"major\":\"A\"," + "\"minor\":\"B\"," + "\"args\":[{\"state\":\"major\"},{\"state\":\"minor\"}]" + "}}"); + if (testOk1(pinp->type == JSON_LINK)) + testDiag("Link was set to '%s'", pinp->value.json.string); + + dbStateSet(major); + dbStateSet(minor); + status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); + testOk(f64 == 0.0, "Got zero (%g)", f64); + testOk(recGblResetAlarms(pio) && DBE_ALARM, "Record alarm was raised"); + status = dbGetAlarm(pinp, &stat, &sevr); + testOk(!status, "dbGetAlarm succeeded (status = %ld)", status); + testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat); + testOk(sevr == MAJOR_ALARM, "Alarm severity = MAJOR (%d)", sevr); + + dbStateClear(major); + status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); + testOk(recGblResetAlarms(pio) && DBE_ALARM, "Record alarm was raised"); + status = dbGetAlarm(pinp, &stat, &sevr); + testOk(!status, "dbGetAlarm succeeded (status = %ld)", status); + testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat); + testOk(sevr == MINOR_ALARM, "Alarm severity = MINOR (%d)", sevr); + } + + testDiag("testing lnkCalc output"); + + { + dbStateId red = dbStateFind("red"); + dbStateId out = dbStateCreate("out"); + + testPutLongStr("io.OUTPUT", "{\"calc\":{" + "\"expr\":\"!a\"," + "\"out\":{\"state\":\"out\"}," + "\"args\":[{\"state\":\"red\"}]," + "\"units\":\"things\"," + "\"prec\":3" + "}}"); + if (testOk1(pout->type == JSON_LINK)) + testDiag("Link was set to '%s'", pout->value.json.string); + + dbStateSet(red); + f64 = 1.0; + status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); + testOk(!status, "dbPutLink succeeded (status = %ld)", status); + testOk(!dbStateGet(out), "output was cleared"); + + dbStateClear(red); + status = dbPutLink(pout, DBF_DOUBLE, &f64, 1); + testOk(!status, "dbGetLink succeeded (status = %ld)", status); + testOk(dbStateGet(out), "output was set"); + } + + { + char units[20] = {0}; + short prec = 0; + + status = dbGetUnits(pout, units, sizeof(units)); + testOk(!status, "dbGetUnits succeeded (status = %ld)", status); + testOk(!strcmp(units, "things"), "Units string correct (%s)", units); + + status = dbGetPrecision(pout, &prec); + testOk(!status, "dbGetPrecision succeeded (status = %ld)", status); + testOk(prec == 3, "Precision correct (%d)", prec); + } + + testIocShutdownOk(); + + testdbCleanup(); +} + + +MAIN(lnkCalcTest) +{ + testPlan(0); + + testCalc(); + + return testDone(); +} From c0a7ab976c49e39f35919f639082ab00a49728c8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 4 Jun 2018 15:27:01 -0500 Subject: [PATCH 048/147] Fix warnings from clang --- src/std/link/lnkDebug.c | 2 +- src/std/link/test/lnkCalcTest.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/std/link/lnkDebug.c b/src/std/link/lnkDebug.c index 3238a0b62..bd8f84e5a 100644 --- a/src/std/link/lnkDebug.c +++ b/src/std/link/lnkDebug.c @@ -882,7 +882,7 @@ static jlif_key_result lnkDebug_start_map(jlink *pjlink) case DBF_FWDLINK: return jlif_key_child_outlink; } - return jlif_stop; + return jlif_key_stop; } static jlif_result lnkDebug_end_map(jlink *pjlink) diff --git a/src/std/link/test/lnkCalcTest.c b/src/std/link/test/lnkCalcTest.c index c0d76dda3..3fe8382d4 100644 --- a/src/std/link/test/lnkCalcTest.c +++ b/src/std/link/test/lnkCalcTest.c @@ -91,7 +91,7 @@ static void testCalc() status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); testOk(!status, "dbGetLink succeeded (status = %ld)", status); testOk(f64 == 0.0, "Got zero (%g)", f64); - testOk(recGblResetAlarms(pio) && DBE_ALARM, "Record alarm was raised"); + testOk(recGblResetAlarms(pio) & DBE_ALARM, "Record alarm was raised"); status = dbGetAlarm(pinp, &stat, &sevr); testOk(!status, "dbGetAlarm succeeded (status = %ld)", status); testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat); @@ -100,7 +100,7 @@ static void testCalc() dbStateClear(major); status = dbGetLink(pinp, DBF_DOUBLE, &f64, NULL, NULL); testOk(!status, "dbGetLink succeeded (status = %ld)", status); - testOk(recGblResetAlarms(pio) && DBE_ALARM, "Record alarm was raised"); + testOk(recGblResetAlarms(pio) & DBE_ALARM, "Record alarm was raised"); status = dbGetAlarm(pinp, &stat, &sevr); testOk(!status, "dbGetAlarm succeeded (status = %ld)", status); testOk(stat == LINK_ALARM, "Alarm status = LINK (%d)", stat); From 8f55a1307d93bc72681053b1ede5270dd9bdbf7e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 22 Jun 2018 14:54:06 -0500 Subject: [PATCH 049/147] startup: Update win*.bat files --- startup/win32.bat | 128 ++++++++++---------------------------------- startup/windows.bat | 73 +++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 101 deletions(-) create mode 100755 startup/windows.bat diff --git a/startup/win32.bat b/startup/win32.bat index af9155dd7..575b06f42 100644 --- a/startup/win32.bat +++ b/startup/win32.bat @@ -1,147 +1,73 @@ @ECHO OFF REM ************************************************************************* -REM Copyright (c) 2002 The University of Chicago, as Operator of Argonne +REM Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne REM National Laboratory. REM Copyright (c) 2002 The Regents of the University of California, as REM Operator of Los Alamos National Laboratory. -REM EPICS BASE Versions 3.13.7 -REM and higher are distributed subject to a Software License Agreement found +REM EPICS BASE is distributed subject to a Software License Agreement found REM in file LICENSE that is included with this distribution. REM ************************************************************************* REM -REM Site-specific EPICS environment settings -REM -REM sites should modify these definitions +REM EPICS build configuration environment settings +REM +REM Installers should modify these definitions as appropriate. +REM This file configures the PATH variable from scratch. REM ====================================================== REM ====== REQUIRED ENVIRONMENT VARIABLES FOLLOW ====== REM ====================================================== REM ====================================================== -REM ---------------- WINDOWS --------------------------- +REM ---------------- WINDOWS ------------------------- REM ====================================================== -REM ----- WIN95 ----- -REM set PATH=C:\WINDOWS;C:\WINDOWS\COMMAND -REM ----- WINNT, WIN2000 ----- -REM set PATH=C:\WINNT;C:\WINNT\SYSTEM32 REM ----- WINXP, Vista, Windows 7 ----- -set PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\SYSTEM32\Wbem +set PATH=C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem REM ====================================================== -REM ---------------- make and perl --------------------- +REM --------------- Strawberry Perl ------------------ REM ====================================================== -REM --------------- ActiveState perl ------------------- -set PATH=C:\Perl\bin;%PATH% - -REM --------------- mingw make ------------------------ -REM set PATH=C:\mingw-make\bin;%PATH% -REM set PATH=C:\mingw-make82-3\bin;%PATH% - -REM --------------- gnuwin32 make ---------------------- -set PATH=C:\gnuwin32\bin;%PATH% +set PATH=C:\Strawberry\perl\bin;%PATH% +set PATH=C:\Strawberry\perl\site\bin;%PATH% +set PATH=C:\Strawberry\c\bin;%PATH% REM ====================================================== -REM ---------------- cygwin tools ------------------------ +REM --------------- Visual C++ ----------------------- REM ====================================================== -REM (make & perl if above perl and make are REMs) -REM Dont use cygwin GNU make and Perl! -REM cygwin contains tk/tcl, vim, perl, and many unix tools -REM need grep from here NOT from cvs directory -REM set PATH=%PATH%;.;.. -REM set PATH=%PATH%;c:\cygwin\bin - -REM ====================================================== -REM --------------- Visual c++ ------------------------- -REM ====================================================== - -REM ------ Microsoft Visual Studio 2005 ------ -REM call "C:\Program files\Microsoft Visual Studio 8\VC\vcvarsall.bat" x86_amd64 -REM set PATH=%PATH%;C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin -REM set INCLUDE=%INCLUDE%;C:\Program Files\Microsoft SDKs\Windows\v6.0A\include -REM REM set LIBPATH=%LIBPATH%;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib -REM set LIB=%LIB%;C:\Program Files\Microsoft SDKs\Windows\v6.0A\lib - -REM ------ Microsoft Visual Studio 2008 ------ -REM call "C:\Program files\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" -REM call "C:\Program files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86_amd64 -REM set PATH=C:\Program Files\Microsoft SDKs\Windows\v7.0\bin;%PATH% -REM set INCLUDE=C:\Program Files\Microsoft SDKs\Windows\v7.0\include;%INCLUDE% -REM set LIBPATH=C:\Program Files\Microsoft SDKs\Windows\v7.0\lib;%LIBPATH% -REM set LIB=C:\Program Files\Microsoft SDKs\Windows\v7.0\lib;%LIB% - -REM ----- Visual Studion 2010 ----- -REM -- windows-x64 --- -REM call "C:\Program files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 REM -- win32-x86 --- -call "C:\Program files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 + +REM ----- Visual Studio 2010 ----- +REM call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 + +REM ----- Visual Studio 2015 ----- +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86 REM ====================================================== -REM --------------- EPICS -------------------------------- +REM --------------- EPICS Base ----------------------- REM ====================================================== -REM set EPICS_HOST_ARCH=windows-x64 set EPICS_HOST_ARCH=win32-x86 set PATH=%PATH%;G:\epics\base\bin\%EPICS_HOST_ARCH% -set PATH=%PATH%;G:\epics\extensions\bin\%EPICS_HOST_ARCH% REM ====================================================== -REM ------- OPTIONAL ENVIRONMENT VARIABLES FOLLOW -------- +REM ====== OPTIONAL ENVIRONMENT VARIABLES FOLLOW ===== REM ====================================================== REM ====================================================== -REM ----------------- remote CVS ------------------------- +REM --------------------- Git ------------------------ REM ====================================================== -REM set CVS_RSH=c:/cygwin/bin/ssh.exe -REM set CVSROOT=:ext:jba@aps.anl.gov:/usr/local/epicsmgr/cvsroot -REM set HOME=c:/users/%USERNAME% -REM set HOME=c:/users/jba +set PATH=%PATH%;C:\Program files\Git REM ====================================================== -REM ------------------- Bazaar --------------------------- +REM --------------- EPICS Extensions ----------------- REM ====================================================== -set PATH=%PATH%;C:\Program files\Bazaar +REM set PATH=%PATH%;G:\epics\extensions\bin\%EPICS_HOST_ARCH% REM ====================================================== -REM ----------------- GNU make flags --------------------- +REM --------------- Exceed --------------------------- REM ====================================================== -set MAKEFLAGS=-w - -REM ====================================================== -REM -------------- vim (use cygwin vim ) ----------------- -REM ====================================================== -REM HOME needed by vim to write .viminfo file. -REM VIM needed by vim to find _vimrc file. -REM set VIM=c:\cygwin - -REM ====================================================== -REM --------------- Epics Channel Access ----------------- -REM Modify and uncomment the following lines -REM to override the base/configure/CONFIG_ENV defaults -REM ====================================================== -REM set EPICS_CA_ADDR_LIST=n.n.n.n n.n.n.n -REM set EPICS_CA_AUTO_ADDR_LIST=YES - -REM set EPICS_CA_CONN_TMO=30.0 -REM set EPICS_CA_BEACON_PERIOD=15.0 -REM set EPICS_CA_REPEATER_PORT=5065 -REM set EPICS_CA_SERVER_PORT=5064 -REM set EPICS_TS_MIN_WEST=420 - -REM ====================================================== -REM --------------- JAVA --------------------------------- -REM ====================================================== -REM Needed for java extensions -REM set CLASSPATH=G:\epics\extensions\javalib -REM set PATH=%PATH%;C:\j2sdk1.4.1_01\bin -REM set CLASSPATH=%CLASSPATH%;C:\j2sdk1.4.1_01\lib\tools.jar - -REM ====================================================== -REM --------------- Exceed ------------------------------- REM Needed for X11 extensions -REM ====================================================== -REM set EX_VER=7.10 -REM set EX_VER=12.00 REM set EX_VER=14.00 +REM set EX_VER=15.00 REM set PATH=%PATH%;C:\Exceed%EX_VER%\XDK\ REM set PATH=%PATH%;C:\Program Files\Hummingbird\Connectivity\%EX_VER%\Exceed\ diff --git a/startup/windows.bat b/startup/windows.bat new file mode 100755 index 000000000..1b0d32eb2 --- /dev/null +++ b/startup/windows.bat @@ -0,0 +1,73 @@ +@ECHO OFF +REM ************************************************************************* +REM Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne +REM National Laboratory. +REM Copyright (c) 2002 The Regents of the University of California, as +REM Operator of Los Alamos National Laboratory. +REM EPICS BASE is distributed subject to a Software License Agreement found +REM in file LICENSE that is included with this distribution. +REM ************************************************************************* +REM +REM EPICS build configuration environment settings +REM +REM Installers should modify these definitions as appropriate. +REM This file configures the PATH variable from scratch. + +REM ====================================================== +REM ====== REQUIRED ENVIRONMENT VARIABLES FOLLOW ===== +REM ====================================================== + +REM ====================================================== +REM ---------------- WINDOWS ------------------------- +REM ====================================================== +REM ----- WINXP, Vista, Windows 7 ----- +set PATH=C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem + +REM ====================================================== +REM --------------- Strawberry Perl ------------------ +REM ====================================================== + +set PATH=C:\Strawberry\perl\bin;%PATH% +set PATH=C:\Strawberry\perl\site\bin;%PATH% +set PATH=C:\Strawberry\c\bin;%PATH% + +REM ====================================================== +REM --------------- Visual C++ ----------------------- +REM ====================================================== +REM -- windows-x64 --- + +REM ----- Visual Studio 2010 ----- +REM call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 + +REM ----- Visual Studio 2015 ----- +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 + +REM ====================================================== +REM --------------- EPICS Base ----------------------- +REM ====================================================== +set EPICS_HOST_ARCH=windows-x64 +set PATH=%PATH%;G:\epics\base\bin\%EPICS_HOST_ARCH% + +REM ====================================================== +REM ====== OPTIONAL ENVIRONMENT VARIABLES FOLLOW ===== +REM ====================================================== + +REM ====================================================== +REM --------------------- Git ------------------------ +REM ====================================================== +set PATH=%PATH%;C:\Program files\Git + +REM ====================================================== +REM --------------- EPICS Extensions ----------------- +REM ====================================================== +REM set PATH=%PATH%;G:\epics\extensions\bin\%EPICS_HOST_ARCH% + +REM ====================================================== +REM --------------- Exceed --------------------------- +REM ====================================================== +REM Needed for X11 extensions +REM set EX_VER=14.00 +REM set EX_VER=15.00 +REM set PATH=%PATH%;C:\Exceed%EX_VER%\XDK\ +REM set PATH=%PATH%;C:\Program Files\Hummingbird\Connectivity\%EX_VER%\Exceed\ + From dcb494b494674b330595599d53014f50b1236dd3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Mar 2018 16:40:01 -0700 Subject: [PATCH 050/147] rtemsttest generalize condition for individual tests --- ci/travis-build.sh | 1 + src/ioc/db/test/Makefile | 2 +- src/libCom/test/Makefile | 2 +- src/std/filters/test/Makefile | 2 +- src/std/rec/test/Makefile | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ci/travis-build.sh b/ci/travis-build.sh index ba752ac4a..f487fbb88 100644 --- a/ci/travis-build.sh +++ b/ci/travis-build.sh @@ -72,6 +72,7 @@ RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 EOF cat << EOF >> configure/CONFIG_SITE CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 +CROSS_COMPILER_RUNTEST_ARCHS+=RTEMS-pc386 EOF # find local qemu-system-i386 diff --git a/src/ioc/db/test/Makefile b/src/ioc/db/test/Makefile index baa381534..90ca9da35 100644 --- a/src/ioc/db/test/Makefile +++ b/src/ioc/db/test/Makefile @@ -184,7 +184,7 @@ TESTSPEC_vxWorks = dbTestHarness.munch; epicsRunDbTests TESTSPEC_RTEMS = dbTestHarness.boot; epicsRunDbTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) -ifeq ($(T_A),RTEMS-pc386) +ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) TESTPROD_RTEMS = $(TESTPROD_HOST) TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) endif diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index b8014a2ab..a2ceb4ea4 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -235,7 +235,7 @@ TESTSPEC_vxWorks = libComTestHarness.munch; epicsRunLibComTests TESTSPEC_RTEMS = libComTestHarness.boot; epicsRunLibComTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) -ifeq ($(T_A),RTEMS-pc386) +ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) TESTPROD_RTEMS = $(TESTPROD_HOST) TESTSCRIPTS_RTEMS += $(filter-out epicsUnitTestTest.t, $(TESTS:%=%.t)) endif diff --git a/src/std/filters/test/Makefile b/src/std/filters/test/Makefile index 6442ba332..d6d9973f6 100644 --- a/src/std/filters/test/Makefile +++ b/src/std/filters/test/Makefile @@ -71,7 +71,7 @@ TESTSPEC_vxWorks = filterTestHarness.munch; epicsRunFilterTests TESTSPEC_RTEMS = filterTestHarness.boot; epicsRunFilterTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) -ifeq ($(T_A),RTEMS-pc386) +ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) TESTPROD_RTEMS = $(TESTPROD_HOST) TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) endif diff --git a/src/std/rec/test/Makefile b/src/std/rec/test/Makefile index f5f9b4312..14e10946c 100644 --- a/src/std/rec/test/Makefile +++ b/src/std/rec/test/Makefile @@ -119,7 +119,7 @@ TESTSPEC_vxWorks = recordTestHarness.munch; epicsRunRecordTests TESTSPEC_RTEMS = recordTestHarness.boot; epicsRunRecordTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) -ifeq ($(T_A),RTEMS-pc386) +ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) TESTPROD_RTEMS = $(TESTPROD_HOST) TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) endif From 65dec97f9ed98414c230c04624458b635dc6c74f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 3 Dec 2017 10:22:19 -0600 Subject: [PATCH 051/147] use new RTEMS build --- ci/travis-build.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ci/travis-build.sh b/ci/travis-build.sh index f487fbb88..0b592228c 100644 --- a/ci/travis-build.sh +++ b/ci/travis-build.sh @@ -62,13 +62,13 @@ 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 + curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \ + | tar -C / -xmj sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' configure/os/CONFIG_SITE.Common.RTEMS cat << EOF >> configure/os/CONFIG_SITE.Common.RTEMS RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 +RTEMS_BASE=/home/travis/.rtems EOF cat << EOF >> configure/CONFIG_SITE CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 @@ -76,7 +76,6 @@ CROSS_COMPILER_RUNTEST_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 From 83b17d5061d9f6008581a59ff189ec5eeb43e847 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Oct 2017 20:00:37 -0500 Subject: [PATCH 052/147] travis-ci: remove unused --- .travis.yml | 1 - ci/travis-build.sh | 9 --------- ci/travis-prepare.sh | 40 ---------------------------------------- 3 files changed, 50 deletions(-) delete mode 100644 ci/travis-prepare.sh diff --git a/.travis.yml b/.travis.yml index 743908764..f8b11534f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,5 +28,4 @@ addons: cache: directories: - $HOME/.cache -install: sh ci/travis-prepare.sh &2 - exit 1 -} - -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" From 220e404203e51624fb7e90f8fe5bcde2ba2767c4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 26 Jun 2018 11:23:15 -0500 Subject: [PATCH 053/147] Move EpicsHostArch.pl into src/tools, install to lib/perl --- configure/CONFIG | 5 ++++- {startup => src/tools}/EpicsHostArch.pl | 0 src/tools/Makefile | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) rename {startup => src/tools}/EpicsHostArch.pl (100%) diff --git a/configure/CONFIG b/configure/CONFIG index 6fe6b9b55..9d8d7e04b 100644 --- a/configure/CONFIG +++ b/configure/CONFIG @@ -21,8 +21,11 @@ endif # Provide a default if the user hasn't set EPICS_HOST_ARCH ifeq ($(origin EPICS_HOST_ARCH), undefined) + # Bootstrapping ... + EHA = $(firstword $(wildcard $(EPICS_BASE)/lib/perl/EpicsHostArch.pl \ + $(TOP)/src/tools/EpicsHostArch.pl)) # NB: We use a simply expanded variable here for performance: - EPICS_HOST_ARCH := $(shell $(CONFIG)/../startup/EpicsHostArch.pl) + export EPICS_HOST_ARCH := $(shell perl $(EHA)) endif # diff --git a/startup/EpicsHostArch.pl b/src/tools/EpicsHostArch.pl similarity index 100% rename from startup/EpicsHostArch.pl rename to src/tools/EpicsHostArch.pl diff --git a/src/tools/Makefile b/src/tools/Makefile index bcf12700d..c54470364 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -16,6 +16,9 @@ PERL_MODULES += EPICS/Path.pm PERL_MODULES += EPICS/Release.pm PERL_MODULES += EPICS/Getopts.pm +# This goes into lib/perl, not bin/ +PERL_MODULES += EpicsHostArch.pl + PERL_SCRIPTS += convertRelease.pl PERL_SCRIPTS += cvsclean.pl PERL_SCRIPTS += dos2unix.pl From b32629c3bf4e718afd42acffd3f5e100d0f17a94 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 26 Jun 2018 11:23:35 -0500 Subject: [PATCH 054/147] Start release notes for tidy-startup branch. --- documentation/RELEASE_NOTES.html | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index b454da0d6..a1c80695b 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,27 @@ +

Cleanup of startup directory

+ +

The files in the startup directory have not been maintained in recent years +and have grown crufty (technical term). This release includes the following +updates to these files:

+ +
    +
  • The EpicsHostArch.pl script has been moved into src/tools +from where it gets installed into lib/perl. The build system has been +adjusted to look for it in both places if the EPICS_HOST_ARCH +environment variable has not been set at build-time. Sites that may have used +this to set EPICS_HOST_ARCH as part of their standard environment may +need to adjust their scripts when they upgrade to this release.
  • + +
  • The existing win32.bat file has been cleaned up and a new +windows.bat file added for 64-bit targets. The contents of these files +should be seen as examples, don't uncomment or install parts for software that +you don't explicitly know that you need.
  • + +
+

Fixes for Launchpad bugs

The following launchpad bugs have fixes included:

From eae59183cc0d2675496425c4b3017dddef383800 Mon Sep 17 00:00:00 2001 From: "J. Lewis Muir" Date: Tue, 26 Jun 2018 15:41:27 -0500 Subject: [PATCH 055/147] Rename Site.{cshrc,profile} to unix.{csh,sh} --- documentation/README.1st | 4 ++-- documentation/README.darwin.html | 2 +- documentation/README.html | 4 ++-- documentation/RELEASE_NOTES.html | 3 +++ startup/{Site.cshrc => unix.csh} | 0 startup/{Site.profile => unix.sh} | 0 6 files changed, 8 insertions(+), 5 deletions(-) rename startup/{Site.cshrc => unix.csh} (100%) rename startup/{Site.profile => unix.sh} (100%) diff --git a/documentation/README.1st b/documentation/README.1st index 462ac460a..4ddad2772 100644 --- a/documentation/README.1st +++ b/documentation/README.1st @@ -223,10 +223,10 @@ EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable - Site.profile bourne shell script to set path and env variables - Site.cshrc c shell script to set path and env variables borland.bat WIN32 bat file to set borland path and env variables cygwin.bat WIN32 bat file to set cygwin path and env variables + unix.csh C shell script to set path and env variables + unix.sh Bourne shell script to set path and env variables win32.bat WIN32 bat file to set path and env variables win32-debug.bat WIN32 debug bat file to set debug path and env variables diff --git a/documentation/README.darwin.html b/documentation/README.darwin.html index cbc290178..dd11ce857 100644 --- a/documentation/README.darwin.html +++ b/documentation/README.darwin.html @@ -21,7 +21,7 @@ of my Bash login script (~/.bash_login): # EPICS_BASE="${HOME}/src/EPICS/base" EPICS_EXTENSIONS="${HOME}/src/EPICS/extensions" -. "${EPICS_BASE}"/startup/Site.profile +. "${EPICS_BASE}"/startup/unix.sh
  • diff --git a/documentation/README.html b/documentation/README.html index a8a572372..ad67cdfcb 100644 --- a/documentation/README.html +++ b/documentation/README.html @@ -232,10 +232,10 @@
             EpicsHostArch       C shell script to set EPICS_HOST_ARCH env variable
             EpicsHostArch.pl    Perl script to set EPICS_HOST_ARCH env variable
    -        Site.profile        bourne shell script to set path and env variables
    -        Site.cshrc          c shell script to set path and env variables
             borland.bat         WIN32 bat file to set borland path and env variables
             cygwin.bat          WIN32 bat file to set cygwin path and env variables
    +        unix.csh            C shell script to set path and env variables
    +        unix.sh             Bourne shell script to set path and env variables
             win32.bat           WIN32 bat file to set path and env variables
             win32-debug.bat     WIN32 debug bat file to set debug path and env variables
     
    diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index a1c80695b..85dc54a7b 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -27,6 +27,9 @@ environment variable has not been set at build-time. Sites that may have used this to set EPICS_HOST_ARCH as part of their standard environment may need to adjust their scripts when they upgrade to this release.
  • +
  • The Site.cshrc and Site.profile files have been renamed to +unix.csh and unix.sh, respectively.
  • +
  • The existing win32.bat file has been cleaned up and a new windows.bat file added for 64-bit targets. The contents of these files should be seen as examples, don't uncomment or install parts for software that diff --git a/startup/Site.cshrc b/startup/unix.csh similarity index 100% rename from startup/Site.cshrc rename to startup/unix.csh diff --git a/startup/Site.profile b/startup/unix.sh similarity index 100% rename from startup/Site.profile rename to startup/unix.sh From 7a5ff269846aa8c09ab972294f193299e21c1537 Mon Sep 17 00:00:00 2001 From: "J. Lewis Muir" Date: Tue, 26 Jun 2018 16:20:07 -0500 Subject: [PATCH 056/147] Remove EpicsHostArch --- ci/travis-build.sh | 2 +- documentation/README.1st | 1 - documentation/README.html | 1 - documentation/RELEASE_NOTES.html | 3 ++ startup/EpicsHostArch | 84 -------------------------------- 5 files changed, 4 insertions(+), 87 deletions(-) delete mode 100755 startup/EpicsHostArch diff --git a/ci/travis-build.sh b/ci/travis-build.sh index a3ca3fd16..2ee5d652f 100644 --- a/ci/travis-build.sh +++ b/ci/travis-build.sh @@ -17,7 +17,7 @@ ticker() { CACHEKEY=1 -EPICS_HOST_ARCH=`sh startup/EpicsHostArch` +EPICS_HOST_ARCH=`perl src/tools/EpicsHostArch.pl` [ -e configure/os/CONFIG_SITE.Common.linux-x86 ] || die "Wrong location: $PWD" diff --git a/documentation/README.1st b/documentation/README.1st index 4ddad2772..f5f209dd1 100644 --- a/documentation/README.1st +++ b/documentation/README.1st @@ -221,7 +221,6 @@ base/startup directory - contains scripts to set environment and path - EpicsHostArch C shell script to set EPICS_HOST_ARCH env variable EpicsHostArch.pl Perl script to set EPICS_HOST_ARCH env variable borland.bat WIN32 bat file to set borland path and env variables cygwin.bat WIN32 bat file to set cygwin path and env variables diff --git a/documentation/README.html b/documentation/README.html index ad67cdfcb..c803ab767 100644 --- a/documentation/README.html +++ b/documentation/README.html @@ -230,7 +230,6 @@

    base/startup directory - contains scripts to set environment and path

    -        EpicsHostArch       C shell script to set EPICS_HOST_ARCH env variable
             EpicsHostArch.pl    Perl script to set EPICS_HOST_ARCH env variable
             borland.bat         WIN32 bat file to set borland path and env variables
             cygwin.bat          WIN32 bat file to set cygwin path and env variables
    diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
    index 85dc54a7b..a419bcabc 100644
    --- a/documentation/RELEASE_NOTES.html
    +++ b/documentation/RELEASE_NOTES.html
    @@ -20,6 +20,9 @@ and have grown crufty (technical term). This release includes the following
     updates to these files: