Compare commits

..

316 Commits

Author SHA1 Message Date
Michael Davidsaver
42604fc794 Allow clang with GCC compilerSpecific.h
Some checks failed
Check EditorConfig / editorconfig (push) Failing after 1s
Base / Cross linux-aarch64 (push) Failing after 2s
Base / Cross linux-arm gnueabi (push) Failing after 1s
Base / Cross linux-arm gnueabihf (push) Failing after 2s
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 unsigned char (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
Makes it easier to run clang derivative analysis tools
on builds configured for GCC.
2023-06-13 08:47:13 -07:00
Michael Davidsaver
4ecc0daa79 make mapDBFToDBR[] const 2023-06-13 08:47:13 -07:00
Michael Davidsaver
5a1f3ecc8b doc: note when some record types were introduced 2023-05-18 11:57:41 -07:00
Michael Davidsaver
cb97d662a7 doc 2023-05-01 10:31:01 -07:00
Michael Davidsaver
d4fab0d20e iocsh: dbCompleteRecord() missing NULL check 2023-05-01 10:31:01 -07:00
Michael Davidsaver
0c13e6ba6c iocsh: tab completion handle iocshArgArgv 2023-05-01 10:31:01 -07:00
Michael Davidsaver
8f1243da40 epicsSingleton: eliminate global ctor with >= c++11 2023-05-01 10:25:29 -07:00
Michael Davidsaver
fe9995c0b5 Update recommendation for CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 2023-05-01 09:06:59 -07:00
Freddie Akeroyd
f56412d6a5 WIN32: use FlsAlloc() to cleanup epicsThreadOSD
Adjust macros for compiling for older MSVC/Win SDK versions

Try to cover missing fibres include in 7.0 SDK

Support Windows XP and above.
Also removed explicit define of _WIN32_WINNT in code if it has not
been passed on compile line. This is possibly a matter for
further discussion
2023-05-01 09:03:52 -07:00
Érico Nogueira
07d18c55ba Clean whitespace in makeBaseApp template README 2023-05-01 09:03:52 -07:00
Minijackson
9f97f25669 ci: add cross-compilation tests for aarch64, arm soft and hard float 2023-05-01 09:03:52 -07:00
912a82c0b5 replace deprecated decrementing volatile with atomic decrement 2023-05-01 09:03:52 -07:00
acf2241fd0 Some archs define ECHO in termios.h 2023-05-01 09:03:52 -07:00
Eva Lott
b878295d06 Added the new annotation EPICS_PRINTF_FMT 2023-05-01 09:03:45 -07:00
f41f11c7f6 fix compiler warning on 32 bit systems 2023-04-28 09:35:49 -05:00
Michael Davidsaver
216359974c update release notes 2023-04-18 13:11:59 -05:00
Torsten Bögershausen
17ad04505e Change compiler for FreeBSD 13: Use clang
FreeBSD 13 uses clang, not gcc, any more.
GNU_DIR must be set to /usr/local

Note: This change touches both the x86 and the x86_64 files.
It was tested on 'amd64' system only, which is x86_64
2023-04-18 09:51:33 -05:00
Michael Davidsaver
3500a02034 iocsh: expose dbCreateAlias 2023-04-18 09:51:28 -05:00
Michael Davidsaver
52b18d56a0 dbCreateAlias fixup error handling 2023-04-18 09:51:28 -05:00
Michael Davidsaver
5507646ce7 posix: optimize epicsThreadOnce()
Use atomic ops to short circuit when already initialized
2023-04-18 09:51:24 -05:00
Michael Davidsaver
625c2ef159 epicsThreadPerform: time epicsThreadOnce() 2023-04-18 09:51:24 -05:00
Jure Varlec
bdaca51d96 Update shareLib API docs, directing the reader to makeAPIheader.pl 2023-04-18 09:51:21 -05:00
Jure Varlec
9655b78e11 Update release notes: ts filter 2023-04-18 09:51:07 -05:00
Jure Varlec
e11f88017d ts filter: port to the new db_field_log 2023-04-18 09:51:07 -05:00
Jure Varlec
8a3020033e ts filter: replace cantProceed with a non-fatal error msg 2023-04-18 09:51:07 -05:00
Jure Varlec
bd1af9ac95 ts filter: fix unused variable warnings 2023-04-18 09:51:07 -05:00
Jure Varlec
d5959ca20a ts filter: handle calloc failures 2023-04-18 09:51:07 -05:00
Jure Varlec
e10dcede7d ts filter: clear the dtor field after destruction 2023-04-18 09:51:07 -05:00
Jure Varlec
c042b08ab0 Extend timestamp filter, giving access to the record timestamp 2023-04-18 09:51:07 -05:00
Michael Davidsaver
5eff3803a8 update release notes 2023-03-10 12:02:29 +00:00
Michael Davidsaver
151256533f renamed hidden pdbbase in dbd parser
avoid confusion with non-static pdbbase global
2023-03-10 11:00:58 +00:00
Michael Davidsaver
3b484f58d3 for links, treat "" the same as unset. 2023-03-10 11:00:58 +00:00
Michael Davidsaver
d3f93746a8 1<<31 upsets ubsan 2023-03-10 10:57:35 +00:00
Michael Davidsaver
f99a1cb0f3 dbdToRecordtypeH use offsetof()
quiets UB sanitizer
2023-03-10 10:57:35 +00:00
Michael Davidsaver
531a769007 fix rtems_ne2kpci_driver_attach prototype 2023-03-10 10:57:35 +00:00
Henrique Silva
3e51491628 Fix generalTimeReport interest_level argument type
Setting to iocshArgInt actually makes the function verbosity to be able
to be controlled by the value
2023-03-10 10:56:58 +00:00
0b01fb20db make buffer large enough for any argument value 2023-03-10 10:56:58 +00:00
Minijackson
c7a769e5da editorconfig: add workflow to check if config is upheld 2023-03-10 10:56:58 +00:00
Minijackson
a9fd57a865 editorconfig: add initial version forcing final newlines
See #337
2023-03-10 10:56:58 +00:00
e862f0e95f fix warning "if clause does not guard..." 2023-03-10 10:56:58 +00:00
172597e0e6 avoid accessing dbr_text[type] when type is out of range 2023-03-10 10:56:58 +00:00
bcdeeed206 fix missing newline at end of file 2023-03-10 10:56:58 +00:00
Michael Davidsaver
b6626e4f60 dbEvent: try to detect possible "stall"
event_read() should not return if the last callback
was delivered with eventsRemaining!=0
2023-03-10 10:56:58 +00:00
Michael Davidsaver
e1c1bb8b1b dbEvent: correct eventsRemaining
Only pass eventsRemaining when no queued events have been canceled.
Also possible race bt accessing ev_que with locking.
2023-03-10 10:56:58 +00:00
Torsten Bögershausen
90ae51e8f2 MacOs: Use readline from MacPorts
Commit b38ff09f6e and
commit d9ca8a70f0 introduced the TAB
completion in iocsh.

Commit 1f75813a4d enabled it for MacOs
having readline installed via HomeBrew.

This commit enables it for MacPorts.
2023-03-10 10:56:58 +00:00
Brendan Chandler
832abbd3b1 Return an error if subrecord processing fails due to bad INP links
If a sub record has an invalid INPx link, it was silently failing (and
not running the proc function).  This change plumbs in the error, so
the put fails and the user knows something went wrong.
2023-03-10 10:56:58 +00:00
Michael Davidsaver
52cc68433f COMMANDLINE_LIBRARY fallback to $(wildcard $(GNU_DIR) 2023-03-10 09:52:30 +00:00
Michael Davidsaver
f430389ee7 iocShutdown(): Always stop worker threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
bded79f14d dbScan join threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
2ff44cb386 callback join threads 2023-03-10 09:52:08 +00:00
Michael Davidsaver
a9ade9669a switch dbScan to epicsThreadCreateOpt() 2023-03-10 09:52:08 +00:00
Michael Davidsaver
f902d70006 switch callback to epicsThreadCreateOpt() 2023-03-10 09:52:08 +00:00
Michael Davidsaver
e22d74310b RTEMS: ensure epicsThreadMustJoin() short-circuits 2023-03-10 09:52:08 +00:00
Simon Rose
e5ad12e638 Updated RELEASE_NOTES 2023-03-10 09:51:08 +00:00
Simon Rose
b963a4564e Added commend about PBUF having no effect on 'Average' algorithm 2023-03-10 09:51:08 +00:00
Simon Rose
579c125b01 Updated documentation 2023-03-10 09:51:08 +00:00
Simon Rose
84d9617375 Added one more put/process to go over the buffer length
Note that it is not really a circular buffer in this case, but
a full reset of the buffer to the beginning. This matches the
documentation, but it seems valuable to add an explicit test for
this case.
2023-03-10 09:51:08 +00:00
Simon Rose
d66e90a016 Fixing 'error C2057: expected constant expression' error 2023-03-10 09:51:08 +00:00
Simon Rose
373e5440ac General cleanup 2023-03-10 09:51:08 +00:00
Simon Rose
dec23501e1 Added test for array_average 2023-03-10 09:51:08 +00:00
Simon Rose
11a4bed9aa compress_scalar for average works correctly now 2023-03-10 09:51:08 +00:00
Simon Rose
bf4a4c6b78 Added failing test for partial ai average 2023-03-10 09:51:08 +00:00
Simon Rose
b54d4b9a24 Added test for low value 2023-03-10 09:51:08 +00:00
Simon Rose
84f4771691 Single input data test passes 2023-03-10 09:51:08 +00:00
Simon Rose
1dc34a02e2 Add test path for single input data 2023-03-10 09:51:08 +00:00
Simon Rose
3ab22818da Added failing test for partially filled buffer average 2023-03-10 09:51:08 +00:00
Simon Rose
1ab474638d Initial test for averaging 2023-03-10 09:51:08 +00:00
Michael Davidsaver
eea361bf5e Com: Allow runtime bypass of freeListLib
By environment or iocsh variable.
2023-03-10 09:48:27 +00:00
Michael Davidsaver
d9052f7105 update ci-scripts 2023-03-09 14:26:45 +00:00
Michael Davidsaver
fa00572780 update pvData 2023-03-06 15:54:34 +00:00
Ralph Lange
636f5517b2 Add QT Creator 9.x dir to .gitignore 2023-03-06 09:30:02 +00:00
Andrew Johnson
718da5c9be Convert RecordReference.md to ComponentReference.pod
That .pod file will now be converted to .html using the same style as
the individual local documents that it links to.

The dbdToHtml output files now include a header and footer that link to
the ComponentReference.html file (they started pointing to the original
RecordReference.html but that was broken on most people's builds because
we weren't converting that from the original Markdown version).

This commit also adjusts documentation/Makefile to use the build system
properly, and reorders the Doxygen main page index.
2023-02-04 22:56:19 -06:00
Michael Davidsaver
e5335ce760 GHA: Add -funsigned-char build 2023-02-01 09:25:10 -08:00
3dbc9ea264 iocsh: fix argument splitting
Since commit 60128ee9 "Com: separate iocsh argument splitting",
iocsh is broken on VxWorks (tested with version 6.9.4.12)

Any command prints the error "Unbalanced quote."

> iocsh
epics> echo
Unbalanced quote.
epics> "echo"
Unbalanced quote.
epics> "echo
Unbalanced quote.
epics> echo bla
Unbalanced quote.
epics> echo 1 2 3
Unbalanced quote.
epics> exit
Unbalanced quote.
2023-02-01 09:25:10 -08:00
Michael Davidsaver
80da400f9c dbLock: avoid possibly lost log prior to cantProceed 2023-02-01 09:25:10 -08:00
Michael Davidsaver
5787125bbb doc 2023-02-01 09:25:10 -08:00
Andrew Johnson
bc54524270 Fix bad JSON char detection in dbStatic
Thanks to Dirk Zimoch for pointing this out.
2023-01-24 11:08:13 -06:00
Andrew Johnson
a2d53c05f6 Explain SNC registration in template 2023-01-24 11:06:48 -06:00
Andrew Johnson
3293a29d59 Darwin: Remove '-undefined dynamic_lookup' from SHRLIB_LDFLAGS
It's been deprecated by Apple in latest XCode and generates warning
messages when creating .dylib libraries, but they don't yet have a
solution for use when creating loadable libraries (.bundle files).
2023-01-19 11:05:21 -06:00
Andrew Johnson
550e902bf3 iocLogPrefix: skip "already set" warning if prefix identical 2023-01-19 11:00:14 -06:00
Andrew Johnson
84e5cc0b69 softIoc -v -x prefix should show loading exit_file 2023-01-19 10:56:46 -06:00
Andrew Johnson
4b63882f28 Appveyor config fixes 2023-01-06 15:28:15 -06:00
Andrew Johnson
fb742beae3 Fix epicsThreadOnceTest.c
Replace epicsThreadSleep() with proper thread synchronization.
The main thread was reading runCount without taking lock first.
Taking the lock before accessing doneCount might not be necessary
given the epicsEventMustWait(), but not 100% sure.
2023-01-06 15:24:56 -06:00
Andrew Johnson
7ef0c80630 errSymLib: status 0 => "Ok" 2022-12-31 19:14:57 -06:00
Andrew Johnson
1f75813a4d Have macOS builds use Homebrew's GNU readline if present 2022-12-31 19:12:49 -06:00
Andrew Johnson
34ad8e2347 Edits to Release Notes and postfix.h documentation 2022-12-31 19:10:49 -06:00
Andrew Johnson
413f14e4ae Remove now-unused pdset variable. 2022-12-29 18:10:38 -06:00
Andrew Johnson
c22895d499 Adjust documentation about longout feature 2022-12-29 18:04:48 -06:00
Andrew Johnson
e63184e518 Merge PR #63, longout.OOPT 2022-12-29 16:31:42 -06:00
Andrew Johnson
755a4541c5 Update the RecordReference.md index; add links and filters. 2022-12-28 15:53:48 -06:00
Andrew Johnson
05cd7edf71 Update channel filter documentation, adding $ syntax 2022-12-28 15:52:30 -06:00
Andrew Johnson
5759726a89 Update link documentation 2022-12-28 15:43:35 -06:00
Andrew Johnson
14e7926d22 Add RecRef links to the top & bottom of each reference page 2022-12-28 15:30:25 -06:00
Andrew Johnson
c068fe3525 capr.pl: Fetch link fields as long strings 2022-12-28 12:43:38 -06:00
Andrew Johnson
c2364d9d1c Add license header to new epicsReadlinePvt.h 2022-12-28 12:42:51 -06:00
Michael Davidsaver
6be0372257 doc 2022-12-21 09:50:07 -08:00
Michael Davidsaver
e994ad78db GHA update 2022-12-21 08:15:26 -08:00
Michael Davidsaver
49fddaa13e errlogRemoveListeners() handle self-removal
Handle errlogRemoveListeners() during a callback.
2022-12-20 20:12:04 -08:00
Michael Davidsaver
7448a8bfa9 errlog: worker exit when buffer is empty
Allow the worker to flush any buffered messages.
After pvt.atExit, further logging will be synchronous.
Ensure any flusher gets a final wakeup.
2022-12-20 20:12:04 -08:00
Michael Davidsaver
166267a32f ringPointerTest in thread 2022-12-20 20:12:04 -08:00
Andrew Johnson
b460c2659e Fix for GH issue #219, menu fields with non-choice values
It's rare, but menu fields may hold a value that does not correspond
to one of the menu choices; the default value of the SSCN fields is
the most common example (65535). Change the type conversion routines
to return a numeric string instead of giving an error.

DBF_DEVICE was fixed in dbFastLinkConv.c before the 7.0.7 release.
2022-12-20 20:12:04 -08:00
Michael Skoufis
7ccc3ab82d Modify pointer type in example to match options from epicsTypes.h 2022-12-20 20:12:04 -08:00
Michael Davidsaver
adb0c898a6 doc 2022-12-20 20:12:04 -08:00
Michael Davidsaver
b38ff09f6e Com: iocsh: Tab completion of variable names for "var" 2022-12-20 20:12:04 -08:00
Michael Davidsaver
d9ca8a70f0 Com: iocsh: Tab completion
Add tab completion for "help ...", record names, and "pdbbase"
2022-12-20 20:12:04 -08:00
Michael Davidsaver
60128ee924 Com: separate iocsh argument splitting 2022-12-20 20:12:04 -08:00
Michael Davidsaver
b189991f9d Com: iocsh: add tab completion for command names 2022-12-20 20:12:04 -08:00
Michael Davidsaver
07ffc1ffae Com: introduce epicsReadlinePvt.h
Helping IDEs understand gnuReadline.c and osdReadline.c
2022-12-20 20:11:45 -08:00
Michael Davidsaver
a6afef4850 calc: add FMOD 2022-12-20 20:11:44 -08:00
Michael Davidsaver
9c0c486111 appveyor: bypass auto-detect of readline 2022-12-08 09:12:45 -08:00
Michael Davidsaver
3f5cf61fb6 update pvData 2022-12-05 10:51:47 -08:00
Andrew Johnson
6222902688 Update pva2pva module 2022-12-01 12:43:18 -06:00
Andrew Johnson
7febee04fa More & better Perl script dependencies 2022-11-30 13:35:56 -06:00
Andrew Johnson
4640f0a8ae Fix dbdExpand.pl issue 2022-11-30 13:34:22 -06:00
Andrew Johnson
8969a952e4 configure: Make Perl-generated files dependent on their .pl script 2022-11-24 17:57:05 -06:00
Michael Davidsaver
bc9415bb10 epicsErrlogTest: osiSockAttach() 2022-11-15 10:07:26 -08:00
Andrew Johnson
cbd86ada20 regRecDevDrv.pl: Don't break long symbol names in DBD files
Makes a test symbol name long enough to trigger the problem.

Fixes lp: #1995728
2022-11-04 11:09:06 -05:00
Michael Davidsaver
0f8ea3aa36 doc update dbUnitTest.h 2022-09-25 09:34:13 -07:00
Andrew Johnson
f62f68fd66 Update all submodules for future development 2022-09-07 17:00:45 -05:00
Andrew Johnson
eddafd2827 Release Checklist used for 7.0.7 2022-09-07 16:58:21 -05:00
Andrew Johnson
e3ce9d7f1a Adjustments to the make-tar.sh script 2022-09-07 16:57:09 -05:00
Andrew Johnson
df96e6df0f Set next development versions 2022-09-07 13:54:12 -05:00
Andrew Johnson
6fab3cafc5 Release notes and version number updates
Some checks failed
Base / CentOS-7 (push) Failing after 1s
Base / Fedora-33 (push) Failing after 2s
Base / Fedora-latest (push) Failing after 1s
Base / MacOS clang-12 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 uC5282 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu (push) Has been cancelled
Base / Win2019 mingw (push) Has been cancelled
Base / Ub-20 gcc-9 C++11, static (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW, static (push) Has been cancelled
Base / Win2019 MSC-19, debug (push) Has been cancelled
Base / Win2019 MSC-19 (push) Has been cancelled
Base / Win2019 MSC-19, static (push) Has been cancelled
Base / Ub-20 clang-10 C++11 (push) Has been cancelled
Base / Ub-20 clang-10 (push) Has been cancelled
Base / Ub-20 gcc-9 + MinGW (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.10 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-4.9 (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 beatnik (push) Has been cancelled
Base / Ub-20 gcc-9 + RT-5.1 pc686 (push) Has been cancelled
2022-09-07 13:50:35 -05:00
Andrew Johnson
e4811d5a28 Documentation updates UNRELEASED => 7.0.7 2022-09-07 12:46:21 -05:00
Andrew Johnson
34af1a12bc Submodule updates for the 7.0.7 release 2022-09-07 12:17:32 -05:00
Andrew Johnson
0301e60629 Expanded on Oksana's annotations 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
759a737983 moved code tags to exclude comments, as suggested 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
eeddf54b84 in file initHooks.h changed brief sytax to make comment appear next to the field, used \code {.cpp} as suggested for the example 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
6f6ab3b758 codeathon 2022 Added doxygen formatting to initHooks.h 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
59d16c56a1 codeathon 2022. Added missing comments with \brief, updated other notation for consistency 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
58edb984c9 codeathone 2022, added doxygen syntax to all comments in dbChannel.h 2022-09-05 21:58:34 -05:00
Oksana Ivashkevych
eb3207ee21 Codeathon 2022 Header annotations project dbChannel.h 2022-09-05 21:58:34 -05:00
Andrew Johnson
098ee6c063 Oops: Fix to RULES_MODULES 2022-09-03 10:59:26 -05:00
Andrew Johnson
54c02e2c24 Fix for GitHub issue #293
Ensure local build targets are up to date before running tests.
2022-09-03 10:47:58 -05:00
Andrew Johnson
efc7cbaf7f Build system fixes related to INSTALL_LOCATION
* The build can't descend into external submodules when there is no
configure/RULES_TOP file present in $(INSTALL_LOCATION).
* Recreate modules/RELEASE.<host>.local if configure/CONFIG_SITE or
configure/CONFIG_SITE.local have changed.
* Move the distclean of modules/RELEASE.<host>.local to RULES_TOP
* Several comment and white-space changes
2022-09-03 10:47:58 -05:00
Andrew Johnson
ede35aa152 Add .gitignore files to the makeBase{App,Ext} templates 2022-09-03 10:47:58 -05:00
Torsten Bögershausen
a8e8d22c31 iocinf.cpp: Hostnames may be longer than 32 bytes
Found here at ESS:

(all in one line)
EPICS_CA_ADDR_LIST=averylonghostname.mylabnetwork.technicalnetwork.example.com
EPICS_CA_AUTO_ADDR_LIST=NO
caget somePVnam

leads to something like this:
CA.Client.Exception...............................................
    Warning: "Empty PV search address list"
    Source File: ../udpiiu.cpp line 403
    Current Time: Thu Jun 09 2022 10:10:47.804161447

Problem desription:
addAddrToChannelAccessAddressList() will collect what ever we specify in
EPICS_CA_ADDR_LIST for channel access.
That function will add IP-addresses to the search list.
hostnames are possible, but are ignored if longer than 32 bytes,
because buf is too short.

If a hostname can be resolved into an IP, that is fine,
if not that is "fine as well" (better say: silently ignored):
If, and only if, EPICS_CA_AUTO_ADDR_LIST=NO is given then the one
and only too long hostname will be ignored and lead to an
"Empty PV search address list".

If EPICS_CA_AUTO_ADDR_LIST=YES (or nothing) is specified, the search list
is not empty, and EPICS will search all broadcast addresses.
This will eventually lead into a timout.

Solution:
Increase the buf size in addAddrToChannelAccessAddressList() from 32 to 256

The maximum length for a hostname is 255:
https://www.ietf.org/rfc/rfc1034.txt

If we add one byte for the string terminating '\0', we need 256 bytes.

And yes, this patch neglets the fact that a user can specify HOSTNAME:PORT,
which may need another 6 bytes. To put it the other way around:
In this case the hostname length is limited to 250 bytes,
which is still long enough in practice.
2022-09-02 18:28:34 -07:00
c2df1c6fe5 string waveform init test added 2022-09-02 08:33:32 -07:00
c5a7548526 eliminated unnecessary code 2022-09-02 08:33:32 -07:00
dc70dfd625 escape non-printable chars in dbgf output of CHAR arrays 2022-09-02 08:33:32 -07:00
20e20cbf2b improved JSON parser error messages 2022-09-02 08:33:32 -07:00
2e44ca586f using the same error printing function consistently 2022-09-02 08:33:32 -07:00
c9619d013a printing some context 2022-09-02 08:33:32 -07:00
ec650e8c3f allow empty array input links 2022-09-02 08:33:32 -07:00
Michael Davidsaver
d47fa4caa4 fix aSub with constant input links 2022-09-02 08:09:51 -07:00
Michael Davidsaver
f0369058bb dbReadCOM missing newline in error 2022-09-02 08:08:27 -07:00
Andrew Johnson
df96c0170a Minor changes to makeBaseApp templates 2022-08-30 14:06:30 -05:00
Andrew Johnson
a411a19b2a Updates to makeBaseExt templates
Removed RULES_PYTHON (swig and Python 2.2!)
Removed CONFIG_SITE files for cygwin, solaris & darwin-ppc & ppcx86
Added CONFIG_SITE files for linux-aarch64 and darwin-aarch64
Removed pointers to many ancient packages
2022-08-30 14:05:15 -05:00
Andrew Johnson
c0db7a0beb Fix ECHO, QUIET_FLAG and QUESTION_FLAG 2022-08-26 15:22:30 -05:00
Andrew Johnson
52dfb89741 PRINT.var targets work under make -q 2022-08-26 12:32:04 -05:00
Andrew Johnson
b652e8230a Improve expandVars.pl debug output 2022-08-26 12:16:09 -05:00
Andrew Johnson
0efffc1bcb expandVars.pl now only writes output when it changes 2022-08-26 12:12:14 -05:00
Andrew Johnson
d7030ae8a5 Adjust for Perls without \N in regex. 2022-08-23 15:15:41 -05:00
Andrew Johnson
24f30ede22 Portability: Don't use bash/shell operations 2022-08-23 13:35:40 -05:00
Andrew Johnson
04ee3f2888 hg and svn have been tested 2022-08-23 13:07:06 -05:00
Andrew Johnson
a373327b59 Get revision date from Darcs 2022-08-23 13:06:44 -05:00
Andrew Johnson
1fa98d489f Merge Pierrick's VersionHeaderDate branch into 7.0 2022-08-23 11:54:07 -05:00
Andrew Johnson
5cef60a3e4 Clear unused var warning 2022-08-21 16:51:17 -05:00
Andrew Johnson
20fb6b9ef5 Merge 3.15 changes into 7.0 2022-08-21 16:44:38 -05:00
Andrew Johnson
a249561677 Added darwin-aarch64 support from 7.0 branch 2022-08-21 16:17:29 -05:00
Andrew Johnson
96887926bf Merge Freddie's set_thread_descriptions branch
PR #270
2022-08-21 16:01:51 -05:00
Andrew Johnson
c8647ffab7 Added Release Note 2022-08-21 16:00:30 -05:00
Michael Davidsaver
e28c914966 dbDumpRecordType show field offset/size 2022-08-20 13:53:03 -07:00
Michael Davidsaver
f086be93a9 add OPT_LDFLAGS and pass -g when linking 2022-08-20 13:53:03 -07:00
Michael Davidsaver
6feaaebd75 test epicsStrtok_r 2022-08-20 11:47:41 -07:00
Andrew Johnson
5d92d406a1 Darwin: Resolve soft-links in epicsGetExecName() 2022-08-18 12:17:06 -05:00
Andrew Johnson
ad1a13730a Remove unused var 2022-08-16 15:08:23 -05:00
Andrew Johnson
a24a84c315 Replace errPrintf() in recGbl.c 2022-08-16 15:07:49 -05:00
Andrew Johnson
6e7a715380 Getting .DTYP from rectype with no devSup now returns '' 2022-08-16 13:33:11 -05:00
Andrew Johnson
b88b35d117 Enhancements to the capr.pl script 2022-08-16 11:58:35 -05:00
Andrew Johnson
0a20825c6e NTPTimeSync: Show when NTP sync failed, recovered 2022-08-15 19:12:05 -05:00
Michael Davidsaver
424d678abf linkTest_registerRecordDeviceDriver() fix return type 2022-07-29 07:45:23 -07:00
Andrew Johnson
007279cf29 Release notes updated 2022-07-28 13:25:14 -07:00
Andrew Johnson
752ca97f7e VxWorks: Stop VxWorks clock sync if EPICS_TS_FORCE_NTPTIME
Use ipcom_ipd_kill() to do it properly, announce when doing it.
Suspending the ipsntps task is dangerous, can hang the OS so
don't try to kill it if user already suspended the task.
Also drops checks for the "ipntpd" thread, not used.
2022-07-28 13:11:59 -07:00
Andrew Johnson
bf0b4d2f61 VxWorks: Re-run tz2timezone() whenever the year increases
In the event that it then goes backwards we won't run it again; that
should never happen, but if it did we should prefer stability!
2022-07-28 13:11:59 -07:00
Andrew Johnson
87d5c01853 Set useNTP if VxWorks sync task is suspended
Also report that state instead of "running".
2022-07-28 13:11:59 -07:00
Andrew Johnson
956af730a9 osiClockTime.c: Clarify message wording
Distinguish between IOC's clock sync thread and OS's one.
Show our sync interval even when not synchronized.
Only mention the clock sync thread where there can be one.
2022-07-28 13:11:59 -07:00
Andrew Johnson
32564b1a94 osiClockTime.c: Move some things around
Group the private variables, note which are mutex-protected.
Reset the sync interval to 1 second if sync is restarted.
Initialize the syncFromPriority variable.
2022-07-28 13:11:59 -07:00
Andrew Johnson
5b690d5467 VxWorks: Pass interest level into osdClockReport 2022-07-28 13:11:59 -07:00
Andrew Johnson
9efebb6d3d osiClock: Register ClockTime_Init with iocsh
ClockTime_Init and ClockTime_Shutdown are only on VxWorks & RTEMS.
Adjust help text to match.
ClockTime_Init can be re-run later to start or stop the sync thread.
2022-07-28 13:11:59 -07:00
Andrew Johnson
1df973b234 VxWorks: Provide osdClockReport() for OS clock sync tasks. 2022-07-28 13:11:59 -07:00
Andrew Johnson
c71ebd1221 VxWorks: Set timezone when using OS own time-sync tasks 2022-07-28 13:11:59 -07:00
Andrew Johnson
167807f0c4 Rename OS Clock provider on macOS, uses a different implementation. 2022-07-28 13:11:59 -07:00
Jure Varlec
e6b8ecd55e Add space to the message printed by errMessage() 2022-07-28 13:11:29 -07:00
Michael Davidsaver
9048aa3438 db: move db_field_log dtor out of union 2022-07-28 13:10:59 -07:00
Bruce Hill
5ba8080f6e Fix undef ts on first camonitor update of NORD
Moves db_post_events() calls for NORD to process() function
after it updates the timestamp.
2022-07-28 13:09:27 -07:00
Michael Davidsaver
a0a7a94944 mingw fix -lreadline
Override of OP_SYS_LDLIBS prevented LDLIBS_READLINE
from having an effect.

Recent readline doesn't need curses
2022-07-28 13:07:34 -07:00
Michael Davidsaver
42c7dbcd21 remove Makefile readline.h detection logic 2022-07-28 13:07:34 -07:00
Michael Davidsaver
4b8edd2b6f automatic COMMANDLINE_LIBRARY w/ newer compilers 2022-07-28 13:07:34 -07:00
Andrew Johnson
d82ab819ef Cap5 support for zero-length long strings 2022-07-13 13:24:54 -05:00
Andrew Johnson
5f02bad3fc Fix decimate filter for testing on VxWorks
Also adds checks to all filter tests to abort if they
can't continue because their filter wasn't registered.
2022-07-08 15:55:14 -05:00
Andrew Johnson
83a685867c Merged 'roehrig-7.0' into 7.0 2022-07-04 20:53:47 -05:00
Christian Roehrig
05311e0c94 Added Doxygen annotations to modules/libcom/src/iocsh/iocsh.h 2022-07-04 20:45:51 -05:00
Andrew Johnson
35f4d3f8dd Merged 'brendanchandler:annotations2' into 7.0 2022-07-04 20:34:24 -05:00
Brendan Chandler
9864f79d67 Update doxygen for ipAddrToAsciiAsynchronous 2022-07-04 20:28:43 -05:00
Brendan Chandler
91800787ed Doxygen support for ipAddrToAsciiAsynchronous.h 2022-07-04 20:28:43 -05:00
Andrew Johnson
05b27067cf Merged 'echandler-anl:doxygen_comments2' into 7.0 2022-07-04 20:23:24 -05:00
Elaine Chandler
ccdd2808d9 add doxygen comments for epicsAtomic.h 2022-07-04 20:19:45 -05:00
Andrew Johnson
00183fcd4b Merged 'brendanchandler:annotations' into 7.0 2022-07-04 19:58:30 -05:00
Brendan Chandler
1be06fc0e9 Fix doxygen annotations in epicsGuard and osiSock
Change addresses some review feedback kindly given by @minijackson
2022-07-04 19:38:15 -05:00
Brendan Chandler
7cdc44434c Doxygen annotation proofreading fixes in osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
f3dfb36117 Update doxygen annotations on osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
500e901e3d Change @param to \param in epicsGuard.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
a3b09ef1b8 Add doxygen annotations for osiSock.h 2022-07-04 19:38:15 -05:00
Brendan Chandler
55d4801eb0 Fix a couple doxygen warnings
Warnings complained about undocumented parameters.
2022-07-04 19:37:57 -05:00
Brendan Chandler
af41b95b98 Fix a few formatting and doxygen conversion issues 2022-07-04 19:29:10 -05:00
Brendan Chandler
c6605b5d87 Update doxygen annotations in testMain.h
There were already some comments here, but they were missing a doxygen
\file declaration, so the annotations weren't shown in the doxygen
output.

Also added some formatting for the code example and definition of MAIN macro.
2022-07-04 19:29:10 -05:00
Brendan Chandler
9b9ed04ae2 Add doxygen annotations for epicsGuard.h 2022-07-04 19:29:09 -05:00
Andrew Johnson
50f9b12e7d Merged 'echandler-anl:doxygen_comments' into 7.0 2022-07-04 19:16:28 -05:00
Andrew Johnson
bfd2684e58 Minor fixes to Elaine's annotations 2022-07-04 16:47:44 -05:00
Elaine Chandler
95fcf690ad add doxygen comments for epicsStackTrace 2022-07-04 16:27:48 -05:00
Elaine Chandler
0fa3337404 add doxygen comments for epicsSpin.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
e5b6ef9893 Fix doxygen comments to epicsString.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
5b64eaac73 add doxygen comments for osiProcess.h 2022-07-04 16:27:48 -05:00
Elaine Chandler
30d4a583d0 add doxygen comments for logClient 2022-07-04 16:27:48 -05:00
Elaine Chandler
6249ef08f7 Added doxygen comments to epicsString.h 2022-07-04 16:27:48 -05:00
Andrew Johnson
b5105740e6 Fix warnings from Doxygen 2022-07-04 16:18:46 -05:00
Andrew Johnson
818f33e78f Update submodules 2022-07-04 16:04:56 -05:00
Andrew Johnson
571165df26 Stop Clang-12 warnings from Perl XS code 2022-07-04 15:55:18 -05:00
Michael Davidsaver
4df48c91f4 dbEvent: re-add compaction of duplicate "empty" events 2022-06-29 07:23:36 -07:00
Michael Davidsaver
32652414b3 update release notes 2022-06-20 08:20:40 -07:00
Michael Davidsaver
9c8aaa93cd Set RSRV_SERVER_PORT
Publish actual TCP port used.
2022-06-20 08:11:09 -07:00
Andrew Johnson
abe819b51d Release notes for dbdExpand.pl changes 2022-06-20 08:10:46 -07:00
Andrew Johnson
cf278b4159 Sort other DBD entries for output
This should solve all DBD-related reproduceable build issues.
2022-06-20 08:10:46 -07:00
Andrew Johnson
50594a8cc3 Release notes entry for dbExpand.pl -s 2022-06-20 08:10:46 -07:00
Andrew Johnson
ce420588db Have dbExpand.pl sort records by name, unless -s used 2022-06-20 08:10:46 -07:00
Andrew Johnson
4d3a27fdb0 Keep a separate list of record names 2022-06-20 08:10:46 -07:00
Jure Varlec
6176a81a76 Update docs for compress record's run-time parameters 2022-06-20 08:10:01 -07:00
Minijackson
a722bb9289 treewide: add usage help to various iocsh functions 2022-06-20 08:09:42 -07:00
Michael Davidsaver
19daf6136f ioc template avoid passing "0"
> dbLoadDatabase("../../dbd/_APPNAME_.dbd",0,0)

is being interpreted as

> dbLoadDatabase("../../dbd/_APPNAME_.dbd","0","0")

If "../../dbd/_APPNAME_.dbd" doesn't exist, this will
next attempt to open "0/../../dbd/_APPNAME_.dbd",
which added to my confusion...
2022-06-20 08:09:08 -07:00
Michael Davidsaver
0552f2bb72 aao: add OMSL and DOL 2022-06-20 08:08:50 -07:00
Andrew Johnson
9bb11e6e88 Fix VxWorks time sync initialization bug 2022-06-14 16:07:39 -05:00
Michael Davidsaver
2f8272d3a1 doc for: posix: use pthread_key_create() to cleanup epicsThreadOSD 2022-06-08 09:40:12 -07:00
Michael Davidsaver
7cf2a1daca epicsThreadTest: check that joined threads disappear 2022-06-08 09:40:12 -07:00
Michael Davidsaver
d019e9787a posix: use pthread_key_create() to cleanup epicsThreadOSD
Ensure that cleanup happens for all threads,
including implicitly created.
2022-06-08 09:40:12 -07:00
Freddie Akeroyd
4b884c15b1 SetThreadName: Add WINAPI (correctly) for 32bit builds 2022-05-24 14:40:46 +01:00
Freddie Akeroyd
0ace4e4a30 SetThreadName: Add WINAPI for 32bit builds 2022-05-24 14:21:12 +01:00
Freddie Akeroyd
3cf2d3737f Use SetThreadDescription(), if available, to set thread name 2022-05-24 13:24:42 +01:00
hanlet
5997018fb0 Made changes suggested by Michael:
- removed unused/misused $opc_X
- modified command line repo calls
- fixed ifndef block
2022-05-17 12:14:29 -05:00
hanlet
2afa4ea390 Cosmetic change. 2022-05-13 13:32:35 -07:00
hanlet
f0c86c5cb3 Added repository name
Changed git date from epoch to present commit date
2022-05-13 13:25:47 -07:00
hanlet
8e4ffd46a0 Changed descriptive text to identify new commit date information. 2022-05-13 11:38:32 -07:00
hanlet
f109371268 Added revision release time to ioc startup message. 2022-05-13 11:30:26 -07:00
hanlet
e566c52a78 Simplified to remove "use" cases and settling for string for versions of commit date/time. 2022-05-13 10:46:17 -07:00
hanlet
8d0bfcbc5b Modify genVersionHeader.pl to add commit time (in epoch).
Tested for git.
Not tested: darcs, mercurial, or svn
Skipping: bzr
2022-05-13 09:31:01 -07:00
Michael Davidsaver
3fadf4a26c add missing registerRecordDeviceDriver.pl dependency 2022-05-12 10:47:44 -07:00
Michael Davidsaver
9ebd841738 update doc in epicsStdio.h 2022-05-12 10:47:44 -07:00
Michael Davidsaver
94b0e2621f iocsh: more helpful help
For plain "help", move the hint text to the end.
For "help ..." make the command names bold.
2022-05-12 09:01:36 -07:00
Michael Davidsaver
a44ddd586e errlog: add ANSI_BOLD 2022-05-12 09:01:36 -07:00
Minijackson
6fbf95ab18 make Perl hash iteration reproducible
By default Perl doesn't iterate over hashes in a reproducible manner,
to avoid DDoS. Since we aren't providing untrusted inputs, it is fine to
disable this behaviour.

Among other things, this makes the .dbd and some .h generation reproducible.

More information here:

- https://reproducible-builds.org/docs/stable-outputs/
- https://perldoc.perl.org/perlrun#PERL_HASH_SEED
2022-05-11 11:44:00 -07:00
Michael Davidsaver
5485adacb9 make epicsNAN and epicsINF constants really constant 2022-05-11 11:44:00 -07:00
Florian Feldbauer
6ecc384116 fix failing STATIC_BUILD on linux-arm
On linux-arm STATIC_BUILD used the `-static` flag
which leads for some reason to the executables being
linked against `/lib/ld.so.1` which does not exists.

Setting `STATIC_LDFLAGS_YES= -Wl,-Bstatic` in CONFIG.linux-arm.linux-arm
fixed this issue for me.
2022-05-11 11:44:00 -07:00
Matt-E7R5
66537d01bd Patch for RTEMS-mvme2700 2022-05-11 11:44:00 -07:00
Ralph Lange
b6f69241e1 Merge 'evan@gh/add-simm-to-ao-records' into 7.0
(closes #144)
2022-05-11 10:56:37 -07:00
Ralph Lange
4fc549234c Merge branch '7.0' into add-simm-to-ao-records 2022-05-11 10:47:12 -07:00
Ralph Lange
0bcffb56bb Add mention to RELEASE_NOTES 2022-05-11 10:44:53 -07:00
Ralph Lange
60001c0571 Add SIMM=RAW for mbboDirect record 2022-05-10 16:33:28 -07:00
Ralph Lange
37b95bc242 Add SIMM=RAW for mbbo record 2022-05-10 16:33:28 -07:00
Ralph Lange
4e9bb9fe50 Add SIMM=RAW to bo record 2022-05-10 16:33:27 -07:00
Ralph Lange
371cdde6df Trivial fixes to simmRAW for ao 2022-05-10 16:33:27 -07:00
Andrew Johnson
cbae8d37b3 Improve wording of seqRecord doc 2022-04-26 21:07:27 -05:00
wtup
9eb88f27d9 Fixed direction of SHIFT to match implementation 2022-04-26 20:56:43 -05:00
Andrew Johnson
e329fa3296 CA Client: Protect against epicsTime::strftime() throwing
libCa shouldn't cause an application to abort with an uncaught
exception on a machine that has timezone problems just because
we can't convert the current time into a string.
2022-04-24 12:50:40 -05:00
Michael Davidsaver
492672c718 Revert "ci: GHA follow 'make' with 'make -q'"
Stupid make...

This reverts commit b4d7ebd648.
This reverts commit 0f0f9f49d6.
2022-04-23 10:19:00 -07:00
Michael Davidsaver
b4d7ebd648 cue.py workaround limitation
The first argument after "build" can't be an option.
cf. python argparse limitations of add_parser() + REMAINDER
2022-04-23 08:49:35 -07:00
Michael Davidsaver
0f0f9f49d6 ci: GHA follow 'make' with 'make -q'
Detect situations where 'make' was somehow incomplete,
or where an incorrect dependency leaves some step
perpetually out-of-date and repeated every time.
2022-04-19 10:22:54 -07:00
Andrew Johnson
6d3821adb8 Soft-links to capr.pl and makeBaseApp.pl scripts now work
The other Perl scripts that use FindBin for their lib path could
have the same changes applied, but these two scripts are the ones
normally run by hand so might get soft-linked by an installer.
Without this change these scripts don't actually work if run from
a soft-link instead of directly.
2022-04-18 20:46:48 -05:00
Michael Davidsaver
92e97af610 softMain: handle rRDD error 2022-04-16 13:23:58 -07:00
Michael Davidsaver
b0e2e8426f Quiet warning 2022-04-16 13:23:58 -07:00
Andrew Johnson
3e371da8ec RULES_EXPAND: Keep intermediate files
This prevents GNUmake from recreating expanded files
such as databaseVersion.h at every build.
2022-03-28 00:07:21 -05:00
Michael Davidsaver
91941af992 quiet warnings 2022-03-04 10:00:12 -08:00
Michael Davidsaver
d2644baf38 minor 2022-03-03 13:16:57 -08:00
Michael Davidsaver
62092d4399 test dbReadDatabaseFP() 2022-03-03 13:16:53 -08:00
Michael Davidsaver
6c5d56688d help out IDEs 2022-03-03 13:16:50 -08:00
Michael Davidsaver
a6779df21c dbReadDatabaseFP() always fclose() 2022-03-03 13:16:45 -08:00
Andrew Johnson
d8c5379453 Configure builds for lgtm.com 2022-02-15 13:26:43 -06:00
Andrew Johnson
7a9801a4cb Add vxWorks-e500v2 target (MVME2500, APS only) 2022-02-15 13:08:51 -06:00
Andrew Johnson
f33add020e Update Release notes 2022-02-15 11:15:04 -06:00
Andrew Johnson
3bebe6e873 Revert "configure: Don't hide any perl scripts being run"
This reverts commit 3e8f3a1ee9
which was wrong - recipes that start with '-' are still echoed,
they just don't fail the build if they don't succeed.

This fixes setting CHECK_RELEASE = WARN in configure/Makefile
2022-02-15 10:49:37 -06:00
Andrew Johnson
2fbaa7f926 Improve POD documentation of the TSE and TSEL fields 2022-02-08 15:29:05 -06:00
Andrew Johnson
e55e4d7646 Make DISP field DCT=Yes 2022-02-08 15:29:05 -06:00
Andrew Johnson
5efc0cbfce Echo message when running makeBpt 2022-02-08 15:29:05 -06:00
Andrew Johnson
3a182a9eea "Quote" exe program paths for Windows
Clean up old EPICS_DATABASE var's (pre-7.0?)
2022-02-08 15:29:05 -06:00
Michael Davidsaver
0e56e202fc ci: drop CentOS-8
The centos:8 docker image has disappeared.
2022-02-01 12:53:55 -08:00
Michael Davidsaver
d9fd73a850 yajl: doc 2022-01-28 11:23:16 -08:00
Andrew Johnson
d508962211 Breaktable.pm: Add missing declaration 2022-01-24 15:30:23 -06:00
Andrew Johnson
7cb80d5a17 Merge Dirk's fix_epicsInt8 branch into 7.0 2022-01-24 13:32:16 -06:00
Andrew Johnson
051e3f3bc3 Merge Michael's fork-warn branch into 7.0 2022-01-24 13:02:22 -06:00
Andrew Johnson
db216e63a7 Merge Dirk's hex_in_hw_links branch into 7.0 2022-01-24 12:57:53 -06:00
Andrew Johnson
7a3c9eaaa0 Merge Michael's linux-mcast-all branch into 7.0 2022-01-24 12:51:09 -06:00
Andrew Johnson
4bece4ad92 Merge Heinz & Andrew's rtems-osd-event branch into 7.0 2022-01-24 12:44:17 -06:00
Andrew Johnson
36f11fba95 Release Notes update for epicsEvent 2022-01-24 12:43:36 -06:00
Andrew Johnson
7017e54930 Allow more char's in breaktable names 2022-01-24 12:25:57 -06:00
Andrew Johnson
43b623d80e Markdown issue in RELEASE_NOTES 2022-01-13 17:14:00 -06:00
Andrew Johnson
132f9105d0 Fix filenames in CONFIG_SITE file comments 2022-01-13 17:13:25 -06:00
Andrew Johnson
1655d68ec4 Fix for NaN/overflow timeout in RTEMS-score osdEvent 2022-01-05 12:04:02 -06:00
Andrew Johnson
e4a81bb361 Document zero and NaN timeout values
Rename parameter timeOut => timeout everywhere
2022-01-04 17:16:59 -06:00
Andrew Johnson
d1094ee787 Fix timeout values in epicsEventWaitWithTimeout()
isnan(timeOut) => wait forever
0 < timeOut < 1/rate => 1 tick
rtems_interval is a typedef for uint32_t
2022-01-04 13:07:30 -06:00
Andrew Johnson
34baa485bc Fix timeout values in epicsEventWaitWithTimeout()
isnan(timeOut) => wait forever
0 < timeOut < 1/rate => 1 tick
2022-01-04 13:05:21 -06:00
c5012d9f73 Make sure epicsInt8 is signed on all architectures 2021-12-17 09:42:04 +01:00
Ralph Lange
7c168f20f4 Fix gdd string to double conversion
This is an alternative fix for the issue described in
https://github.com/epics-modules/pcas/issues/4 and
https://github.com/epics-extensions/ca-gateway/issues/37
that keeps the call to epicsScanDouble() before trying
sscanf() first with "%lf" (ignoring extra characters)
then with "%x" (to catch hex numbers).
(closes #216)
2021-12-08 17:07:11 +01:00
Michael Davidsaver
de7ad13b3c Com: posix warn of use of epicsThread from child after fork() 2021-11-15 10:09:52 -08:00
Michael Davidsaver
5e2a52401f Com: avoid implicit use of epicsStdio in posix epicsThread.c 2021-11-13 11:47:15 -08:00
6173baed1e mention hex numbers for HW links in release notes 2021-11-10 10:49:23 +01:00
71efed8c1b extend link test to hex numbers 2021-11-10 10:15:56 +01:00
9a09436ac8 allow hex (and octal) in hardware links
Conflicts:
	modules/database/src/ioc/dbStatic/dbStaticLib.c
2021-11-10 10:15:39 +01:00
Andrew Johnson
6063de9a8b Added Heinz new osdEvent.c to RTEMS-posix 2021-10-12 12:37:57 -05:00
Michael Davidsaver
51191e6155 Com: clear IP_MULTICAST_ALL on Linux
The default, non-compliant, behavior will pass all multicast packets
to any socket bound to 0.0.0.0 or the mcast address, regardless
of which groups, on which interfaces, that socket has joined.
2021-08-05 08:51:02 -07:00
Evan Daykin
2f0a7c7342 Merge branch 'epics-base:7.0' into add-simm-to-ao-records 2021-06-09 10:19:01 -04:00
Evan Daykin
edb9208b01 correct number of simm tests 2021-03-12 17:06:35 -05:00
Evan Daykin
4f0cc20e2b Feature: add SIMM=RAW to ao records 2021-03-12 16:31:10 -05:00
Joao Paulo Martins
6c573b496a longout rec: fix behaviour when record is processed for the first time and OOPT is On Change 2021-03-10 18:50:42 +01:00
Joao Paulo Martins
1d85bc7424 longout record: detect OUT link change using special function AFTER put, better documentation 2021-03-10 11:07:30 +01:00
Joao Paulo Martins
f4d94b9725 Longout OOPT field refactoring and updated documentation; Release notes additions 2021-03-09 16:31:54 +01:00
Joao Paulo Martins
4e7a18bfb4 Adding test routines for longout record with OOPT field 2021-03-09 16:31:54 +01:00
Joao Paulo Martins
c1ae5064b8 Added OOPT to longout record 2021-03-09 16:31:54 +01:00
306 changed files with 7813 additions and 2718 deletions

View File

@@ -25,14 +25,19 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skipping commits affecting only specific files
# Skip commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
# Removed - 'documentation/*'
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
# the last commit pushed to a PR only updates the Release Notes the whole
# PR build gets skipped. GitHub Actions looks at the complete list
# of files changed since its last build, which is much more useful.
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.gitattributes'
- '.lgtm.yml'
- '**/*.html'
- '**/*.md'
@@ -67,6 +72,8 @@ environment:
- CMP: vs2010
- CMP: gcc
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# TODO: static linking w/ readline isn't working. Bypass auto-detect
COMMANDLINE_LIBRARY: EPICS
# Platform: processor architecture
platform:

View File

@@ -32,13 +32,18 @@ init:
# Set clone depth (do not fetch complete history)
clone_depth: 5
# Skipping commits affecting only specific files
# Skip commits affecting only specific files
skip_commits:
files:
- 'documentation/*'
# Removed - 'documentation/*'
# Unfortunately Appveyor only looks at the HEAD (latest) commit, so if
# the last commit pushed to a PR only updates the Release Notes the whole
# PR build gets skipped. GitHub Actions looks at the complete list
# of files changed since its last build, which is much more useful.
- 'startup/*'
- '.github/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
@@ -73,6 +78,9 @@ environment:
- CMP: vs2012
- CMP: vs2010
- CMP: gcc
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
# TODO: static linking w/ readline isn't working. Bypass auto-detect
COMMANDLINE_LIBRARY: EPICS
# Platform: processor architecture
platform:

2
.ci

Submodule .ci updated: 75bae77c1d...1e0e326f74

8
.editorconfig Normal file
View File

@@ -0,0 +1,8 @@
# Documentation for this file: https://EditorConfig.org
root = true
# Unix-style newlines ending every file,
# as some compilers complain about files not ending in newline
[*]
insert_final_newline = true

View File

@@ -0,0 +1,13 @@
name: Check EditorConfig
on:
push:
pull_request:
jobs:
editorconfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: EditorConfig-Action
uses: greut/eclint-action@v0

View File

@@ -15,6 +15,7 @@ on:
- 'startup/*'
- '.appveyor/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
@@ -24,6 +25,7 @@ on:
- 'startup/*'
- '.appveyor/*'
- '.tools/*'
- '.lgtm.yml'
- '.gitattributes'
- '**/*.html'
- '**/*.md'
@@ -41,9 +43,7 @@ jobs:
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
RTEMS: ${{ matrix.rtems }}
RTEMS_TARGET: ${{ matrix.rtems_target }}
CI_CROSS_TARGETS: ${{ matrix.cross }}
EXTRA: ${{ matrix.extra }}
TEST: ${{ matrix.test }}
strategy:
@@ -54,13 +54,13 @@ jobs:
- os: ubuntu-20.04
cmp: gcc
configuration: default
wine: "64"
cross: "windows-x64-mingw"
name: "Ub-20 gcc-9 + MinGW"
- os: ubuntu-20.04
cmp: gcc
configuration: static
wine: "64"
cross: "windows-x64-mingw"
name: "Ub-20 gcc-9 + MinGW, static"
- os: ubuntu-20.04
@@ -69,6 +69,12 @@ jobs:
extra: "CMD_CXXFLAGS=-std=c++11"
name: "Ub-20 gcc-9 C++11, static"
- os: ubuntu-20.04
cmp: gcc
configuration: static
extra: "CMD_CFLAGS=-funsigned-char CMD_CXXFLAGS=-funsigned-char"
name: "Ub-20 gcc-9 unsigned char"
- os: ubuntu-20.04
cmp: clang
configuration: default
@@ -83,67 +89,42 @@ jobs:
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-pc686-qemu
cross: "RTEMS-pc686-qemu@5"
name: "Ub-20 gcc-9 + RT-5.1 pc686"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-beatnik
cross: "RTEMS-beatnik@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 beatnik"
# Only build one RTEMS target per CPU family
# unless it's running the tests
#
# - os: ubuntu-20.04
# cmp: gcc
# configuration: default
# rtems: "5"
# rtems_target: RTEMS-mvme3100
# test: NO
# name: "Ub-20 gcc-9 + RT-5.1 mvme3100"
#
# - os: ubuntu-20.04
# cmp: gcc
# configuration: default
# rtems: "5"
# rtems_target: RTEMS-qoriq_e500
# test: NO
# name: "Ub-20 gcc-9 + RT-5.1 qoriq_e500"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-xilinx_zynq_a9_qemu
cross: "RTEMS-xilinx_zynq_a9_qemu@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 xilinx_zynq_a9_qemu"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "5"
rtems_target: RTEMS-uC5282
cross: "RTEMS-uC5282@5"
test: NO
name: "Ub-20 gcc-9 + RT-5.1 uC5282"
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "4.10"
name: "Ub-20 gcc-9 + RT-4.10"
rtems_target: RTEMS-pc386-qemu
cross: "RTEMS-pc386-qemu@4.10"
test: NO
- os: ubuntu-20.04
cmp: gcc
configuration: default
rtems: "4.9"
name: "Ub-20 gcc-9 + RT-4.9"
rtems_target: RTEMS-pc386-qemu
cross: "RTEMS-pc386-qemu@4.9"
- os: macos-latest
cmp: clang
@@ -152,13 +133,15 @@ jobs:
- os: windows-2019
cmp: vs2019
configuration: default
configuration: debug
name: "Win2019 MSC-19"
extra: "CMD_CXXFLAGS=-analysis"
- os: windows-2019
cmp: vs2019
configuration: static
configuration: static-debug
name: "Win2019 MSC-19, static"
extra: "CMD_CXXFLAGS=-analysis"
- os: windows-2019
cmp: vs2019
@@ -170,8 +153,28 @@ jobs:
configuration: default
name: "Win2019 mingw"
# Cross builds
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-aarch64"
cross: linux-aarch64
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-arm gnueabi"
cross: linux-arm@arm-linux-gnueabi
- os: ubuntu-latest
cmp: gcc
configuration: default
name: "Cross linux-arm gnueabihf"
cross: linux-arm@arm-linux-gnueabihf
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Automatic core dumper analysis
@@ -189,7 +192,7 @@ jobs:
run: python .ci/cue.py -T 60M test
- name: Upload tapfiles Artifact
if: ${{ always() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'
@@ -219,11 +222,6 @@ jobs:
cmp: gcc
configuration: default
- name: "CentOS-8"
image: centos:8
cmp: gcc
configuration: default
- name: "Fedora-33"
image: fedora:33
cmp: gcc
@@ -261,7 +259,7 @@ jobs:
# people would rather just break all existing scripts...
[ -e /usr/bin/python ] || ln -sf python3 /usr/bin/python
python --version
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Automatic core dumper analysis
@@ -274,7 +272,7 @@ jobs:
run: python .ci/cue.py -T 20M test
- name: Upload tapfiles Artifact
if: ${{ always() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: tapfiles ${{ matrix.name }}
path: '**/O.*/*.tap'

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@
/modules/Makefile.local
O.*/
/QtC-*
/.qtc_*
/.vscode/
*.orig
*.log

50
.lgtm.yml Normal file
View File

@@ -0,0 +1,50 @@
# Configuration for lgtm.com
#
path_classifiers:
test:
- exclude: /
- test
- "modules/*/test*"
library:
- modules/libcom/src/yacc
- modules/libcom/src/flex
template:
- src/template
- modules/ca/src/template
- modules/database/src/template
extraction:
cpp:
prepare:
packages:
- "libreadline-dev"
index:
build_command:
- "g++ --version"
- "make --version"
- "perl --version"
- "make -sj2 || echo '*** Build failed, ignored for lgtm ***'"
python:
index:
include:
- src/tools
# Interpreted languages to be excluded
javascript:
index:
exclude:
- "*"
# Compiled languages to be excluded
java:
index:
build_command: "echo No Java code in this project"
csharp:
index:
build_command: "echo No C# code in this project"
go:
index:
build_command: "echo No Go code in this project"

View File

@@ -140,10 +140,12 @@ sed \
-e '/\/\.ci-local\//d' \
-e '/\/\.tools\//d' \
-e '/\/jenkins\//d' \
-e '/\/\.git/d' \
-e '/\/\.github\//d' \
-e '/\/\.gitmodules$/d' \
-e '/\/\.hgtags$/d' \
-e '/\/\.cproject$/d' \
-e '/\/\.project$/d' \
-e '/\/\.lgtm\.yml$/d' \
-e '/\/\.travis\.yml$/d' \
-e '/\/\.appveyor\.yml$/d' \
-e '/\/\.readthedocs\.yml$/d' \

View File

@@ -34,6 +34,11 @@ ifeq ($(origin EPICS_HOST_ARCH), undefined)
EHA :=
endif
# Make Perl hash iteration reproducible.
# See: https://reproducible-builds.org/docs/stable-outputs/
#
export PERL_HASH_SEED = 0
-include $(CONFIG)/RELEASE
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH)
-include $(CONFIG)/RELEASE.$(EPICS_HOST_ARCH).Common

View File

@@ -47,6 +47,7 @@ OPT_CXXFLAGS_NO = -g
CODE_LDFLAGS = $(PROF_CXXFLAGS_$(PROFILE)) $(GPROF_CXXFLAGS_$(GPROF))
CODE_LDFLAGS += $(ASAN_LDFLAGS_$(ENABLE_ASAN))
OPT_LDFLAGS_NO = -g
PIPE_CFLAGS_YES_YES = -pipe
PIPE_CFLAGS = $(PIPE_CFLAGS_$(GCC_PIPE)_$(GNU))

View File

@@ -38,10 +38,16 @@ TOOLS = $(abspath $(EPICS_BASE_HOST_BIN))
FIND_TOOL = $(firstword $(wildcard $(TOOLS)/$(1) \
$(TOP)/src/tools/$(1)) $(EPICS_BASE)/src/tools/$(1))
#---------------------------------------------------------------
# Find Perl modules for dependencies
FIND_PM = $(wildcard $(EPICS_BASE)/lib/perl/$(1))
#---------------------------------------------------------------
# EPICS Base build tools and tool flags
PODTOHTML = $(PERL) $(TOOLS)/podToHtml.pl
PODTOHTML_pl = $(TOOLS)/podToHtml.pl
PODTOHTML_dep = $(PODTOHTML_pl) $(call FIND_PM,EPICS/PodHtml.pm)
PODTOHTML = $(PERL) $(PODTOHTML_pl)
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG)

View File

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

View File

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

View File

@@ -82,14 +82,20 @@ FINAL_LOCATION = $(INSTALL_ABSOLUTE)
IOCS_APPL_TOP = $(INSTALL_ABSOLUTE)
#-------------------------------------------------------
# Silencing the build - suppress messages during 'make -s'
NOP = :
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
QUIET_FLAG := $(if $(filter -s,$(MFLAGS)),-q,)
# How to portably check the flags to make
define checkflags
make-$1 = $(findstring $1,$(filter-out --%,$(MAKEFLAGS)))
endef
# This is extensible to most single letter flags:
$(foreach flag,s q, $(eval $(call checkflags,$(flag))))
# Silent builds - suppress messages during 'make -s'
NOP = :
ECHO = @$(if $(make-s),$(NOP),echo)
QUIET_FLAG := $(if $(make-s),-q,)
#-------------------------------------------------------
# Convert 'make -q' flag into '-i' for genVersionHeader.pl
QUESTION_FLAG := $(if $(filter -q,$(MFLAGS)),-i,)
QUESTION_FLAG := $(if $(make-q),-i,)
#-------------------------------------------------------
ifdef T_A
@@ -267,6 +273,7 @@ WARN_CXXFLAGS = $(WARN_CXXFLAGS_$($(BUILD_CLASS)_WARN))
OPT_CPPFLAGS = $(OPT_CPPFLAGS_$($(BUILD_CLASS)_OPT))
OPT_CFLAGS = $(OPT_CFLAGS_$($(BUILD_CLASS)_OPT))
OPT_CXXFLAGS = $(OPT_CXXFLAGS_$($(BUILD_CLASS)_OPT))
OPT_LDFLAGS = $(OPT_LDFLAGS_$($(BUILD_CLASS)_OPT))
# Static build flags
STATIC_CFLAGS = $(STATIC_CFLAGS_$(STATIC_BUILD))
@@ -288,7 +295,6 @@ TARGET_LIB_LDFLAGS = $(if $(findstring $*, $(LOADABLE_LIBRARY)), \
#--------------------------------------------------
# Command-line input support default
COMMANDLINE_LIBRARY = EPICS
OP_SYS_LDLIBS += $(LDLIBS_$(COMMANDLINE_LIBRARY))
OP_SYS_LDFLAGS += $(LDFLAGS_$(COMMANDLINE_LIBRARY))
RUNTIME_LDFLAGS += $(RUNTIME_LDFLAGS_$(COMMANDLINE_LIBRARY))

View File

@@ -5,22 +5,28 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set EPICS_DATABASE if necessary
ifndef EPICS_DATABASE
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
# Installed perl scripts and dependent modules that have
# a significant effect on the script's output
DBDEXPAND_pl = $(EPICS_BASE_HOST_BIN)/dbdExpand.pl
DBDTORECTYPEH_pl = $(EPICS_BASE_HOST_BIN)/dbdToRecordtypeH.pl
DBDTORECTYPEH_dep = $(DBDTORECTYPEH_pl) $(call FIND_PM,DBD/Rec*.pm)
DBDTOMENUH_pl = $(EPICS_BASE_HOST_BIN)/dbdToMenuH.pl
DBDTOMENUH_dep = $(DBDTOMENUH_pl) $(call FIND_PM,DBD/Menu.pm)
DBDTOHTML_pl = $(EPICS_BASE_HOST_BIN)/dbdToHtml.pl
DBDTOHTML_dep = $(DBDTOHTML_pl) $(call FIND_PM,EPICS/Pod*Html.pm)
REGRECDEVDRV_pl = $(EPICS_BASE_HOST_BIN)/registerRecordDeviceDriver.pl
REGRECDEVDRV_dep = $(REGRECDEVDRV_pl)
# Paths to tools built here
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
endif
# Commands for running scripts in recipes
DBEXPAND = $(PERL) $(DBDEXPAND_pl)
DBTORECORDTYPEH = $(PERL) $(DBDTORECTYPEH_pl)
DBTOMENUH = $(PERL) $(DBDTOMENUH_pl)
DBDTOHTML = $(PERL) $(DBDTOHTML_pl)
REGISTERRECORDDEVICEDRIVER = $(PERL) $(REGRECDEVDRV_pl)
# Set location of locally-built tools
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
# Installed binary executables, quoted for running on Windows
MAKEBPT = "$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)"
MSI3_15 = "$(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)"
# Libraries needed to link a basic IOC
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com

View File

@@ -1,7 +1,7 @@
# Version number for the database APIs and shared library
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 21
EPICS_DATABASE_MINOR_VERSION = 22
EPICS_DATABASE_MAINTENANCE_VERSION = 1
# Development flag, set to zero for release versions

View File

@@ -5,9 +5,10 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set location of locally generated tools
YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE)
LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \
# Our locally-built tools
# Windows can need these paths to be quoted
YACC = "$(EPICS_BASE_HOST_BIN)/antelope$(HOSTEXE)"
LEX = "$(EPICS_BASE_HOST_BIN)/e_flex$(HOSTEXE)" \
-S$(EPICS_BASE)/include/flex.skel.static
# Default stack size for osiThread

View File

@@ -1,7 +1,7 @@
# Version number for the libcom APIs and shared library
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 21
EPICS_LIBCOM_MINOR_VERSION = 22
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
# Development flag, set to zero for release versions

View File

@@ -17,7 +17,7 @@ TEMPL_SUFFIX ?= .template
# vpath
vpath %.pm $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.pod $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.pod $(USR_VPATH) $(SRC_DIRS) .. $(dir $(DBD))
vpath %.dbd $(USR_VPATH) $(SRC_DIRS) $(dir $(DBD))
vpath %.db $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
vpath %.vdb $(USR_VPATH) $(SRC_DIRS) $(dir $(DB))
@@ -217,32 +217,32 @@ realclean: clean
#---------------------------------------------------------------
# Dependency files
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd
%Record.h$(DEP): $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%Record.h$(DEP): %Record.dbd
%Record.h$(DEP): %Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%Record.h$(DEP): ../%Record.dbd
%Record.h$(DEP): ../%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd
menu%.h$(DEP): $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): menu%.dbd
menu%.h$(DEP): menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
menu%.h$(DEP): ../menu%.dbd
menu%.h$(DEP): ../menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $@
@$(DBTOMENUH) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
@@ -261,7 +261,7 @@ menu%.h$(DEP): ../menu%.dbd
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $< > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
%.dbd$(DEP):
%.dbd$(DEP): $($*_DBD)
@$(RM) $@
@$(DBEXPAND) -D $(DBDFLAGS) -o $(COMMONDEP_TARGET) $($*_DBD) > $@
@echo "$(COMMONDEP_TARGET): ../Makefile" >> $@
@@ -330,32 +330,32 @@ $(INSTALL_DB)/%$(TEMPL_SUFFIX): ../%$(TEMPL_SUFFIX)
#---------------------------------------------------------------
# INC files
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd
$(COMMON_DIR)/%Record.h: $(COMMON_DIR)/%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%Record.h: %Record.dbd
$(COMMON_DIR)/%Record.h: %Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%Record.h: ../%Record.dbd
$(COMMON_DIR)/%Record.h: ../%Record.dbd $(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd
$(COMMON_DIR)/menu%.h: $(COMMON_DIR)/menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: menu%.dbd
$(COMMON_DIR)/menu%.h: menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menu%.h: ../menu%.dbd
$(COMMON_DIR)/menu%.h: ../menu%.dbd $(DBDTOMENUH_dep)
@$(RM) $(notdir $@)
$(DBTOMENUH) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
@@ -366,6 +366,7 @@ $(COMMON_DIR)/menu%.h: ../menu%.dbd
# DBD files
$(COMMON_DIR)/bpt%.dbd: bpt%.data
$(ECHO) "Converting data from $<"
@$(RM) $(notdir $@)
$(MAKEBPT) $< $(notdir $@)
@$(MV) $(notdir $@) $@
@@ -399,7 +400,7 @@ $(COMMON_DBDCATS):$(COMMON_DIR)/%.dbd:
$(DBDCAT_COMMAND)
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.dbd:
$(COMMON_DIR)/%.dbd: $($*_DBD)
$(ECHO) "Creating dbd file $(notdir $@)"
@$(RM) $(notdir $@)
$(DBEXPAND) $(DBDFLAGS) -o $(notdir $@) $($*_DBD)
@@ -429,28 +430,28 @@ $(foreach file, $(DBD_INSTALLS), $(eval $(call DBD_INSTALLS_template, $(file))))
#---------------------------------------------------------------
# HTML files
$(COMMON_DIR)/%.html: %.dbd.pod
$(COMMON_DIR)/%.html: %.dbd.pod $(DBDTOHTML_pl)
@$(RM) $(notdir $@)
$(DBDTOHTML) $(DBDFLAGS) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: %.pod
$(COMMON_DIR)/%.html: %.pod $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -s -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: %.pm
$(COMMON_DIR)/%.html: %.pm $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: ../%.pm
$(COMMON_DIR)/%.html: ../%.pm $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -o $(notdir $@) $<
@$(MKDIR) $(dir $@)
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.html: ../%.pl
$(COMMON_DIR)/%.html: ../%.pl $(PODTOHTML_dep)
@$(RM) $(notdir $@)
$(PODTOHTML) -s -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
@@ -526,16 +527,19 @@ $(foreach file, $(DB_INSTALLS), $(eval $(call DB_INSTALLS_template, $(file))))
#---------------------------------------------------------------
# register record,device,driver support
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd
%_registerRecordDeviceDriver.cpp: $(COMMON_DIR)/%.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
%_registerRecordDeviceDriver.cpp: %.dbd
%_registerRecordDeviceDriver.cpp: %.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
%_registerRecordDeviceDriver.cpp: ../%.dbd
%_registerRecordDeviceDriver.cpp: ../%.dbd $(REGRECDEVDRV_dep)
@$(RM) $@
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ $< $(basename $@) $(IOCS_APPL_TOP)
$(REGISTERRECORDDEVICEDRIVER) $(REGRDDFLAGS) -o $@ \
$< $(basename $@) $(IOCS_APPL_TOP)
.PRECIOUS: %_registerRecordDeviceDriver.cpp

View File

@@ -207,7 +207,7 @@ endif
checkRelease:
+$(CONVERTRELEASE) checkRelease
warnRelease:
$(CONVERTRELEASE) checkRelease
-$(CONVERTRELEASE) checkRelease
noCheckRelease:
ifeq ($(EPICS_HOST_ARCH),$(T_A))
$(info Warning: RELEASE file consistency checks have been disabled)
@@ -373,11 +373,11 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: run-tap-tests
run-tap-tests: $(TESTSCRIPTS.t)
run-tap-tests: | build
ifneq ($(TESTSCRIPTS.t),)
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PROVE) $^"
@$(PROVE) $^ || $(PROVE_FAILURE)
$(ECHO) "$(PROVE) $(TESTSCRIPTS.t)"
@$(PROVE) $(TESTSCRIPTS.t) || $(PROVE_FAILURE)
endif
endif
@@ -390,8 +390,8 @@ test-results: tap-results
tap-results: $(TAPFILES)
ifneq ($(strip $(TAPFILES)),)
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PROVE.tap) $^"
@$(PROVE.tap) $^ || $(PROVE_FAILURE)
$(ECHO) "$(PROVE.tap) $(TAPFILES)"
@$(PROVE.tap) $(TAPFILES) || $(PROVE_FAILURE)
endif
CURRENT_TAPFILES := $(wildcard $(TAPFILES))
@@ -407,7 +407,7 @@ ifneq ($(CURRENT_JUNITFILES),)
endif
# A .tap file is the output from running the associated test script
$(TAPFILES.t): %.tap: %.t
$(TAPFILES.t): %.tap: %.t | build
ifdef RUNTESTS_ENABLED
$(ECHO) "$(PERL) $< -tap > $@"
@$(PERL) $< -tap > $@ || $(TAPFILE_FAILURE)

View File

@@ -27,7 +27,7 @@ $(foreach file,$(MAKEFILE_LIST), \
PRINT_Var = $(@:PRINT.%=%)
PRINT.%:
@echo $(PRINT_Var) = '$($(PRINT_Var))'
@+echo $(PRINT_Var) = '$($(PRINT_Var))'
.PHONY: PRINT PRINT.%

View File

@@ -47,7 +47,7 @@ vpath %@ $(USR_VPATH) $(ALL_SRC_DIRS)
# INC += myVersion.h
# Default settings
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl
EXPAND_TOOL ?= $(PERL) $(TOOLS)/expandVars.pl $(QUIET_FLAG)
EXPANDARCH = -a $(T_A)
EXPANDFLAGS += -t $(INSTALL_LOCATION)
@@ -55,22 +55,17 @@ EXPANDFLAGS += $(addprefix -D ,$(EXPAND_VARS) $($@_EXPAND_VARS))
EXPANDFLAGS += $(foreach var, $(EXPAND_ME) $($@_EXPAND_ME), \
-D$(var)="$(strip $($(var)))")
# The names of files to be expanded must end with '@'
# Output files
EXPANDED = $(EXPAND:%@=%)
EXPANDED_COM = $(EXPAND_COMMON:%@=%)
EXPANDED_COMMON = $(EXPANDED_COM:%=$(COMMON_DIR)/%)
EXPANDED_COMMON = $(EXPAND_COMMON:%@=$(COMMON_DIR)/%)
$(EXPANDED): %: %@
$(ECHO) "Expanding $< to $@"
@$(RM) $@
$(EXPAND_TOOL) $(EXPANDARCH) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
$(EXPANDED_COM): %: %@
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %@
$(ECHO) "Expanding $< to $(COMMON_DIR)/$@"
@$(RM) $@
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
$(EXPANDED_COMMON): $(COMMON_DIR)/%: %
@$(MV) $< $@
clean: expand_clean

View File

@@ -22,9 +22,11 @@
# 7. Submodules must have a configure/CONFIG_SITE file that contains
# -include $(TOP)/../CONFIG_SITE.local
# Add checked-out submodules to DIRS
LIVE_SUBMODULES = $(subst /Makefile,,$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
DIRS += $(LIVE_SUBMODULES)
# Add checked-out submodules to DIRS, unless INSTALL_LOCATION is empty
LIVE_SUBMODULES = $(subst /Makefile,, \
$(wildcard $(addsuffix /Makefile, $(SUBMODULES))))
live = $(if $(wildcard $(INSTALL_CONFIG)/RULES_TOP),LIVE,DEAD)
DIRS += $($(live)_SUBMODULES)
include $(CONFIG)/RULES_DIRS
@@ -37,14 +39,13 @@ all host $(DIRS) $(ARCHS) $(ACTIONS) $(dirActionTargets) $(dirArchTargets) \
# Convenience target
RELEASE.host: $(RELEASE_LOCAL)
$(RELEASE_LOCAL): Makefile CONFIG_SITE.local
$(RELEASE_LOCAL): Makefile $(CONFIG)/CONFIG_SITE \
$(wildcard $(CONFIG)/CONFIG_SITE.local)
$(ECHO) Creating $@ with
$(ECHO) " $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)"
@echo $(PARENT_MODULE) = $(INSTALL_ABSOLUTE)> $@
realclean:
$(RM) $(wildcard RELEASE.*.local)
.PHONY: RELEASE.host realclean
.PHONY: RELEASE.host
# Testing: Combine test failure logs from the live submodules
TESTS_FAILED_LOGS = $(wildcard $(addsuffix /$(TESTS_FAILED_LOG), \

View File

@@ -23,35 +23,42 @@ ifndef DISABLE_TOP_RULES
# Rules for a regular application top directory
#
distclean: realclean cvsclean realuninstall
# When run by 'make distclean' the realuninstall target also
# removes any modules/RELEASE.<host>.local files
distclean: realclean cvsclean realuninstall
realuninstall: uninstallDirs
realuninstall: uninstallDirs
$(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)
ifeq (modules,$(filter modules,$(DIRS)))
ifeq (distclean,$(filter distclean,$(MAKECMDGOALS)))
$(RM) $(wildcard modules/RELEASE.*.local)
endif
endif
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs: | clean
UNINSTALL_DIRS += $(INSTALL_DB) $(INSTALL_DBD) $(INSTALL_DOC) $(INSTALL_HTML)
UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs:
$(RMDIR) $(UNINSTALL_DIRS)
# Remove the bin and lib directories if they have no sub-directories
#
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs | clean
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs
$(RMDIR) $(EMPTY_INSTALL_DIRS)
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
uninstall$(DIVIDER)%: | clean
uninstall$(DIVIDER)%:
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))
# Only run this at the top of the parent
runtests test-results:
# Only run this at the top of the parent
runtests test-results:
@$(SHOWTESTFAILURES)
else
@@ -76,7 +83,6 @@ help:
@echo " inc - Installs header, dbd and html files"
@echo " build - Builds and installs all targets"
@echo " install - Builds and installs all targets"
@echo " buildInstall - Same as install (deprecated)"
@echo " clean - Removes the O.<arch> dirs created by running make"
@echo " In O.<arch> dir, clean removes build created files"
@echo " realclean - Removes ALL O.<arch> dirs"
@@ -101,7 +107,8 @@ ifndef DISABLE_TOP_RULES
@echo " uninstall$(DIVIDER)<arch> - Remove bin & lib directories for <arch> only."
@echo " uninstall - Remove install directories created by this hostarch."
@echo " realuninstall - Removes ALL install dirs"
@echo " distclean - Same as realclean cvsclean realuninstall."
@echo " distclean - Does realclean cvsclean realuninstall and deletes any"
@echo " generated modules/RELEASE.<host>.local files"
endif
@echo " help - Prints this list of valid make targets "
@echo "Object targets are supported by the O.<arch> level Makefile .e.g"

View File

@@ -77,7 +77,7 @@ CPPFLAGS += $($(BUILD_CLASS)_CPPFLAGS) $(POSIX_CPPFLAGS) $(OPT_CPPFLAGS)\
$(USR_CPPFLAGS) $(CMD_CPPFLAGS) $(ARCH_DEP_CPPFLAGS) $(OP_SYS_CPPFLAGS)\
$(OP_SYS_INCLUDE_CPPFLAGS) $(CODE_CPPFLAGS)
ECHO = @$(if $(filter -s,$(MFLAGS)),$(NOP),echo)
ECHO = @$(if $(make-s),$(NOP),echo)
# Originally set in os/CONFIG.UnixCommon.Common
MKDIR = mkdir -p

View File

@@ -11,14 +11,15 @@ MUNCH_SUFFIX = .boot
define MUNCH_CMD
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary -R .comment -S $< rtems
gzip -f9 rtems
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@ \
$(RTEMS_TOOLS)/bin/$(LD_FOR_TARGET) -o $@.elf \
$(PROJECT_RELEASE)/lib/bootloader.o \
--just-symbols=$< \
-b binary rtems.gz \
--no-warn-mismatch \
--no-warn-mismatch \
-T $(PROJECT_RELEASE)/lib/ppcboot.lds \
-Map $<.map
rm -f rtems.gz
$(RTEMS_TOOLS)/bin/$(OBJCOPY_FOR_TARGET) -O binary $@.elf $@
rm -f rtems.gz $@.elf
endef
include $(CONFIG)/os/CONFIG.Common.RTEMS

View File

@@ -7,6 +7,10 @@
# Include definitions common to all Unix targets
include $(CONFIG)/os/CONFIG.Common.UnixCommon
GNU = NO
CMPLR_CLASS = clang
CC = clang
CCC = clang++
OS_CLASS = freebsd

View File

@@ -0,0 +1,21 @@
# CONFIG.Common.vxWorks-e500v2
#
# Definitions for vxWorks-e500v2 target archs (MVME2500)
# Sites may override these definitions in CONFIG_SITE.Common.vxWorks-e500v2
#-------------------------------------------------------
# Include definitions common to all vxWorks target archs
include $(CONFIG)/os/CONFIG.Common.vxWorksCommon
# Vx GNU cross compiler suffix
CMPLR_SUFFIX = ppc
ARCH_CLASS = ppc
# Architecture specific build flags
ARCH_DEP_CFLAGS += -te500v2 -mhard-float
ARCH_DEP_CPPFLAGS += -DCPU=PPC85XX
ARCH_DEP_CFLAGS += -DCPU_VARIANT=_ppc85XX_e500v2
ARCH_DEP_CFLAGS += -mlongcall
GNU_TARGET = powerpc-wrs-vxworks

View File

@@ -12,7 +12,7 @@ ARCH_CLASS = x86
POSIX = NO
# Definitions used when COMMANDLINE_LIBRARY is READLINE
LDLIBS_READLINE = -lreadline -lcurses
LDLIBS_READLINE = -lreadline -ltermcap
ARCH_DEP_CFLAGS += -m32
ARCH_DEP_LDFLAGS += -m32

View File

@@ -66,7 +66,7 @@ GNU = NO
#
# Darwin shared libraries
#
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace -undefined dynamic_lookup \
SHRLIB_LDFLAGS = -dynamiclib -flat_namespace \
-install_name $(abspath $(INSTALL_LIB))/$@ \
$(addprefix -compatibility_version , $(SHRLIB_VERSION)) \
$(addprefix -current_version , $(SHRLIB_VERSION))

View File

@@ -5,3 +5,4 @@
#Include definitions common to unix hosts
include $(CONFIG)/os/CONFIG.UnixCommon.Common
CMPLR_CLASS = clang

View File

@@ -2,6 +2,7 @@
# Definitions for freebsd-x86 host - freebsd-x86 target builds
# Sites may override these definitions in CONFIG_SITE.freebsd-x86.freebsd-x86
#-------------------------------------------------------
GNU_DIR=/usr/local
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon

View File

@@ -2,6 +2,7 @@
# Definitions for freebsd-x86_64 host - freebsd-x86_64 target builds
# Sites may override these definitions in CONFIG_SITE.freebsd-x86_64.freebsd-x86_64
#-------------------------------------------------------
GNU_DIR=/usr/local
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon

View File

@@ -6,3 +6,8 @@
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon
STATIC_LDFLAGS_YES= -Wl,-Bstatic
STATIC_LDFLAGS_NO=
STATIC_LDLIBS_YES= -Wl,-Bdynamic
STATIC_LDLIBS_NO=

View File

@@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
GNU_LDLIBS_YES =
# Link with system libraries
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp

View File

@@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \
GNU_LDLIBS_YES =
# Link with system libraries
OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp
OP_SYS_LDLIBS += -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp

View File

@@ -34,5 +34,6 @@
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 instead.
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 or for
# cross-builds in CONFIG_SITE.<host-arch>.linux-aarch64 instead.

View File

@@ -15,11 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -12,10 +12,6 @@
GNU_DIR = /usr/local/vw/microblaze-2.0/microblazeel-unknown-linux-gnu
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -15,10 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -15,10 +15,6 @@
# to inform the system of the shared library location.
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(GNU_DIR)/include/readline/readline.h), READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -3,11 +3,6 @@
# Site-specific settings for the linux-xscale_be target
# Use GNU Readline if the header file is installed
COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
$(firstword $(READLINE_DIR) $(GNU_DIR))/include/readline/readline.h), \
READLINE, EPICS))
# If libreadline needs additional libraries to be linked with it, try
# uncommenting each of the lines below in turn, starting with the top
# one and working downwards, until the build succeeds. Do a 'make rebuild'

View File

@@ -3,21 +3,27 @@
# Site specific definitions for darwin builds
#-------------------------------------------------------
# Note the dir/firstword/wildcard functions below are used
# to avoid warnings about missing directories.
# These settings are designed for users of Homebrew.
# Users of other third-party package managers are welcome to
# provide patches appropriate for their manager.
ifneq (,$(wildcard /opt/homebrew))
# Default location on aarch64
HOMEBREW_DIR = /opt/homebrew
else ifneq (,$(wildcard /usr/local/Homebrew))
# Default location on x86_64
HOMEBREW_DIR = /usr/local
else ifneq (,$(wildcard /opt/local/include/readline))
# MacPorts
READLINE_DIR = /opt/local
endif
# Mix-and-match of different package systems is probably not advisable,
# but you can try that if you like...
# Uncomment these definitions when using Homebrew packages:
#OP_SYS_INCLUDES += -I/usr/local/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /usr/local/lib/*))))
# Uncomment these definitions when using DarwinPorts packages:
#OP_SYS_INCLUDES += -I/opt/local/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /opt/local/lib/*))))
# Uncomment these definitions when using Fink packages:
#OP_SYS_INCLUDES += -I/sw/include
#OP_SYS_LDFLAGS += $(addprefix -L,$(dir $(firstword $(wildcard /sw/lib/*))))
# Look for Homebrew's readline
ifneq (,$(wildcard $(HOMEBREW_DIR)/opt/readline))
READLINE_DIR = $(HOMEBREW_DIR)/opt/readline
endif
# Use GNU readline if it's avaiilable
ifneq (,$(wildcard $(READLINE_DIR)/include/readline/readline.h))
INCLUDES_READLINE = -I$(READLINE_DIR)/include
LDFLAGS_READLINE = -L$(READLINE_DIR)/lib
endif

View File

@@ -1,6 +1,6 @@
# CONFIG_SITE.linux-x86.linux-aarch64
# CONFIG_SITE.linux-x86_64.linux-aarch64
#
# Site specific definitions for linux-x86 host - linux-aarch64 target builds
# Site specific definitions for linux-x86_64 host - linux-aarch64 target builds
#-------------------------------------------------------
# Set GNU crosscompiler target name

View File

@@ -35,3 +35,15 @@ OS_API = posix
OS_API = score
# endif
#endif
#ifdef __has_include
# if defined(__rtems__) && __RTEMS_MAJOR__<5 && __has_include(<libtecla.h>)
COMMANDLINE_LIBRARY ?= LIBTECLA
# elif __has_include(<readline/readline.h>)
COMMANDLINE_LIBRARY ?= READLINE
# else
COMMANDLINE_LIBRARY ?= EPICS
# endif
#else
COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS))
#endif

View File

@@ -0,0 +1,170 @@
=head1 EPICS Component Reference Manual
This document provides reference information about the record types,
menus, link types and channel filters included with EPICS Base.
Many details about the record and menu definitions are derived automatically
from the source code at build time.
=head2 Introduction and IOC Concepts
These links point to an external website where introductory and overview
documentation is now being published.
=over
=item * L<Introduction to EPICS|https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html>
=item * L<Process Database Concepts|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html>
=back
=head2 Record Type Definitions
These sections describe common aspects of the record types:
=over
=item * L<Fields Common to All Record Types|dbCommonRecord>
=item * L<Fields Common to Input Record Types|dbCommonInput>
=item * L<Fields Common to Output Record Types|dbCommonOutput>
=back
These are the record types supplied with EPICS Base:
=over
=item * L<Analog Array Input Record (aai)|aaiRecord>
=item * L<Analog Array Output Record (aao)|aaoRecord>
=item * L<Analog Input Record (ai)|aiRecord>
=item * L<Analog Output Record (ao)|aoRecord>
=item * L<Array Subroutine Record (aSub)|aSubRecord>
=item * L<Binary Input Record (bi)|biRecord>
=item * L<Binary Output Record (bo)|boRecord>
=item * L<Calculation Output Record (calcout)|calcoutRecord>
=item * L<Calculation Record (calc)|calcRecord>
=item * L<Compression Record (compress)|compressRecord>
=item * L<Data Fanout Record (dfanout)|dfanoutRecord>
=item * L<Event Record (event)|eventRecord>
=item * L<Fanout Record (fanout)|fanoutRecord>
=item * L<Histogram Record (histogram)|histogramRecord>
=item * L<64-bit Integer Input Record (int64in)|int64inRecord>
=item * L<64-bit Integer Output Record (int64out)|int64outRecord>
=item * L<Long Input Record (longin)|longinRecord>
=item * L<Long Output Record (longout)|longoutRecord>
=item * L<Long String Input Record (lsi)|lsiRecord>
=item * L<Long String Output Record (lso)|lsoRecord>
=item * L<Multi-Bit Binary Input Direct Record (mbbiDirect)|mbbiDirectRecord>
=item * L<Multi-Bit Binary Input Record (mbbi)|mbbiRecord>
=item * L<Multi-Bit Binary Output Direct Record (mbboDirect)|mbboDirectRecord>
=item * L<Multi-Bit Binary Output Record (mbbo)|mbboRecord>
=item * L<Permissive Record (permissive)|permissiveRecord>
=item * L<Printf Record (printf)|printfRecord>
=item * L<Select Record (sel)|selRecord>
=item * L<Sequence Record (seq)|seqRecord>
=item * L<State Record (state)|stateRecord>
=item * L<String Input Record (stringin)|stringinRecord>
=item * L<String Output Record (stringout)|stringoutRecord>
=item * L<Sub-Array Record (subArray)|subArrayRecord>
=item * L<Subroutine Record (sub)|subRecord>
=item * L<Waveform Record (waveform)|waveformRecord>
=back
=head2 Menu Definitions
Menu field choices are documented with the record type that defines them, or
here for the global menus that are used by multiple record types:
=over
=item * L<Alarm Severity Menu|menuAlarmSevr>
=item * L<Alarm Status Menu|menuAlarmStat>
=item * L<Analog Conversions Menu|menuConvert>
=item * L<Field Type Menu|menuFtype>
=item * L<Invalid Value Output Action Menu|menuIvoa>
=item * L<Output Mode Select Menu|menuOmsl>
=item * L<Process at iocInit Menu|menuPini>
=item * L<Post Monitors Menu|menuPost>
=item * L<Priority Menu|menuPriority>
=item * L<Scan Menu|menuScan>
=item * L<Simulation Mode Menu|menuSimm>
=item * L<YesE<sol>No Menu|menuYesNo>
=back
=head2 Other Components
EPICS Base also comes with extensible sets of server Channel Filters and IOC
Database Link types, which are documented here:
=over
=item * L<Channel Filters|filters>
=item * L<IOC Database Link Types|links>
=back
=head2 Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS
core developers, or as GitHub pull requests to the 7.0 branch of Base.
These document sources can be found under `modules/database/src` tree, mostly
in the `std/rec` and `ioc/db` directories in files with extension `.dbd.pod`.
The documentation source format is a combination of the EPICS DBD file format
with an extended version of Perl's POD (plain old documentation); run `perldoc
pod` for details of POD.

View File

@@ -762,7 +762,6 @@ WARN_LOGFILE =
INPUT = ../mainpage.dox \
../RELEASE_NOTES.md \
../README.md \
../RecordReference.md \
@TOP@/include
# This tag can be used to specify the character encoding of the source files

View File

@@ -1,24 +1,24 @@
TOP = ..
include $(TOP)/configure/CONFIG
ifeq ($(T_A),$(EPICS_HOST_ARCH))
DOXYGEN=doxygen
EXPAND = Doxyfile@
EXPAND_ME += EPICS_VERSION
EXPAND_ME += EPICS_REVISION
EXPAND_ME += EPICS_MODIFICATION
EXPAND_ME += EPICS_PATCH_LEVEL
EXPAND_ME += OS_CLASS CMPLR_CLASS
HTMLS += ComponentReference.html
TARGETS += doxygen
DOXYGEN = doxygen
ME = documentation/O.$(T_A)/html
GH_FILES = $(ME)/ $(ME)/.nojekyll $(ME)/*.* $(ME)/*/*.*
install: doxygen
include $(TOP)/configure/RULES
doxygen: Doxyfile ../mainpage.dox
doxygen: Doxyfile ../mainpage.dox $(INSTALL_HTMLS)
$(DOXYGEN)
rsync -av $(TOP)/html/ html/
@@ -29,7 +29,3 @@ commit: doxygen
(cd $(TOP) && $(CURDIR)/../commit-gh.sh $(GH_FILES))
.PHONY: commit
endif # EPICS_HOST_ARCH
include $(TOP)/configure/RULES

View File

@@ -387,7 +387,7 @@ install directories.
EPICS executables and perl scripts are installed into the
`$(INSTALL_LOCATION)/bin/<arch>` directories. Libraries are installed
into $`(INSTALL_LOCATION)/lib/<arch>`. The default definition for
into `$(INSTALL_LOCATION)/lib/<arch>`. The default definition for
`$(INSTALL_LOCATION)` is `$(TOP)` which is the root directory in the
distribution directory structure, `base`. Intermediate object files
are stored in `O.<arch>` source subdirectories during the build

View File

@@ -2,19 +2,348 @@
These release notes describe changes that have been made since the previous
release of this series of EPICS Base. **Note that changes which were merged up
from commits to the 3.15 branch are not described at the top of this file but
lower down, under the 3.15 release to which they were originally committed.**
Thus it is important to read more than just the first section to understand
everything that has changed in each release.
from commits to the 3.15 branch are described
[further down this file](#changes-incorporated-from-the-315-branch)
under the 3.15 release to which they were originally committed.** Thus it is
important to read more than just the first section to understand everything that
has changed in each release.
The PVA submodules each have their own individual sets of release notes which
should also be read to understand what has changed since earlier releases.
**This version of EPICS has not been released yet.**
## Changes made on the 7.0 branch since 7.0.6.1
## Changes made on the 7.0 branch since 7.0.7
<!-- Insert new items immediately below here ... -->
### Fixed leak from a non-EPICS thread on WIN32
On Windows targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated. Prior to this release the allocation would not be `free()`d,
resulting in a memory leak.
A similar issue on POSIX targets was previously fixed.
### Change compiler for FreeBSD to clang
The default compiler for FreeBSD targets changes from GCC to clang.
### Expose `dbCreateAlias` in IOC shell
Add a new IOC shell command `dbCreateAlias` allow record aliases to be added.
Intended for use before `iocInit`. eg. to add an alias "bar" for a record "foo".
```
dbLoadRecords("some.db") # includes: record(ai, "foo") { ...
dbCreateAlias("foo", "bar")
iocInit()
```
### dbEvent eventsRemaining missed on cancel
In some cases, RSRV may queue a subscription update, but not flush it.
This partially addresses this issue.
### subRecord on bad INP links
Previously, if a subRecord has an invalid `INP*` link, it was silently failing
(and not running the proc function). Now the the status code returned by the
subroutine is returned from `dbProcess()`.
### COMMANDLINE_LIBRARY fallback to GNU_DIR
Fall back to the previous behavior when searching for `readline.h` with older compilers.
### Search for readline installed via HomeBrew.
Look for `/opt/local/include/readline` on OSX.
### Always stop worker threads
The SCAN and callback threads are now stopped during normal IOC shutdown.
### Allow runtime bypass of free list allocator
The environment variable `$EPICS_FREELIST_BYPASS` may be set to `YES` to cause the `freeListLib` functions to always call directly to `malloc()`/`free()`. May be useful when troubleshooting some kinds of memory allocation bugs which would otherwise be "hidden". eg. use-after-free data races. This may also improve the results of dynamic analysis tools which are not aware of this internal free list.
### `compress` record enhancement
The compress record now supports the use of partially-filled buffers when using
any of the N-to-one algorithms. This is achieved by setting the new field `PBUF`
to `YES`.
### Extended timestamp channel filter
The `"ts"` filter can now retrieve the record's timestamp in several numeric
and string formats, some of which support full nanosecond precision.
Hal$ caget -a test:channel
test:channel 2021-03-11 18:23:48.265386 42
Hal$ caget -f9 'test:channel.{"ts": {"num": "dbl"}}'
test:channel.{"ts": {"num": "dbl"}} 984331428.265386105
Hal$ caget 'test:channel.{"ts": {"str": "iso"}}'
test:channel.{"ts": {"str": "iso"}} 2021-03-11T18:23:48.265386+0100
Hal$ caget -f1 'test:channel.{"ts": {"num": "ts"}}'
test:channel.{"ts": {"num": "ts"}} 2 984331428.0 265386163.0
More information is included in the filters documentation, which can be found in
the `html/filters.html` document that is generated during the build
### Add conditional output (OOPT) to the longout record
The longout record can now be configured using its new OOPT and OOCH fields
to (not) write to its output link depending on the contents of VAL, in a
similar manner to the calcout record. More information can be found on the
reference page for the longout record type that accompanies this release.
This functionality was suggested in
[lp# 1398215](https://bugs.launchpad.net/epics-base/+bug/1398215) and may
be added to other output record types if the community finds it useful,
please send feedback about the feature to tech-talk.
### Tab completion for IOC shell
When built with optional GNU libreadline support, the interactive IOC shell
will perform tab completion for command names as well as for some arguments
of the built-in commands. For example, the record name argument of `dbpr`,
and the path name argument of `cd`.
Externally defined commands have a limited ability to opt into completion by
using the new `iocshArgStringRecord` and `iocshArgStringPath` argument types.
Both function identically to `iocshArgString` but indicate how to suggest
completion strings.
Builds on macOS (darwin-x86 or darwin-aarch64 targets) normally use Apple's
libedit library in readline compatibility mode, which doesn't support the tab
completion API that GNU readline provides. You can use Homebrew or some other
third-party package manager to install the GNU readline package, then edit the
configure/os/CONFIG_SITE.darwinCommon.darwinCommon file to have EPICS use the
real thing to get tab completion in the IOC shell. The default settings in that
file currently look for and use a Homebrew-installed readline if present.
### Add FMOD as CALC Expression
The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC
expression engine and is available to all software using that (calc and calcout
record types, access security library and some extensions).
-----
## EPICS Release 7.0.7
### Doxygen Annotations
Thanks to several attendees at the 2022 EPICS Codeathon the number of header
files with Doxygen annotations in the EPICS Core has again increased.
### Build System updates
The top-level make targets `uninstall`, `archuninstall` and similar no
longer trigger the `clean` target which empties build directories, this
was a bug introduced in 7.0.5.
The `make distclean` target now properly deletes the generated file(s)
`modules/RELEASE.<host>.local` which are essential to build the external
submodules under the `modules` directory, and should not crash if the
build is configured with `INSTALL_LOCATION` pointing to an empty external directory (i.e. if you run `make distclean` twice in succession). When
`INSTALL_LOCATION` is set in the files `configure/CONFIG_SITE` or
`configure/CONFIG_SITE.local` the `modules/RELEASE.<host>.local` file
will now be regenerated in case the install path has been modified.
Note that passing `INSTALL_LOCATION=<path>` on the make command-line will
only work if you have run `make distclean` immediately beforehand, as the
`modules/RELEASE.<host>.local` file must be recreated using the new path.
### Enhancements to `capr.pl`
The `capr.pl` script can now display records from older Base versions to
which fields have since been added, and shows long strings and array data
up to 10 elements, use the new `-n` option to increase that number.
The script is fully event-driven and prints all the field data received by
the end of the CA wait time (`-w` option which defaults to 2 seconds).
The interest level can now be specified using the `-l` option before the
PV name, and the new `-D` flag outputs debugging information.
### Time Synchronization on VxWorks
VxWorks 6.9 can do its own OS clock time synchronization, if it has been
configured by setting `SNTPC_PRIMARY_IPV4_ADDR`. Since EPICS 3.15.3 the
IOC time support code has checked for the existence of the VxWorks time
synchronization task and avoided starting the EPICS one if the OS task
exists and the OS clock gives a "recent" time (i.e. after when EPICS was
compiled), unless the environment variable `EPICS_TS_FORCE_NTPTIME` is
also set. However a logic error in that code required the environment
variable to be set in more cases than it should have.
This error has been fixed and the IOC should work normally if the VxWorks
task is configured and running. The `TIMEZONE` value for the year is also
now calculated at initialization in this configuration, previously it was
only done when the IOC synchronzation task was used. Setting the above
environment variable will now cause the IOC support code to shut down the
VxWorks synchronization thread (if running) before starting the EPICS one.
Running the iocsh command `ClockTime_Report` now shows whether the VxWorks
task is running as well as giving the state of the IOC synchronization task.
The `ClockTime_Init` command can also be used to stop or restart the IOC
time synchronization task while the IOC is running, depending on the `0` or
`1` parameter passed to it. This last change also applies to RTEMS IOCs.
### Incompatible change to `struct db_field_log`
This change may cause channel filters which manipulate array updates
to fail to compile.
To avoid potential speculation issues arising from overlapping code pointers
with data values, `union dbfl_ref` is modified to remove the `dtor` member.
`dtor` is moved out into the enclosing `struct db_field_log`.
So eg. using a `db_field_log* p`, the expression `p->u.r.dtor` must be
changed to `(p)->dtor`.
### Fix undef ts on first camonitor update of NORD from waveformRecord
The order over operations when processing a waveformRecord is adjusted
so that updates to NORD is posted with the correct timestamp.
### Automatic COMMANDLINE_LIBRARY w/ newer compilers
When built with a compiler supporting `__has_include<>`, the presence
of the `<readline/readline.h>` will be used to automatically determine
a default value for `COMMANDLINE_LIBRARY`.
Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`.
This should not effect sites which set explicitly set `COMMANDLINE_LIBRARY`
as the only definition in Base now has the form `COMMANDLINE_LIBRARY ?= ...`.
### Perl CA support for empty long strings
The Perl CA bindings have been fixed to handle zero-length long string data
properly.
### `aao` gains `OMSL` and `DOL`
The `aao` record types gains the same `DOL` functionality found
in other output record types (`ao`, `longout`, etc.)
### Server exports `RSRV_SERVER_PORT`
During `iocInit()`, the environment variable `RSRV_SERVER_PORT` is set
with the TCP port number selected.
### `dbdExpand.pl` sorts all items by name
DBD files generated by the `dbdExpand.pl` script are now sorted within each
item type by the primary name of the item. The result should resolve any
issues with reproducable builds. No option is provided to prevent the sorting,
previously the order was essentially random and varied each time.
### `dbExpand.pl` sorts records by name
Records are now output by this program in order, sorted by name. The new flag
`-s` can be given to output the records in the same order they were read in,
instead of sorting them.
Note that there are currently no build rules provided with Base which make use
of this program.
### Simulation Mode RAW Support for Output Record Types
SIMM=RAW support has been added for the relevant output record types
(ao, bo, mbbo, mbboDirect).
RAW simulation mode will have those records do the appropriate conversion
and write RVAL to the location pointed to by SIOL.
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
struct would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX targets.
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
for WIN32 status.
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
allocation would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX and WIN32 targets (excluding
MSVC before vs2012, and the WINE runtime).
### Fixed leak from a non-EPICS thread
On some targets, if a thread not created by `epicsThreadCreate*()` directly
or indirectly calls an `epicsThread*()` function, a specific tracking struct
is allocated.
Prior to this release, on POSIX and WIN32 targets, this
struct would not be `free()`d, resulting in a memory leak.
This release fixed the leak on POSIX targets.
See the associated github [issue 241](https://github.com/epics-base/epics-base/issues/241)
for WIN32 status.
### Fix `CHECK_RELEASE = WARN`
This now works again, it was broken in 2019 (7.0.3.1) by an errant commit.
### Document `DISP` as design-time field
The DISP field can be set to a non-zero value to prevent records being changed
from outside the IOC (this is ancient behavior), but has never been documented
as being usable at design-time (DCT=Yes in the Record Reference tables). This
has now been changed.
### Make `epicsInt8` signed on all architectures
The `epicsInt8` and thus `DBF_CHAR` types have always been unsigned on
architectures where `char` is unsigned, for example on many PowerPC CPU
architectures. This was counter-intuitive, and resulted in IOC behavior
differing between architectures when converting `DBF_CHAR` values into a
signed integer or floating point type.
**WARNING**: This fix may change behavior of existing databases on target
architectures with unsigned `char` (mainly PowerPC) when using input links to
read from `CHAR` arrays. Architectures with signed `char` (usually x86) should
be unaffected, although some compilers might generate new warnings.
### Allow hexadecimal and octal numbers in hardware links
[GH:213](https://github.com/epics-base/epics-base/pull/213)
Several types of hardware links (`VME_IO`, `CAMAC_IO`, etc) now accept
hexadecimal and octal numbers. (Hexadecimal numbers had already been valid
up to EPICS R3.15.) This change may introduce incompatibilities when using
numbers with leading `0` as they will now be parsed as octal.
### Fix embedded implementations of `epicsEvent`
[GH:202](https://github.com/epics-base/epics-base/issues/202) and
[GH:206](https://github.com/epics-base/epics-base/pull/206)
Heinz Junkes provided a new implementation of the `epicsEvent` API suitable for
RTEMS Posix targets (RTEMS 5.1 and later). In review a few issues related to
overflow of timeout values surfaced in this and other embedded implementations,
and these were also been fixed in this Pull Request. The API documentation for
this and some other routines has also been updated.
### Breakpoint Table Names
The names of breakpoint tables were made unnecessarily strict when DBD file
processing was moved to Perl for the 3.15 release series. Table names may now
contain the special characters `_` `-` `:` `;` `.` `[` `]` `<` `>` in addition
to letters and digits.
### Fix for `undefined` in configure/RELEASE files
@@ -67,7 +396,7 @@ monitors posted on the bit fields.
Some scripts now make use of features that were introduced to this Perl version
that was released in 2009.
### DB Links to DBF_MENU fields fixed
### DB Links to `DBF_MENU` fields fixed
[GH:183](https://github.com/epics-base/epics-base/issues/183)
These were broken in a previous release, but now work again.
@@ -409,10 +738,10 @@ broken.
This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295).
### Support for Apple M1 (arm64) Processors
### Support for Apple M1/M2 (arm64) Processors
Thanks to Jeong Han Lee this release comes with build support for Apple's new
M1 CPUs running macOS, using the target name `darwin-aarch64`.
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
It should also be possible to build universal binaries containing code for
both the Intel and arm64 processors under either target name: In the
@@ -1428,7 +1757,7 @@ editing and history. This functionality has now been restored, see Launchpad
### Constant link types
Constant links can now hold 64-bit integer values, either as scalars or
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
arrays. Only base 10 is supported by the JSON parser though, the JSON standard
doesn't allow for hexadecimal numbers.
### Upgraded the YAJL JSON Library
@@ -2026,6 +2355,17 @@ header and removed the need for dbScan.c to reach into the internals of its
## Changes from the 3.15 branch since 3.15.9
### Support for Apple M1/M2 (arm64) Processors
Thanks to Jeong Han Lee this release comes with build support for Apple's new
M1/M2 CPUs running macOS, using the target name `darwin-aarch64`.
### Set thread names on Windows
On MS Windows, epicsThread names are made available to the OS and debugger
using `SetThreadDescription()` if available as well as using the older
exception mechanism.
### Fix timers on MS Windows for non-EPICS threads
The waitable timer changes in 3.15.9 broke calls to `epicsThreadSleep()` and

View File

@@ -1,74 +0,0 @@
# Record Reference Documentation {#recordrefmanual}
The documentation below for the record types and menus included with Base was
converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base. The first two links below are to an external
website where these original reference chapters are now being published.
* [Introduction to EPICS](https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html)
* [Process Database Concepts](https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html)
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInput.html)
* [Fields Common to Output Record Types](dbCommonOutput.html)
## Record Types
* [Analog Array Input Record (aai)](aaiRecord.html)
* [Analog Array Output Record (aao)](aaoRecord.html)
* [Analog Input Record (ai)](aiRecord.html)
* [Analog Output Record (ao)](aoRecord.html)
* [Array Subroutine Record (aSub)](aSubRecord.html)
* [Binary Input Record (bi)](biRecord.html)
* [Binary Output Record (bo)](boRecord.html)
* [Calculation Output Record (calcout)](calcoutRecord.html)
* [Calculation Record (calc)](calcRecord.html)
* [Compression Record (compress)](compressRecord.html)
* [Data Fanout Record (dfanout)](dfanoutRecord.html)
* [Event Record (event)](eventRecord.html)
* [Fanout Record (fanout)](fanoutRecord.html)
* [Histogram Record (histogram)](histogramRecord.html)
* [64bit Integer Input Record (int64in)](int64inRecord.html)
* [64bit Integer Output Record (int64out)](int64outRecord.html)
* [Long Input Record (longin)](longinRecord.html)
* [Long Output Record (longout)](longoutRecord.html)
* [Long String Input Record (lsi)](lsiRecord.html)
* [Long String Output Record (lso)](lsoRecord.html)
* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html)
* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html)
* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html)
* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html)
* [Permissive Record (permissive)](permissiveRecord.html)
* [Printf Record (printf)](printfRecord.html)
* [Select Record (sel)](selRecord.html)
* [Sequence Record (seq)](seqRecord.html)
* [State Record (state)](stateRecord.html)
* [String Input Record (stringin)](stringinRecord.html)
* [String Output Record (stringout)](stringoutRecord.html)
* [Sub-Array Record (subArray)](subArrayRecord.html)
* [Subroutine Record (sub)](subRecord.html)
* [Waveform Record (waveform)](waveformRecord.html)
## Menu Definitions
* [Alarm Severity Menu](menuAlarmSevr.html)
* [Alarm Status Menu](menuAlarmStat.html)
* [Analog Conversions Menu](menuConvert.html)
* [Field Type Menu](menuFtype.html)
* [Invalid Value Output Action Menu](menuIvoa.html)
* [Output Mode Select Menu](menuOmsl.html)
* [Process at iocInit Menu](menuPini.html)
* [Post Monitors Menu](menuPost.html)
* [Priority Menu](menuPriority.html)
* [Scan Menu](menuScan.html)
* [Simulation Mode Menu](menuSimm.html)
* [Yes/No Menu](menuYesNo.html)
## Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS core
developers, or as merge requests or pull requests to the 7.0 branch of Base.
The document sources can be found in the `modules/database/src/std/rec` and
`modules/database/src/ioc/db` directories in files with extension `.dbd.pod`.
The documentation source format is a combination of the EPICS DBD file format
with an extended version of Perl's POD (plain old documentation); run `perldoc
pod` for details of POD.

View File

@@ -54,8 +54,8 @@ everything that has to be done since it's so easy to miss steps.</p>
<dd>Responsible for individual operating system platforms</dd>
<dt><strong>Application Developers</strong></dt>
<dd>Responsible for support modules that depend on EPICS Base.</dd>
<dt><strong>Website Editor</strong> (Andrew Johnson)</dt>
<dd>Responsible for the EPICS website</dd>
<dt><strong>APS Website Editor</strong> (Andrew Johnson)</dt>
<dd>Responsible for the APS EPICS website</dd>
</dl>
<form>
@@ -180,6 +180,9 @@ everything that has to be done since it's so easy to miss steps.</p>
<p><b>For each external submodule</b> in turn (assuming it has not been
tagged yet):</p>
<ol>
<li><tt>git grep UNRELEASED</tt> and insert the module version to any
doxygen annotations that have a <tt>@since UNRELEASED</tt> comment.
Commit (don't push yet).</li>
<li>Check that the module's Release Notes have been updated to cover
all changes; add items as necessary, and set the module version
number and release date if appropriate. Convert to HTML and view in
@@ -188,7 +191,7 @@ everything that has to be done since it's so easy to miss steps.</p>
cd base-7.0/modules/&lt;module&gt;/documentation<br />
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md
</tt></blockquote>
Commit changes (don't push yet).</li>
Commit changes (don't push).</li>
<li>Edit the module's release version file
<tt>configure/CONFIG_<i>module</i>_VERSION</tt> and its top-level
@@ -198,7 +201,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<li>Tag the module:
<blockquote><tt>
git tag -m 'ANJ: Tag for EPICS 7.0.6.1' &lt;module-version&gt;
git tag -m 'ANJ: Tag for EPICS 7.0.7' &lt;module-version&gt;
</tt></blockquote>
</li>
@@ -267,7 +270,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Tag the epics-base module in Git:
<blockquote><tt>
cd base-7.0<br />
git tag -m 'ANJ: Tagged for release' R7.0.6.1
git tag -m 'ANJ: Tagged for release' R7.0.7
</tt></blockquote>
<p>Don't push anything to the Launchpad repository
yet.</p>
@@ -302,12 +305,12 @@ everything that has to be done since it's so easy to miss steps.</p>
files and directories that are only used for continuous integration:
<blockquote><tt>
cd base-7.0<br />
./.tools/make-tar.sh R7.0.6.1 ../base-7.0.6.1.tar.gz base-7.0.6.1/
./.tools/make-tar.sh R7.0.7 ../base-7.0.7.tar.gz base-7.0.7/
</tt></blockquote>
Create a GPG signature file of the tarfile as follows:
<blockquote><tt>
cd ..<br />
gpg --armor --sign --detach-sig base-7.0.6.1.tar.gz
gpg --armor --sign --detach-sig base-7.0.7.tar.gz
</tt></blockquote>
</td>
</tr>
@@ -372,7 +375,7 @@ everything that has to be done since it's so easy to miss steps.</p>
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
epics-controls web-server.
<blockquote><tt>
scp base-7.0.6.1.tar.gz base-7.0.6.1.tar.gz.asc epics-controls:download/base<br />
scp base-7.0.7.tar.gz base-7.0.7.tar.gz.asc epics-controls:download/base<br />
</tt></blockquote>
</td>
</tr>

View File

@@ -5,11 +5,11 @@ Documentation index
@li @ref releasenotes
@li @ref install
@li @ref recordrefmanual
@li <a href="ComponentReference.html">EPICS Component Reference Manual</a>
@li <a href="filters.html">Field Modifiers and Channel Filters</a>
@li <a href="links.html">Extensible IOC Database Links</a>
@li <a href="CAref.html">Channel Access Reference Manual</a>
@li <a href="filters.html">Server Side Filters Reference</a>
@li <a href="msi.html">msi: Macro Substitution and Include Tool</a>
@li <a href="links.html">JSON Link Types</a>
@li <a href="CA.html">Perl 5 Interface to Channel Access</a>
*/

View File

@@ -2,6 +2,16 @@
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
#
# modules/CONFIG_SITE.local
#
# Despite the .local in its name, this file *is* included in EPICS Base
# sources and should *not* be modified by sites. This trick is necessary
# to allow external submodules to be placed inside the modules directory
# without having to modify them, as long as their configure/CONFIG_SITE
# file includes the standard line
# -include $(TOP)/../CONFIG_SITE.local
# that causes this file to be read in during submodule builds.
# The name our submodules know us by:
PARENT_MODULE = EPICS_BASE

View File

@@ -32,7 +32,13 @@ static const iocshArg *acctstArgs[] =
&acctstArg3,
&acctstArg4
};
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
static const iocshFuncDef acctstFuncDef = {
"acctst",
5,
acctstArgs,
"Execute a Channel Access regression test.\n\n"
"For more information, see the 'acctst' documentation in the Channel Access reference.\n",
};
/* Wrapper called by iocsh, selects the argument types that print needs */

View File

@@ -392,9 +392,19 @@ void ca_client_context :: vSignal (
}
epicsTime current = epicsTime::getCurrent ();
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printFormated ( " Current Time: %s\n", date );
try {
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printFormated ( " Current Time: %s\n", date );
}
catch ( std::exception & except ) {
errlogPrintf (
"CA client library thread \"%s\" caught C++ exception \"%s\"\n",
epicsThreadGetNameSelf (), except.what () );
epicsTimeStamp now = current;
this->printFormated ( " Current Time: %u.%u\n",
now.secPastEpoch, now.nsec );
}
/*
* Terminate execution if unsuccessful

View File

@@ -559,19 +559,19 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id );
/*
* ca_pend_event()
*
* timeOut R wait for this delay in seconds
* timeout R wait for this delay in seconds
*/
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeOut);
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout);
#define ca_poll() ca_pend_event(1e-12)
/*
* ca_pend_io()
*
* timeOut R wait for this delay in seconds but return early
* timeout R wait for this delay in seconds but return early
* if all get requests (or search requests with null
* connection handler pointer have completed)
*/
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeOut);
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout);
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early);

View File

@@ -88,6 +88,7 @@ public:
bool push ( const T & value );
template < class T >
unsigned push ( const T * pValue, unsigned nElem );
unsigned push ( const char * pValue, unsigned nElem );
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
unsigned push ( const epicsOldString * pValue, unsigned nElem );
@@ -208,6 +209,11 @@ inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const char *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
{
unsigned index = this->nextWriteIndex;

View File

@@ -46,7 +46,7 @@ void comQueRecv::clear ()
this->nBytesPending = 0u;
}
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
unsigned comQueRecv::copyOutBytes ( char *pBuf, unsigned nBytes )
{
unsigned totalBytes = 0u;
do {

View File

@@ -33,7 +33,7 @@ public:
comQueRecv ( comBufMemoryManager & );
~comQueRecv ();
unsigned occupiedBytes () const;
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
unsigned copyOutBytes ( char *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
void pushLastComBufReceived ( comBuf & );
void clear ();

View File

@@ -79,7 +79,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
const char *pStr;
const char *pToken;
struct sockaddr_in addr;
char buf[32u]; /* large enough to hold an IP address */
char buf[256u]; /* large enough to hold an IP address or hostname */
int status, ret = -1;
pStr = envGetConfigParamPtr (pEnv);

View File

@@ -56,6 +56,7 @@ extern "C" void epicsStdCall ca_dump_dbr (
if ( INVALID_DB_REQ ( type ) ) {
printf ( "bad DBR type %ld\n", type );
return;
}
printf ( "%s\t", dbr_text[type] );

View File

@@ -202,7 +202,7 @@ udpiiu::udpiiu (
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf("CAC: failed to set mcast ttl %d\n", ttl);
errlogPrintf("CAC: failed to set mcast ttl %d\n", (int)ttl);
}
}
#endif

View File

@@ -12,6 +12,13 @@
* here and just generates unnecessary compiler warnings. */
#define REENTRINC
/* Clang-12 and later generates many warnings about compound token */
#ifdef __has_warning
# if __has_warning("-Wcompound-token-split-by-macro")
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
# endif
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
@@ -201,6 +208,8 @@ SV * newSVdbr(struct event_handler_args *peha) {
if (is_primitive) {
if (value_type == DBR_CHAR) {
/* Long string => Perl scalar */
if (peha->count == 0)
return newSVpvn(peha->dbr, 0);
((char *)peha->dbr) [peha->count - 1] = 0;
return newSVpv(peha->dbr, 0);
}
@@ -271,8 +280,12 @@ SV * newSVdbr(struct event_handler_args *peha) {
char *str = dbr_value_ptr(peha->dbr, peha->type);
/* Long string => Perl scalar */
str[peha->count - 1] = 0;
val = newSVpv(str, 0);
if (peha->count == 0)
val = newSVpvn(str, 0);
else {
str[peha->count - 1] = 0;
val = newSVpv(str, 0);
}
} else if (peha->count == 1) {
/* Single value => Perl scalar */
val = newSVdbf(value_type,

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env perl
#*************************************************************************
# Copyright (c) 2005 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2022 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# SPDX-License-Identifier: EPICS
# EPICS BASE is distributed subject to a Software License Agreement found
@@ -14,26 +14,24 @@
#
#######################################################################
use 5.10.1;
use strict;
use FindBin qw($Bin);
use lib ("$Bin/../../lib/perl");
use FindBin qw($RealBin);
use lib ("$RealBin/../../lib/perl");
use Getopt::Std;
use EPICS::Path;
use Cwd 'abs_path';
use CA;
######### Globals ##########
our ($opt_h, $opt_f, $opt_r);
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} || "$Bin/../../dbd/softIoc.dbd";
our $opt_w = 1;
our ($opt_h, $opt_f, $opt_l, $opt_r, $opt_D);
our $opt_d = $ENV{EPICS_CAPR_DBD_FILE} // abs_path("$RealBin/../../dbd/softIoc.dbd");
our $opt_w = 2;
our $opt_n = 10;
my %record = (); # Empty hash to put dbd data in
my $iIdx = 0; # Array indexes for interest, data type and base
my $tIdx = 1;
my $bIdx = 2;
my %device = (); # Empty hash to record which rec types have device support
# EPICS field types
my %fieldType = (
@@ -58,13 +56,14 @@ my %fieldType = (
);
# globals for sub caget
my %connected;
my $unconnected_count;
my %callback_data;
my %timed_out;
my $callback_incomplete;
######### Main program ############
HELP_MESSAGE() unless getopts('hd:f:rw:');
HELP_MESSAGE() unless getopts('hDd:f:l:n:rw:');
HELP_MESSAGE() if $opt_h;
die "File $opt_d not found. (\"capr.pl -h\" gives help)\n"
@@ -76,7 +75,7 @@ print "Using $opt_d\n\n";
# Print a list of record types
if ($opt_r) {
print ("Record types found:\n");
printList(0);
printList($opt_l);
exit;
}
@@ -100,7 +99,7 @@ if (@ARGV) {
} else {
# Drop any ".FIELD" part
s/\. \w+ $//x;
printRecord($_, 0);
printRecord($_, $opt_l);
}
}
@@ -130,9 +129,11 @@ sub parseDbd {
my $thisRecord;
my $thisField;
my $thisType;
my $thisSize = 0;
my $field = {};
my $interest = 0;
my $thisBase = 'DECIMAL';
my $special = '';
while (@dbd) {
$_ = shift @dbd;
@@ -149,35 +150,47 @@ sub parseDbd {
$thisField = $1;
$thisType = $2;
$isAfield = 1;
$thisSize = 1024 if $thisType =~ m/^ DBF_(IN|OUT|FWD)LINK $/x;
}
elsif ( m/interest \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$interest = $1;
}
elsif ( m/size \s* \( \s* ([0-9]+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$thisSize = $1;
}
elsif ( m/special \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$special = $1;
}
elsif ( m/base \s* \( \s* (\w+) \s* \)/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 2 && $isAfield;
$thisBase = $1;
}
elsif ( m/device \s* \( (\w+) \s* ,/x ) {
die "File format error at line $i of file\n $opt_d\n"
unless $level == 0;
$device{$1}++;
}
if ( m/\{/ ) {
$level++;
}
if ( m/\}/ ) {
if ($level == 2 && $isAfield) {
my $params = [];
$params->[$iIdx] = $interest;
$params->[$tIdx] = $thisType;
$params->[$bIdx] = $thisBase;
my $params = {};
$params->{interest} = $interest;
$params->{dbfType} = $thisType;
$params->{base} = $thisBase;
$params->{special} = $special;
$params->{size} = $thisSize;
$field->{$thisField} = $params;
# Reset default values
$isAfield = 0;
$interest = 0; # reset default
$thisBase = 'DECIMAL'; # reset default
$interest = 0;
$thisBase = 'DECIMAL';
$special = '';
$thisSize = 0;
}
elsif ($level == 1 && $isArecord) {
$isArecord = 0;
@@ -207,21 +220,23 @@ sub getRecType {
# Given the record type and field, returns the interest level, data type
# and number base for the field
# Usage: ($dataType, $interest, $base) = getFieldParams($recType, $field);
# Usage: ($dataType, $interest, $base, $special, $size) = getFieldParams($recType, $field);
sub getFieldParams {
my ($recType, $field) = @_;
my $params = $record{$recType}{$field} or
die "Can't find params for $recType.$field";
exists($fieldType{$params->[$tIdx]}) ||
exists($fieldType{$params->{dbfType}}) ||
die "Field data type $field for $recType not found in dbd file --";
exists($params->[$iIdx]) ||
exists($params->{interest}) ||
die "Interest level for $field in $recType not found in dbd file --";
my $fType = $fieldType{$params->[$tIdx]};
my $fInterest = $params->[$iIdx];
my $fBase = $params->[$bIdx];
return ($fType, $fInterest, $fBase);
my $fType = $fieldType{$params->{dbfType}};
my $fInterest = $params->{interest};
my $fBase = $params->{base};
my $fSpecial = $params->{special};
my $fSize = $params->{size};
return ($fType, $fInterest, $fBase, $fSpecial, $fSize);
}
# Prints field name and data for given field. Formats output so
@@ -233,27 +248,37 @@ sub printField {
my $screenWidth = 80;
my ($outStr, $wide);
my $field = "$fieldName:";
if ( $dataType eq 'DBF_STRING' ) {
$outStr = sprintf('%-5s %s', $field, $fieldData);
} elsif ( $base eq 'HEX' ) {
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
$outStr = sprintf('%-5s 0x%x', $field, $val);
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
} elsif ( $dataType eq 'DBF_CHAR' ) {
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
} else {
# DBF_INT64, DBF_LONG, DBF_SHORT,
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
$outStr = sprintf('%-5s %d', $field, $fieldData);
if (ref $fieldData eq 'ARRAY') {
my $elems = scalar @{$fieldData};
my $field = "$fieldName\[$elems\]:";
my $count = $elems > $opt_n ? $opt_n : $elems;
my @show = @{$fieldData}[0 .. $count - 1];
$outStr = sprintf('%-5s %s', $field, join(', ', @show));
$outStr .= ", ..." if $elems > $count;
}
else {
my $field = "$fieldName:";
if ( $dataType eq 'DBF_STRING' ) {
$outStr = sprintf('%-5s %s', $field, $fieldData);
} elsif ( $base eq 'HEX' ) {
my $val = ( $dataType eq 'DBF_CHAR' ) ? ord($fieldData) : $fieldData;
$outStr = sprintf('%-5s 0x%x', $field, $val);
} elsif ( $dataType eq 'DBF_DOUBLE' || $dataType eq 'DBF_FLOAT' ) {
$outStr = sprintf('%-5s %.8f', $field, $fieldData);
} elsif ( $dataType eq 'DBF_UCHAR' ) {
$outStr = sprintf('%-5s %d', $field, ord($fieldData));
} else {
# DBF_INT64, DBF_LONG, DBF_SHORT,
# DBF_UINT64, DBF_ULONG, DBF_USHORT, DBF_UCHAR,
$outStr = sprintf('%-5s %d', $field, $fieldData);
}
}
my $len = length($outStr);
if ($len <= 20) { $wide = 20; }
elsif ( $len <= 40 ) { $wide = 40; }
elsif ( $len <= 60 ) { $wide = 60; }
if ($len < 20) { $wide = 20; }
elsif ( $len < 40 ) { $wide = 40; }
elsif ( $len < 60 ) { $wide = 60; }
else { $wide = 80;}
my $pad = $wide - $len;
@@ -269,49 +294,64 @@ sub printField {
return $col;
}
# Query for a list of fields simultaneously.
# The results are filled in the the %callback_data global hash
# and the result of the operation is the number of read pvs
# Query the native values of a list of PVs simultaneously.
# The data is returned in the the %callback_data global hash.
# The return value is the number of read pvs
#
# NOTE: Not re-entrant because results are written to global hash
# %callback_data
#
# Usage: $fields_read = caget( @pvlist )
sub caget {
my @chans = map { CA->new($_); } @_;
#clear any previous results;
%connected = ();
$unconnected_count = scalar @_;
%callback_data = ();
%timed_out = ();
$callback_incomplete = 0;
eval { CA->pend_io($opt_w); };
if ($@) {
if ($@ =~ m/^ECA_TIMEOUT/) {
my $name = $chans[0]->name;
my $err = (@chans > 1) ? 'some fields' : "'$name'";
print "Channel connect timed out: $err not found.\n";
foreach my $chan (@chans) {
$timed_out{$chan->name} = !$chan->is_connected;
}
@chans = grep { $_->is_connected } @chans;
} else {
die $@;
}
}
my @chans = map {
print " Creating channel for $_\n" if $opt_D;
CA->new($_, \&canew_callback);
} @_;
my $channel_count = scalar @chans;
return 0 unless $channel_count gt 0;
map {
$_->get_callback(\&caget_callback, $_->field_type);
} @chans;
print " $channel_count channels created.\n" if $opt_D;
my $fields_read = $callback_incomplete = @chans;
CA->pend_event(0.1)
while $callback_incomplete;
return $fields_read;
my $elapsed = 0;
do {
print " Waiting for $unconnected_count channels to connect\n"
if $unconnected_count && $opt_D;
print " Waiting for data from $callback_incomplete channels\n"
if $callback_incomplete && $opt_D;
CA->pend_event(0.1);
$elapsed += 0.1;
} until (($elapsed > $opt_w) or
(scalar %connected && $callback_incomplete == 0));
my $data_count = scalar keys %callback_data;
printf " Got data from %d of %d channels\n", $data_count, $channel_count
if $opt_D;
return $data_count;
}
sub canew_callback {
my ($chan, $up) = @_;
return unless $up;
$connected{$chan->name} = $chan;
$unconnected_count--;
my $ftype = $chan->field_type;
my $count = $chan->element_count;
$ftype = 'DBR_LONG' if $ftype eq 'DBR_CHAR' && $count == 1;
print " Getting ${\$chan->name} as $ftype\n" if $opt_D;
# We have to fetch all elements so we can show how many there are
$chan->get_callback(\&caget_callback, $ftype);
$callback_incomplete++;
}
sub caget_callback {
my ($chan, $status, $data) = @_;
die $status if $status;
print " Got ${\$chan->name} = '$data'\n" if $opt_D;
$callback_data{$chan->name} = $data;
$callback_incomplete--;
}
@@ -333,69 +373,83 @@ sub printRecord {
my @ftypes = (); #types, from parser
my @bases = (); #bases, from parser
foreach my $field (sort keys %{$record{$recType}}) {
# Skip DTYP field if this rec type doesn't have device support defined
next if $field eq 'DTYP' && !exists($device{$recType});
my ($fType, $fInterest, $base) = getFieldParams($recType, $field);
# FIXME: Support waveform.VAL fields etc.
unless( $fType eq 'DBF_NOACCESS' ) {
if ($interest >= $fInterest ) {
my $fToGet = "$name.$field";
push @fields_pr, $field;
push @readlist, $fToGet;
push @ftypes, $fType;
push @bases, $base;
}
my ($fType, $fInterest, $base, $special, $size) =
getFieldParams($recType, $field);
next if $fInterest > $interest;
my $fToGet = "$name.$field";
if ($fType eq 'DBF_NOACCESS') {
next unless $special eq 'SPC_DBADDR';
$fType = 'DBF_STRING';
}
elsif ($fType eq 'DBF_STRING' && $size >= 40) {
$fToGet .= '$';
}
push @fields_pr, $field;
push @readlist, $fToGet;
push @ftypes, $fType;
push @bases, $base;
}
my $fields_read = caget( @readlist );
my @missing;
# print while iterating over lists gathered
my $col = 0;
for (my $i=0; $i < scalar @readlist; $i++) {
my $field = $fields_pr[$i];
my $fToGet = $readlist[$i];
my ($fType, $data, $base);
next if $timed_out{$fToGet};
push @missing, $field unless exists $callback_data{$fToGet};
next unless exists $callback_data{$fToGet};
$fType = $ftypes[$i];
$base = $bases[$i];
$data = $callback_data{$fToGet};
$col = printField($field, $data, $fType, $base, $col);
}
print("\n"); # Final newline
printf "\nUnreadable fields: %s\n", join(', ', @missing) if @missing && $opt_D;
}
# Prints list of record types found in dbd file. If level > 0
# then the fields of that record type, their interest levels and types are
# also printed.
# Diagnostic routine, usage: void printList(level);
# then uses printRecordList to display all fields in each record type.
sub printList {
my $level = shift;
foreach my $rkey (sort keys(%record)) {
print(" $rkey\n");
if ($level > 0) {
foreach my $fkey (keys %{$record{$rkey}}) {
print("\tField $fkey - interest $record{$rkey}{$fkey}[$iIdx] ");
print("- type $record{$rkey}{$fkey}[$tIdx] ");
print("- base $record{$rkey}{$fkey}[$bIdx]\n");
}
printRecordList($rkey);
}
else {
print(" $rkey\n");
}
}
}
# Prints list of fields with interest levels for given record type
# Diagnostic routine, usage: void printRecordList("recordType");
# Prints list of fields and metadata for given record type
sub printRecordList {
my $type = shift;
if (exists($record{$type}) ) {
print("Record type - $type\n");
foreach my $fkey (sort keys %{$record{$type}}) {
printf('%-8s', $fkey);
printf(" interest = $record{$type}{$fkey}[$iIdx]");
printf(" type = %-12s ",$record{$type}{$fkey}[$tIdx]);
print (" base = $record{$type}{$fkey}[$bIdx]\n");
my $param = $record{$type}{$fkey};
my $dbfType = $param->{dbfType};
printf " %-8s", $fkey;
printf " interest = %d", $param->{interest};
printf " type = %-12s", $dbfType;
if ($dbfType eq 'DBF_STRING') {
printf " size = %s\n", $param->{size};
}
elsif ($dbfType =~ m/DBF_U?(CHAR|SHORT|INT|LONG|INT64)/) {
printf " base = %s\n", $param->{base};
}
elsif ($dbfType eq 'DBF_NOACCESS') {
printf " special = %s\n", $param->{special};
}
else {
print "\n";
}
}
}
else {
@@ -411,16 +465,20 @@ sub HELP_MESSAGE {
" capr.pl [options] <record name> [<interest>]\n",
"\n",
" -h Print this help message.\n",
" -D Print debug messages.\n",
"Channel Access options:\n",
" -w <sec>: Wait time, specifies CA timeout, default is $opt_w second\n",
"Database Definitions:\n",
" -d <file.dbd>: The file containing record type definitions.\n",
" This can be set using the EPICS_CAPR_DBD_FILE environment variable.\n",
" Default: ", AbsPath($opt_d), "\n",
" Default: ", abs_path($opt_d), "\n",
"Output Options:\n",
" -r Lists all record types in the selected dbd file.\n",
" -f <record type>: Lists all fields with their interest level, data type\n",
" and number base for the given record_type.\n",
" -f <record type>: Lists all fields with interest level, data type\n",
" and other information for the given record_type.\n",
" -l <interest>: interest level\n",
" -n <elems>: Maximum number of array elements to display\n",
" Default: $opt_n\n",
"\n",
"Base version: ", CA->version, "\n";
exit 1;

View File

@@ -241,7 +241,7 @@ void asCaStart(void)
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)asCaTask,0);
if(threadid==0) {
errMessage(0,"asCaStart: taskSpawn Failure\n");
errMessage(0,"asCaStart: taskSpawn Failure");
}
}
epicsMutexMustLock(asCaTaskLock);

View File

@@ -16,7 +16,7 @@
#include "asIocRegister.h"
/* asSetFilename */
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgString};
static const iocshArg asSetFilenameArg0 = { "ascf",iocshArgStringPath};
static const iocshArg * const asSetFilenameArgs[] = {&asSetFilenameArg0};
static const iocshFuncDef asSetFilenameFuncDef =
{"asSetFilename",1,asSetFilenameArgs,
@@ -97,7 +97,7 @@ static void aspmemCallFunc(const iocshArgBuf *args)
}
/* astac */
static const iocshArg astacArg0 = { "recordname",iocshArgString};
static const iocshArg astacArg0 = { "recordname",iocshArgStringRecord};
static const iocshArg astacArg1 = { "user",iocshArgString};
static const iocshArg astacArg2 = { "host",iocshArgString};
static const iocshArg * const astacArgs[] = {&astacArg0,&astacArg1,&astacArg2};

View File

@@ -11,5 +11,6 @@
# This is a Makefile fragment, see src/ioc/Makefile.
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
$(addprefix $(COMMON_DIR)/,$(BPT_DBD)) : $(COMMON_DIR)/bpt%.dbd : \
$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)
# Don't try to use $(MAKEBPT) above

View File

@@ -13,13 +13,15 @@
THESE_RULES := $(IOCDIR)/db/RULES
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
$(DBDTORECTYPEH_dep)
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -I $(COMMON_DIR) -o $(COMMONDEP_TARGET) $< > $@
$(COMMON_DIR)/dbCommonRecord.html: ../db/dbCommon.dbd.pod
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES) \
$(DBDTORECTYPEH_dep)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) -I ../db -I $(COMMON_DIR) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@

View File

@@ -58,6 +58,7 @@ typedef struct cbQueueSet {
int shutdown; // use atomic
int threadsConfigured;
int threadsRunning;
epicsThreadId *threads;
} cbQueueSet;
static cbQueueSet callbackQueue[NUM_CALLBACK_PRIORITIES];
@@ -242,11 +243,15 @@ void callbackStop(void)
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
cbQueueSet *mySet = &callbackQueue[i];
int j;
while (epicsAtomicGetIntT(&mySet->threadsRunning)) {
epicsEventSignal(mySet->semWakeUp);
epicsEventWaitWithTimeout(startStopEvent, 0.1);
}
for(j=0; j<mySet->threadsConfigured; j++) {
epicsThreadMustJoin(mySet->threads[j]);
}
}
}
@@ -266,6 +271,8 @@ void callbackCleanup(void)
mySet->semWakeUp = NULL;
epicsRingPointerDelete(mySet->queue);
mySet->queue = NULL;
free(mySet->threads);
mySet->threads = NULL;
}
epicsTimerQueueRelease(timerQueue);
@@ -297,17 +304,25 @@ void callbackInit(void)
cantProceed("epicsRingPointerLockedCreate failed for %s\n",
threadNamePrefix[i]);
callbackQueue[i].queueOverflow = FALSE;
if (callbackQueue[i].threadsConfigured == 0)
callbackQueue[i].threadsConfigured = callbackThreadsDefault;
callbackQueue[i].threads = callocMustSucceed(callbackQueue[i].threadsConfigured,
sizeof(*callbackQueue[i].threads),
"callbackInit");
for (j = 0; j < callbackQueue[i].threadsConfigured; j++) {
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = threadPriority[i];
opts.stackSize = epicsThreadStackBig;
if (callbackQueue[i].threadsConfigured > 1 )
sprintf(threadName, "%s-%d", threadNamePrefix[i], j);
else
strcpy(threadName, threadNamePrefix[i]);
tid = epicsThreadCreate(threadName, threadPriority[i],
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC)callbackTask, &priorityValue[i]);
callbackQueue[i].threads[j] = tid = epicsThreadCreateOpt(threadName,
(EPICSTHREADFUNC)callbackTask, &priorityValue[i], &opts);
if (tid == 0) {
cantProceed("Failed to spawn callback thread %s\n", threadName);
} else {

View File

@@ -73,7 +73,7 @@ epicsExportAddress(int, dbAccessDebugPUTF);
DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL;
static short mapDBFToDBR[DBF_NTYPES] = {
static const short mapDBFToDBR[DBF_NTYPES] = {
/* DBF_STRING => */ DBR_STRING,
/* DBF_CHAR => */ DBR_CHAR,
/* DBF_UCHAR => */ DBR_UCHAR,

View File

@@ -220,6 +220,8 @@ DBCORE_API long dbNameToAddr(const char *pname, struct dbAddr *paddr);
/** Initialize DBADDR from a dbEntry
* Also handles SPC_DBADDR processing. This is really an internal
* routine for use by dbNameToAddr() and dbChannelCreate().
*
* \since 7.0.2.1
*/
DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
struct dbAddr *paddr);
@@ -227,6 +229,8 @@ DBCORE_API long dbEntryToAddr(const struct dbEntry *pdbentry,
/** Initialize DBENTRY from a valid dbAddr*
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias().
*
* \since 3.16.1
*/
DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
struct dbEntry *pdbentry);
@@ -234,6 +238,8 @@ DBCORE_API void dbInitEntryFromAddr(struct dbAddr *paddr,
/** Initialize DBENTRY from a valid record (dbCommon*)
* Constant time equivalent of dbInitEntry() then dbFindRecord(),
* and finally dbFollowAlias() when no field is specified.
*
* \since 3.16.1
*/
DBCORE_API void dbInitEntryFromRecord(struct dbCommon *prec,
struct dbEntry *pdbentry);

View File

@@ -9,14 +9,22 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Andrew Johnson <anj@aps.anl.gov>
* Ralph Lange <Ralph.Lange@bessy.de>
*/
#ifndef INC_dbChannel_H
#define INC_dbChannel_H
/** \file dbChannel.h
*
* \author Andrew Johnson (ANL)
* \author Ralph Lange (BESSY)
*
* \brief The dbChannel API gives access to record fields.
*
* The dbChannel API is used internally by the IOC and by link types, device
* support and IOC servers (RSRV and QSRV) to access record fields, either
* directly or through one or more server-side filters as specified in the
* channel name used when creating the channel.
*/
#include "dbDefs.h"
#include "dbAddr.h"
#include "ellLib.h"
@@ -30,200 +38,531 @@
extern "C" {
#endif
/*
/**
* event subscription
*/
typedef struct evSubscrip {
ELLNODE node;
struct dbChannel *chan;
EVENTFUNC *user_sub;
void *user_arg;
struct event_que *ev_que;
db_field_log **pLastLog;
unsigned long npend; /* n times this event is on the queue */
unsigned long nreplace; /* n times replacing event on the queue */
unsigned char select;
char useValque;
char callBackInProgress;
char enabled;
ELLNODE node;
struct dbChannel * chan;
EVENTFUNC * user_sub;
void * user_arg;
struct event_que * ev_que;
db_field_log ** pLastLog;
unsigned long npend; /**< n times this event is on the queue */
unsigned long nreplace; /**< n times replacing event on the queue */
unsigned char select;
char useValque;
char callBackInProgress;
char enabled;
} evSubscrip;
typedef struct chFilter chFilter;
/* A dbChannel points to a record field, and can have multiple filters */
/** \brief A Database Channel object
*
* A dbChannel is created from a user-supplied channel name, and holds
* pointers to the record & field and information about any filters that
* were specified with it. The dbChannel macros defined in this header
* file should always be used to read data from a dbChannel object, the
* internal implementation may change without notice.
*/
typedef struct dbChannel {
const char *name;
dbAddr addr; /* address structure for record/field */
long final_no_elements; /* final number of elements (arrays) */
short final_field_size; /* final size of element */
short final_type; /* final type of database field */
ELLLIST filters; /* list of filters as created from JSON */
ELLLIST pre_chain; /* list of filters to be called pre-event-queue */
ELLLIST post_chain; /* list of filters to be called post-event-queue */
const char *name; /**< Channel name */
dbAddr addr; /**< Pointers to record & field */
long final_no_elements; /**< Final number of array elements */
short final_field_size; /**< Final size of each element */
short final_type; /**< Final type of database field */
ELLLIST filters; /**< Filters used by dbChannel */
ELLLIST pre_chain; /**< Filters on pre-event-queue chain */
ELLLIST post_chain; /**< Filters on post-event-queue chain */
} dbChannel;
/* Prototype for the channel event function that is called in filter stacks
/** \brief Event filter function type
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
* Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data,
* as this indicates the data is still owned by the record.
* Prototype for channel event filter functions.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
* then return NULL.
* When these functions are called the scan lock for the record associated
* with \p chan _may_ already be locked, but they must use dbfl_has_copy()
* to determine whether the data in \p pLog belongs to the record. If that
* returns 0 the function must call dbScanLock() before accessing the data.
*
* A filter function owns the field log \p pLog when called. To discard an
* update it should free the field log using db_delete_field_log() and
* return NULL.
*/
typedef db_field_log* (chPostEventFunc)(void *pvt, dbChannel *chan, db_field_log *pLog);
/* Return values from chFilterIf->parse_* routines: */
/** \brief Result returned by chFilterIf parse routines.
*
* The parsing functions from a chFilterIf must return either \p parse_stop
* (in event of an error) or \p parse_continue.
*/
typedef enum {
parse_stop, parse_continue
} parse_result;
/* These routines must be implemented by each filter plug-in */
/** \brief Channel Filter Interface
*
* Routines to be implemented by each Channel Filter.
*/
typedef struct chFilterIf {
/* cleanup pointer passed to dbRegisterFilter().
* Called during DB shutdown
/** \brief Release private filter data.
*
* Called during database shutdown to release resources allocated by
* the filter.
* \param puser The user-pointer passed into dbRegisterFilter().
*/
void (* priv_free)(void *puser);
/* Parsing event handlers: */
parse_result (* parse_start)(chFilter *filter);
/* If parse_start() returns parse_continue for a filter, one of
/** \name Parsing event handlers
*
* A filter that doesn't accept a particular JSON value type may use a
* \p NULL pointer to the parsing handler for that value type, which is
* equivalent to a routine that always returns \p parse_stop.
*/
/** \brief Create new filter instance.
*
* Called when a new filter instance is requested. Filter may allocate
* resources for this instance and store in \p filter->puser.
* If parse_start() returns \p parse_continue for a filter, one of
* parse_abort() or parse_end() will later be called for that same
* filter.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start)(chFilter *filter);
/** \brief Parsing of filter instance is being cancelled.
*
* This function should release any memory allocated for the given
* \p filter instance; no further parsing handlers will be called for it.
* \param filter Pointer to instance data.
*/
void (* parse_abort)(chFilter *filter);
/* If parse_abort() is called it should release any memory allocated
* for this filter; no further parse_...() calls will be made;
/** \brief Parsing of filter instance has completed successfully.
*
* The parser has reached the end of this instance and no further parsing
* handlers will be called for it. The filter must check the instance
* data and indicate whether it was complete or not.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end)(chFilter *filter);
/* If parse_end() returns parse_stop it should have released any
* memory allocated for this filter; no further parse_...() calls will
* be made in this case.
/** \brief Parser saw \p null value.
*
* Optional.
* Null values are rarely accepted by channel filters.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_null)(chFilter *filter);
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
parse_result (* parse_integer)(chFilter *filter, long integerVal);
parse_result (* parse_double)(chFilter *filter, double doubleVal);
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
size_t stringLen); /* NB: stringVal is not zero-terminated: */
/** \brief Parser saw boolean value.
*
* Optional.
* \param filter Pointer to instance data.
* \param boolVal true/false Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
/** \brief Parser saw integer value.
*
* Optional.
* \param filter Pointer to instance data.
* \param integerVal Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_integer)(chFilter *filter, long integerVal);
/** \brief Parser saw double value.
*
* Optional.
* \param filter Pointer to instance data.
* \param doubleVal Value.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_double)(chFilter *filter, double doubleVal);
/** \brief Parser saw string value.
*
* Optional.
* \param filter Pointer to instance data.
* \param stringVal Value, not zero-terminated.
* \param stringLen Number of chars in \p stringVal.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
size_t stringLen);
/** \brief Parser saw start of a JSON map value.
*
* Optional.
* Inside a JSON map all data consists of key/value pairs.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start_map)(chFilter *filter);
/** \brief Parser saw a JSON map key.
*
* Optional.
* \param filter Pointer to instance data.
* \param key Value not zero-terminated.
* \param stringLen Number of chars in \p key
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_map_key)(chFilter *filter, const char *key,
size_t stringLen); /* NB: key is not zero-terminated: */
size_t stringLen);
/** \brief Parser saw end of a JSON map value.
*
* Optional.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end_map)(chFilter *filter);
/** \brief Parser saw start of a JSON array value.
*
* Optional.
* Data inside a JSON array doesn't have to be all of the same type.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_start_array)(chFilter *filter);
/** \brief Parser saw end of a JSON array value.
*
* Optional.
* \param filter Pointer to instance data.
* \returns \p parse_stop on error, or \p parse_continue
*/
parse_result (* parse_end_array)(chFilter *filter);
/* Channel operations: */
/** \name Channel operations */
/** \brief Open filter on channel.
*
* Optional, initialize instance.
* \param filter Pointer to instance data.
* \returns 0, or an error status value.
*/
long (* channel_open)(chFilter *filter);
void (* channel_register_pre) (chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_register_post)(chFilter *filter, chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
void (* channel_report)(chFilter *filter, int level, const unsigned short indent);
/** \brief Get pre-chain filter function.
*
* Optional.
* Returns pre-chain filter function and context.
* \param[in] filter Pointer to instance data.
* \param[out] cb_out Write filter function pointer here.
* \param[out] arg_out Write private data pointer here.
* \param[in,out] probe db_field_log with metadata for adjusting.
*/
void (* channel_register_pre) (chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
/** \brief Get post-chain filter function.
*
* Optional, return post-chain filter function and context.
* \param[in] filter Pointer to instance data.
* \param[out] cb_out Write filter function pointer here.
* \param[out] arg_out Write private data pointer here.
* \param[in,out] probe db_field_log with metadata for adjusting.
*/
void (* channel_register_post)(chFilter *filter,
chPostEventFunc **cb_out, void **arg_out, db_field_log *probe);
/** \brief Print information about filter to stdout.
*
* Optional.
* \param filter Pointer to instance data.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
void (* channel_report)(chFilter *filter,
int level, const unsigned short indent);
/** \brief Close filter.
*
* Optional, releases resources allocated for this instance.
* \param filter Pointer to instance data.
*/
void (* channel_close)(chFilter *filter);
} chFilterIf;
/* A chFilterPlugin holds data for a filter plugin */
/** \brief Filter plugin data
*
* A chFilterPlugin object holds data about a filter plugin.
*/
typedef struct chFilterPlugin {
ELLNODE node;
const char *name;
const chFilterIf *fif;
void *puser;
ELLNODE node; /**< \brief List node (dbBase->filterList) */
const char *name; /**< \brief Filter name */
const chFilterIf *fif; /**< \brief Filter interface routines */
void *puser; /**< \brief For use by the plugin */
} chFilterPlugin;
/* A chFilter holds data for a single filter instance */
/** \brief Filter instance data
*
* A chFilter holds data about a single filter instance.
*/
struct chFilter {
ELLNODE list_node;
ELLNODE pre_node;
ELLNODE post_node;
dbChannel *chan;
const chFilterPlugin *plug;
chPostEventFunc *pre_func;
void *pre_arg;
chPostEventFunc *post_func;
void *post_arg;
void *puser;
ELLNODE list_node; /**< \brief List node (dbChannel->filters) */
ELLNODE pre_node; /**< \brief List node (dbChannel->pre_chain) */
ELLNODE post_node; /**< \brief List node (dbChannel->post_chain) */
dbChannel *chan; /**< \brief The dbChannel we belong to */
const chFilterPlugin *plug; /**< \brief The plugin that created us */
chPostEventFunc *pre_func; /**< \brief pre-chain filter function */
void *pre_arg; /**< \brief pre-chain context pointer */
chPostEventFunc *post_func; /**< \brief post-chain filter function */
void *post_arg; /**< \brief post-chain context pointer */
void *puser; /**< \brief For use by the plugin */
};
struct dbCommon;
struct dbFldDes;
DBCORE_API void dbChannelInit (void);
/** \brief Initialize the dbChannel subsystem. */
DBCORE_API void dbChannelInit(void);
/** \brief Cleanup the dbChannel subsystem. */
DBCORE_API void dbChannelExit(void);
/** \brief Test the given PV name for existance.
*
* This routine looks up the given record and field name, but does not check
* whether any field modifiers given after the field name are correct.
* This is sufficient for the correct server to quickly direct searches to the
* IOC that owns that PV name. Field modifiers will be checked when
* dbChannelCreate() is later called with the same name.
* \param name Channel name.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelTest(const char *name);
/** \brief Create a dbChannel object for the given PV name.
*
* \param name Channel name.
* \return Pointer to dbChannel object, or NULL if invalid.
*/
DBCORE_API dbChannel * dbChannelCreate(const char *name);
/** \brief Open a dbChannel for doing I/O.
*
* \param chan Pointer to the dbChannel object.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelOpen(dbChannel *chan);
/*Following is also defined in db_convert.h*/
/** \brief Request (DBR) type conversion array.
*
* This converter array is declared in db_convert.h but redeclared
* here as it is needed by the dbChannel...CAType macros defined here.
*/
DBCORE_API extern unsigned short dbDBRnewToDBRold[];
/* In the following macros pChan is dbChannel* */
/** \name dbChannel Inspection Macros */
/* evaluates to const char* */
/** \brief Name that defined the channel.
*
* \param pChan Pointer to the dbChannel object.
* \returns const char*
*/
#define dbChannelName(pChan) ((pChan)->name)
/* evaluates to struct dbCommon* */
/** \brief Record the channel connects to.
*
* \param pChan Pointer to the dbChannel object.
* \returns struct dbCommon*
*/
#define dbChannelRecord(pChan) ((pChan)->addr.precord)
/* evaluates to struct dbFldDes* */
/** \brief Field descriptor for the field pointed to.
*
* \param pChan Pointer to the dbChannel object.
* \returns struct dbFldDes*
*/
#define dbChannelFldDes(pChan) ((pChan)->addr.pfldDes)
/* evaluates to long */
/** \brief Number of array elements in the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns long
*/
#define dbChannelElements(pChan) ((pChan)->addr.no_elements)
/* evaluates to short */
/** \brief Data type (DBF type) of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFieldType(pChan) ((pChan)->addr.field_type)
/* evaluates to short */
/** \brief Request type (DBR type) of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelExportType(pChan) ((pChan)->addr.dbr_field_type)
/* evaluates to short */
/** \brief CA data type of the field.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelExportCAType(pChan) (dbDBRnewToDBRold[dbChannelExportType(pChan)])
/* evaluates to short */
/** \brief Field (element if array) size in bytes.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFieldSize(pChan) ((pChan)->addr.field_size)
/* evaluates to long */
/** \brief Array length after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns long
*/
#define dbChannelFinalElements(pChan) ((pChan)->final_no_elements)
/* evaluates to short */
/** \brief Data type after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFinalFieldType(pChan) ((pChan)->final_type)
/* evaluates to short */
/** \brief Channel CA data type after filtering.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelFinalCAType(pChan) (dbDBRnewToDBRold[(pChan)->final_type])
/* evaluates to short */
/** \brief Field/element size after filtering, in bytes.
*
* \param pChan Pointer to the dbChannel object.
* \returns short */
#define dbChannelFinalFieldSize(pChan) ((pChan)->final_field_size)
/* evaluates to short */
/** \brief Field special attribute.
*
* \param pChan Pointer to the dbChannel object.
* \returns short
*/
#define dbChannelSpecial(pChan) ((pChan)->addr.special)
/* Channel filters do not get to interpose here since there are many
/** \brief Pointer to the record field.
*
* Channel filters do not get to interpose here since there are many
* places where the field pointer is compared with the address of a
* specific record field, so they can't modify the pointer value.
* \param pChan Pointer to the dbChannel object.
* \returns void *
*/
/* evaluates to void* */
#define dbChannelField(pChan) ((pChan)->addr.pfield)
/** \name dbChannel Operation Functions */
/** \brief dbGet() through a dbChannel.
*
* Calls dbGet() for the field that \p chan refers to.
* Only call this routine if the record is already locked.
* \param[in] chan Pointer to the dbChannel object.
* \param[in] type Request type from dbFldTypes.h.
* \param[out] pbuffer Pointer to data buffer.
* \param[in,out] options Request options from dbAccessDefs.h.
* \param[in,out] nRequest Pointer to the element count.
* \param[in] pfl Pointer to a db_field_log or NULL.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelGet(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
/** \brief dbGetField() through a dbChannel.
*
* Get values from a PV through a channel.
* This routine locks the record, calls
* dbChannelGet(), then unlocks the record again.
* \param[in] chan Pointer to the dbChannel object.
* \param[in] type Request type from dbFldTypes.h.
* \param[out] pbuffer Pointer to data buffer.
* \param[in,out] options Request options from dbAccessDefs.h.
* \param[in,out] nRequest Pointer to the element count.
* \param[in] pfl Pointer to a db_field_log or NULL.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
/** \brief dbPut() through a dbChannel.
*
* Put values to a PV through a channel. Only call this routine if the
* record is already locked.
* Calls dbPut() for the field that \p chan refers to.
* \param chan[in] Pointer to the dbChannel object.
* \param type[in] Request type from dbFldTypes.h.
* \param pbuffer[in] Pointer to data buffer.
* \param nRequest[in] Number of elements in pbuffer.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelPut(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
/** \brief dbPutField() through a dbChannel.
*
* Put values to a PV through a channel.
* This routine calls dbPutField() for the field that \p chan refers to.
* \param chan[in] Pointer to the dbChannel object.
* \param type[in] Request type from dbFldTypes.h.
* \param pbuffer[in] Pointer to data buffer.
* \param nRequest[in] Number of elements in pbuffer.
* \returns 0, or an error status value.
*/
DBCORE_API long dbChannelPutField(dbChannel *chan, short type,
const void *pbuffer, long nRequest);
/** \brief Print report on a channel.
*
* Print information about the channel to stdout.
* \param chan Pointer to the dbChannel object.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
DBCORE_API void dbChannelShow(dbChannel *chan, int level,
const unsigned short indent);
/** \brief Print report on a channel's filters.
*
* Print information about the channel's filters to stdout.
* \param chan Pointer to the dbChannel object.
* \param level Higher levels may provide more detail.
* \param indent Indent all lines by this many spaces.
*/
DBCORE_API void dbChannelFilterShow(dbChannel *chan, int level,
const unsigned short indent);
/** \brief Delete a channel.
*
* Releases resources owned by this channel and its filters.
* \param chan Pointer to the dbChannel object.
*/
DBCORE_API void dbChannelDelete(dbChannel *chan);
DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *puser);
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
/** \name Other routines */
DBCORE_API void dbRegisterFilter(const char *key,
const chFilterIf *fif, void *puser);
DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan,
db_field_log *pLogIn);
DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan,
db_field_log *pLogIn);
DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len);
DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan,
void **pfield, long *no_elements, long *offset);

View File

@@ -230,6 +230,8 @@ The B<SPVT> field is for internal use by the scanning system.
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
promptgroup("10 - Common")
interest(1)
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
@@ -456,9 +458,10 @@ record. If left empty, the record is placed in group C<DEFAULT>.
The B<ASP> field is private for use by the access security system.
The B<DISP> field controls whether puts from outside the IOC are allowed to
modify the fields of this record at all. If the field is set to TRUE all puts
directed to this record are ignored, except for puts to the field DISP itself.
The B<DISP> field can be set to a non-zero value to reject puts from outside of
the IOC (i.e. via Channel Access or PV Access) to any field of the record other
than to the DISP field itself. Field changes and record processing can still be
instigated from inside the IOC using DB links and the IOC scan mechanisms.
The B<DTYP> field specifies the device type for the record. Most record types
have their own set of device types which are specified in the IOC's database
@@ -489,17 +492,37 @@ The B<TIME> field holds the time stamp when this record was last processed.
The B<UTAG> field can be used to hold a site-specific 64-bit User Tag value
that is associated with the record's time stamp.
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
call get time as before '-1' - call the time stamp driver and use the best
source available. '-2' - the device support sets the time stamp and optional
user tag from the hardware. Values between 1-255 request the time of the last
occurance of a generalTime event.
The B<TSE> field value indicates the mechanism to use to get the time stamp:
=over
=item *
C< 0> E<mdash> Get the current time as normal
=item *
C<-1> E<mdash> Ask the time stamp driver for its best source of the current time, if
available.
=item *
C<-2> E<mdash> Device support sets the time stamp and the optional User Tag from the
hardware.
=item *
Positive values (normally between 1-255) get the time of the last occurance of
the numbered generalTime event.
=back
The B<TSEL> field contains an input link for obtaining the time stamp. If this
link points to the TIME field of a record then the time stamp and user tag of
link points to the TIME field of a record then the time stamp and User Tag of
that record are copied directly into this record (Channel Access links can only
copy the time stamp). If the link points to any other field, that field's value
is read and stored in the TSE field which is then used to acquire a time stamp.
copy the time stamp, not the User Tag). If the link points to any other field,
that field's value is read and stored in the TSE field which is then used to
provide the time stamp as described above.
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, UTAG, TSE, TSEL

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Input Record Types
=title Fields Common to Input Record Types
This section describes fields that are found in many input record types.
These fields usually have the same meaning whenever they are used.
@@ -206,3 +206,5 @@ If SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back
=cut

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Output Record Types
=title Fields Common to Output Record Types
This section describes fields that are found in many output record types.
These fields usually have the same meaning whenever they are used.
@@ -237,3 +237,5 @@ If SIMM is not YES or NO, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back
=cut

View File

@@ -3,7 +3,7 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to All Record Types
=title Fields Common to All Record Types
This section contains a description of the fields that are common to all record
types. These fields are defined in dbCommon.dbd.

View File

@@ -27,6 +27,7 @@
#include "dbFldTypes.h"
#include "dbLink.h"
#include "link.h"
#include "errlog.h"
/**************************** Convert functions ****************************/
@@ -153,7 +154,7 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
const char *pstr = plink->value.constantStr;
size_t len;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
len = strlen(pstr);
@@ -178,26 +179,36 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
return dbLSConvertJSON(pstr, pbuffer, size, plen);
status = dbLSConvertJSON(pstr, pbuffer, size, plen);
if (status)
errlogPrintf("... while parsing link %s.%s\n",
plink->precord->name, dbLinkFieldName(plink));
return status;
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,
long *pnReq)
{
const char *pstr = plink->value.constantStr;
long status;
if (!pstr)
if (!pstr || !pstr[0])
return S_db_badField;
/* Choice values must be numeric */
if (dbrType == DBF_MENU || dbrType == DBF_ENUM || dbrType == DBF_DEVICE)
dbrType = DBF_USHORT;
return dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
status = dbPutConvertJSON(pstr, dbrType, pbuffer, pnReq);
if (status)
errlogPrintf("... while parsing link %s.%s\n",
plink->precord->name, dbLinkFieldName(plink));
return status;
}
static long dbConstGetNelements(const struct link *plink, long *nelements)

View File

@@ -30,10 +30,12 @@ typedef struct parseContext {
} parseContext;
static int dbcj_null(void *ctx) {
errlogPrintf("dbConvertJSON: Null objects not supported\n");
return 0; /* Illegal */
}
static int dbcj_boolean(void *ctx, int val) {
errlogPrintf("dbConvertJSON: Boolean not supported\n");
return 0; /* Illegal */
}
@@ -50,10 +52,6 @@ static int dbcj_integer(void *ctx, long long num) {
return 1;
}
static int dblsj_integer(void *ctx, long long num) {
return 0; /* Illegal */
}
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
@@ -66,7 +64,9 @@ static int dbcj_double(void *ctx, double num) {
return 1;
}
static int dblsj_double(void *ctx, double num) {
static int dblsj_number(void *ctx, const char *val, size_t len) {
errlogPrintf("dbLSConvertJSON: Numeric value %.*s provided, string expected\n",
(int)len, val);
return 0; /* Illegal */
}
@@ -78,7 +78,8 @@ static int dbcj_string(void *ctx, const unsigned char *val, size_t len) {
* metadata about the field than we have available at the moment.
*/
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
errlogPrintf("dbConvertJSON: String \"%.*s\" provided, numeric value expected\n",
(int)len, val);
return 0; /* Illegal */
}
@@ -97,11 +98,6 @@ static int dblsj_string(void *ctx, const unsigned char *val, size_t len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: dblsj_string dbrType " ERL_ERROR "\n");
return 0; /* Illegal */
}
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
len = parser->dbrSize - 1;
@@ -118,14 +114,6 @@ static int dbcj_start_map(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_map_key(void *ctx, const unsigned char *key, size_t len) {
return 0; /* Illegal */
}
static int dbcj_end_map(void *ctx) {
return 0; /* Illegal */
}
static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
@@ -135,32 +123,30 @@ static int dbcj_start_array(void *ctx) {
return (parser->depth == 1);
}
static int dbcj_end_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
parser->depth--;
return (parser->depth == 0);
}
static yajl_callbacks dbcj_callbacks = {
dbcj_null, dbcj_boolean, dbcj_integer, dbcj_double, NULL, dbcj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
dbcj_start_map, NULL, NULL,
dbcj_start_array, NULL
};
long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *pnRequest)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
long status;
if(INVALID_DB_REQ(dbrType))
if (INVALID_DB_REQ(dbrType)) {
errlogPrintf("dbConvertJSON: Invalid dbrType %d\n", dbrType);
return S_db_badDbrtype;
}
if (!jlen) {
*pnRequest = 0;
return 0;
}
parser->depth = 0;
parser->dbrType = dbrType;
@@ -168,10 +154,11 @@ long dbPutConvertJSON(const char *json, short dbrType,
parser->pdest = pdest;
parser->elems = *pnRequest;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dbcj_callbacks, &dbcj_alloc, parser);
if (!yh)
yh = yajl_alloc(&dbcj_callbacks, NULL, parser);
if (!yh) {
errlogPrintf("dbConvertJSON: out of memory\n");
return S_db_noMemory;
}
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
if (ys == yajl_status_ok)
@@ -183,15 +170,13 @@ long dbPutConvertJSON(const char *json, short dbrType,
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbConvertJSON: %s\n", err);
yajl_free_error(yh, err);
default: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
errlogPrintf("dbConvertJSON: %s", err);
yajl_free_error(yh, err);
status = S_db_badField;
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
@@ -200,16 +185,15 @@ long dbPutConvertJSON(const char *json, short dbrType,
static yajl_callbacks dblsj_callbacks = {
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
dbcj_null, dbcj_boolean, NULL, NULL, dblsj_number, dblsj_string,
dbcj_start_map, NULL, NULL,
dbcj_start_array, NULL
};
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
epicsUInt32 *plen)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
@@ -226,10 +210,11 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
parser->pdest = pdest;
parser->elems = 1;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dblsj_callbacks, &dbcj_alloc, parser);
if (!yh)
yh = yajl_alloc(&dblsj_callbacks, NULL, parser);
if (!yh) {
errlogPrintf("dbLSConvertJSON: out of memory\n");
return S_db_noMemory;
}
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
@@ -239,15 +224,13 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
yajl_free_error(yh, err);
default: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, jlen);
errlogPrintf("dbLSConvertJSON: %s", err);
yajl_free_error(yh, err);
status = S_db_badField;
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);

View File

@@ -76,6 +76,7 @@ struct event_que {
unsigned short quota; /* the number of assigned entries*/
unsigned short nDuplicates; /* N events duplicated on this q */
unsigned short nCanceled; /* the number of canceled entries */
unsigned possibleStall;
};
struct event_user {
@@ -731,7 +732,7 @@ static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
/* don't make a copy yet, just reference the field value */
pLog->u.r.field = dbChannelField(chan);
/* indicate field value still owned by record */
pLog->u.r.dtor = NULL;
pLog->dtor = NULL;
/* no private data yet, may be set by a filter */
pLog->u.r.pvt = NULL;
}
@@ -789,6 +790,18 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
LOCKEVQUE (ev_que);
/* if we have an event on the queue and both the last
* event on the queue and the current event reference
* a record field, simply ignore duplicate events.
*/
if (pevent->npend > 0u
&& !dbfl_has_copy(*pevent->pLastLog)
&& !dbfl_has_copy(pLog)) {
db_delete_field_log(pLog);
UNLOCKEVQUE (ev_que);
return;
}
/*
* add to task local event que
*/
@@ -922,6 +935,7 @@ void db_post_single_event (dbEventSubscription event)
static int event_read ( struct event_que *ev_que )
{
db_field_log *pfl;
int notifiedRemaining = 0;
void ( *user_sub ) ( void *user_arg, struct dbChannel *chan,
int eventsRemaining, db_field_log *pfl );
@@ -943,6 +957,7 @@ static int event_read ( struct event_que *ev_que )
while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) {
struct evSubscrip *pevent = ev_que->evque[ev_que->getix];
int eventsRemaining;
pfl = ev_que->valque[ev_que->getix];
if ( pevent == &canceledEvent ) {
@@ -965,6 +980,7 @@ static int event_read ( struct event_que *ev_que )
event_remove ( ev_que, ev_que->getix, EVENTQEMPTY );
ev_que->getix = RNGINC ( ev_que->getix );
eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY && !ev_que->nCanceled;
/*
* create a local copy of the call back parameters while
@@ -997,7 +1013,8 @@ static int event_read ( struct event_que *ev_que )
if (pfl) {
/* Issue user callback */
( *user_sub ) ( pevent->user_arg, pevent->chan,
ev_que->evque[ev_que->getix] != EVENTQEMPTY, pfl );
eventsRemaining, pfl );
notifiedRemaining = eventsRemaining;
}
LOCKEVQUE (ev_que);
@@ -1024,6 +1041,11 @@ static int event_read ( struct event_que *ev_que )
db_delete_field_log(pfl);
}
if(notifiedRemaining && !ev_que->possibleStall) {
ev_que->possibleStall = 1;
errlogPrintf(ERL_WARNING " dbEvent possible queue stall\n");
}
UNLOCKEVQUE (ev_que);
return DB_EVENT_OK;
@@ -1201,7 +1223,7 @@ void db_delete_field_log (db_field_log *pfl)
{
if (pfl) {
/* Free field if reference type field log and dtor is set */
if (pfl->type == dbfl_type_ref && pfl->u.r.dtor) pfl->u.r.dtor(pfl);
if (pfl->type == dbfl_type_ref && pfl->dtor) pfl->dtor(pfl);
/* Free the field log chunk */
freeListFree(dbevFieldLogFreeList, pfl);
}

View File

@@ -14,7 +14,6 @@
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
@@ -24,6 +23,7 @@
#include "dbDefs.h"
#include "epicsConvert.h"
#include "epicsStdlib.h"
#include "epicsStdio.h"
#include "errlog.h"
#include "errMdef.h"
@@ -1335,24 +1335,26 @@ static long cvt_menu_st(
epicsEnum16 *from,
char *to,
const dbAddr *paddr)
{
dbFldDes *pdbFldDes;
dbMenu *pdbMenu;
char **papChoiceValue;
char *pchoice;
{
dbFldDes *pdbFldDes;
dbMenu *pdbMenu;
if(! paddr
|| !(pdbFldDes = paddr->pfldDes)
|| !(pdbMenu = (dbMenu *)pdbFldDes->ftPvt)
|| *from>=pdbMenu->nChoice
|| !(papChoiceValue = pdbMenu->papChoiceValue)
|| !(pchoice=papChoiceValue[*from])) {
recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_menu_st)");
return(S_db_badChoice);
if (!paddr ||
!(pdbFldDes = paddr->pfldDes) ||
!(pdbMenu = (dbMenu *)pdbFldDes->ftPvt)) {
recGblDbaddrError(S_db_badChoice, paddr, "dbFastLinkConv(cvt_menu_st)");
return S_db_badChoice;
}
strncpy(to,pchoice,MAX_STRING_SIZE);
return(0);
}
if (*from < pdbMenu->nChoice) {
strncpy(to, pdbMenu->papChoiceValue[*from], MAX_STRING_SIZE);
}
else {
/* Convert out-of-range values to numeric strings */
epicsSnprintf(to, MAX_STRING_SIZE, "%u", *from);
}
return 0;
}
/* Get Device to String */
@@ -1366,10 +1368,17 @@ static long cvt_device_st(
char **papChoice;
char *pchoice;
if(!paddr
|| !(pdbFldDes = paddr->pfldDes)
|| !(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)
|| *from>=pdbDeviceMenu->nChoice
if (!paddr
|| !(pdbFldDes = paddr->pfldDes)) {
recGblDbaddrError(S_db_errArg, paddr, "dbFastLinkConv(cvt_device_st)");
return S_db_errArg;
}
if (!(pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt)) {
/* Valid, record type has no device support */
*to = '\0';
return 0;
}
if (*from >= pdbDeviceMenu->nChoice
|| !(papChoice= pdbDeviceMenu->papChoice)
|| !(pchoice=papChoice[*from])) {
recGblDbaddrError(S_db_badChoice,paddr,"dbFastLinkConv(cvt_device_st)");

View File

@@ -8,10 +8,13 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define EPICS_PRIVATE_API
#include "iocsh.h"
#include "callback.h"
#include "dbAccess.h"
#include "dbStaticPvt.h"
#include "dbBkpt.h"
#include "dbCaTest.h"
#include "dbEvent.h"
@@ -28,53 +31,66 @@
DBCORE_API extern int callbackParallelThreadsDefault;
/* dbLoadDatabase */
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadDatabaseArg1 = { "path",iocshArgString};
static const iocshArg dbLoadDatabaseArg0 = { "file name",iocshArgStringPath};
static const iocshArg dbLoadDatabaseArg1 = { "path",iocshArgStringPath};
static const iocshArg dbLoadDatabaseArg2 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadDatabaseArgs[3] =
{
&dbLoadDatabaseArg0,&dbLoadDatabaseArg1,&dbLoadDatabaseArg2
};
static const iocshFuncDef dbLoadDatabaseFuncDef =
{"dbLoadDatabase",3,dbLoadDatabaseArgs};
static const iocshFuncDef dbLoadDatabaseFuncDef = {
"dbLoadDatabase",
3,
dbLoadDatabaseArgs,
"Load the given .dbd file, with 'path' added as a search path, with the given substitutions.\n\n"
"Substitutions are usually not needed for .dbd files.\n\n"
"Example: dbLoadDatabase dbd/my.dbd\n",
};
static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
{
iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval));
}
/* dbLoadRecords */
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgString};
static const iocshArg dbLoadRecordsArg0 = { "file name",iocshArgStringPath};
static const iocshArg dbLoadRecordsArg1 = { "substitutions",iocshArgString};
static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoadRecordsArg1};
static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs};
static const iocshFuncDef dbLoadRecordsFuncDef = {
"dbLoadRecords",
2,
dbLoadRecordsArgs,
"Load the given .db file, with the given substitutions.\n\n"
"Substitutions should be given in the format 'var1=value1,var2=value2'.\n\n"
"Example: dbLoadRecords db/myRecords.db 'user=myself,host=myhost'\n",
};
static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
{
iocshSetError(dbLoadRecords(args[0].sval,args[1].sval));
}
/* dbb */
static const iocshArg dbbArg0 = { "record name",iocshArgString};
static const iocshArg dbbArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbbArgs[1] = {&dbbArg0};
static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs,
"Add breakpoint to a lock set.\n"};
static void dbbCallFunc(const iocshArgBuf *args) { dbb(args[0].sval);}
/* dbd */
static const iocshArg dbdArg0 = { "record name",iocshArgString};
static const iocshArg dbdArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbdArgs[1] = {&dbdArg0};
static const iocshFuncDef dbdFuncDef = {"dbd",1,dbdArgs,
"Remove breakpoint from a record.\n"};
static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);}
/* dbc */
static const iocshArg dbcArg0 = { "record name",iocshArgString};
static const iocshArg dbcArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbcArgs[1] = {&dbcArg0};
static const iocshFuncDef dbcFuncDef = {"dbc",1,dbcArgs,
"Continue processing in a lock set.\n"};
static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);}
/* dbs */
static const iocshArg dbsArg0 = { "record name",iocshArgString};
static const iocshArg dbsArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbsArgs[1] = {&dbsArg0};
static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs,
"Step through record processing.\n"};
@@ -86,7 +102,7 @@ static const iocshFuncDef dbstatFuncDef = {"dbstat",0,0,
static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();}
/* dbp */
static const iocshArg dbpArg0 = { "record name",iocshArgString};
static const iocshArg dbpArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbpArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbpArgs[2] = {&dbpArg0,&dbpArg1};
static const iocshFuncDef dbpFuncDef = {"dbp",2,dbpArgs,
@@ -95,7 +111,7 @@ static void dbpCallFunc(const iocshArgBuf *args)
{ dbp(args[0].sval,args[1].ival);}
/* dbap */
static const iocshArg dbapArg0 = { "record name",iocshArgString};
static const iocshArg dbapArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbapArgs[1] = {&dbapArg0};
static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs,
"toggle printing after processing a certain record.\n"};
@@ -109,7 +125,7 @@ static const iocshFuncDef dbsrFuncDef = {"dbsr",1,dbsrArgs,
static void dbsrCallFunc(const iocshArgBuf *args) { dbsr(args[0].ival);}
/* dbcar */
static const iocshArg dbcarArg0 = { "record name",iocshArgString};
static const iocshArg dbcarArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbcarArg1 = { "level",iocshArgInt};
static const iocshArg * const dbcarArgs[2] = {&dbcarArg0,&dbcarArg1};
static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs,
@@ -124,7 +140,7 @@ static void dbcarCallFunc(const iocshArgBuf *args)
}
/* dbjlr */
static const iocshArg dbjlrArg0 = { "record name",iocshArgString};
static const iocshArg dbjlrArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbjlrArg1 = { "level",iocshArgInt};
static const iocshArg * const dbjlrArgs[2] = {&dbjlrArg0,&dbjlrArg1};
static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs,
@@ -135,7 +151,7 @@ static void dbjlrCallFunc(const iocshArgBuf *args)
}
/* dbel */
static const iocshArg dbelArg0 = { "record name",iocshArgString};
static const iocshArg dbelArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbelArg1 = { "level",iocshArgInt};
static const iocshArg * const dbelArgs[2] = {&dbelArg0,&dbelArg1};
static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs,
@@ -147,7 +163,7 @@ static void dbelCallFunc(const iocshArgBuf *args)
}
/* dba */
static const iocshArg dbaArg0 = { "record name",iocshArgString};
static const iocshArg dbaArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbaArgs[1] = {&dbaArg0};
static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs,
"dbAddr info.\n"};
@@ -181,21 +197,21 @@ static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs,
static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);}
/* dbla */
static const iocshArg dblaArg0 = { "pattern",iocshArgString};
static const iocshArg dblaArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg * const dblaArgs[1] = {&dblaArg0};
static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs,
"List record alias()s by alias name pattern.\n"};
static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);}
/* dbgrep */
static const iocshArg dbgrepArg0 = { "pattern",iocshArgString};
static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord};
static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0};
static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs,
"List record names matching pattern.\n"};
static void dbgrepCallFunc(const iocshArgBuf *args) { dbgrep(args[0].sval);}
/* dbgf */
static const iocshArg dbgfArg0 = { "record name",iocshArgString};
static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbgfArgs[1] = {&dbgfArg0};
static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs,
"Database Get Field.\n"
@@ -203,7 +219,7 @@ static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs,
static void dbgfCallFunc(const iocshArgBuf *args) { dbgf(args[0].sval);}
/* dbpf */
static const iocshArg dbpfArg0 = { "record name",iocshArgString};
static const iocshArg dbpfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbpfArgs[2] = {&dbpfArg0,&dbpfArg1};
static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs,
@@ -213,7 +229,7 @@ static void dbpfCallFunc(const iocshArgBuf *args)
{ dbpf(args[0].sval,args[1].sval);}
/* dbpr */
static const iocshArg dbprArg0 = { "record name",iocshArgString};
static const iocshArg dbprArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbprArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dbprArgs[2] = {&dbprArg0,&dbprArg1};
static const iocshFuncDef dbprFuncDef = {"dbpr",2,dbprArgs,
@@ -223,14 +239,14 @@ static void dbprCallFunc(const iocshArgBuf *args)
{ dbpr(args[0].sval,args[1].ival);}
/* dbtr */
static const iocshArg dbtrArg0 = { "record name",iocshArgString};
static const iocshArg dbtrArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbtrArgs[1] = {&dbtrArg0};
static const iocshFuncDef dbtrFuncDef = {"dbtr",1,dbtrArgs,
"Process record and then some fields.\n"};
static void dbtrCallFunc(const iocshArgBuf *args) { dbtr(args[0].sval);}
/* dbtgf */
static const iocshArg dbtgfArg0 = { "record name",iocshArgString};
static const iocshArg dbtgfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
"Database Test Get Field.\n"
@@ -238,7 +254,7 @@ static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
/* dbtpf */
static const iocshArg dbtpfArg0 = { "record name",iocshArgString};
static const iocshArg dbtpfArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbtpfArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpfArgs[2] = {&dbtpfArg0,&dbtpfArg1};
static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs,
@@ -261,14 +277,14 @@ static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0,
static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();}
/* gft */
static const iocshArg gftArg0 = { "record name",iocshArgString};
static const iocshArg gftArg0 = { "record name",iocshArgStringRecord};
static const iocshArg * const gftArgs[1] = {&gftArg0};
static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs,
"Report dbChannel info and value.\n"};
static void gftCallFunc(const iocshArgBuf *args) { gft(args[0].sval);}
/* pft */
static const iocshArg pftArg0 = { "record name",iocshArgString};
static const iocshArg pftArg0 = { "record name",iocshArgStringRecord};
static const iocshArg pftArg1 = { "value",iocshArgString};
static const iocshArg * const pftArgs[2] = {&pftArg0,&pftArg1};
static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs,
@@ -277,7 +293,7 @@ static void pftCallFunc(const iocshArgBuf *args)
{ pft(args[0].sval,args[1].sval);}
/* dbtpn */
static const iocshArg dbtpnArg0 = { "record name",iocshArgString};
static const iocshArg dbtpnArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dbtpnArg1 = { "value",iocshArgString};
static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs,
@@ -305,7 +321,7 @@ static void dbPutAttrCallFunc(const iocshArgBuf *args)
{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);}
/* tpn */
static const iocshArg tpnArg0 = { "record name",iocshArgString};
static const iocshArg tpnArg0 = { "record name",iocshArgStringRecord};
static const iocshArg tpnArg1 = { "value",iocshArgString};
static const iocshArg * const tpnArgs[2] = {&tpnArg0,&tpnArg1};
static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs,
@@ -314,7 +330,7 @@ static void tpnCallFunc(const iocshArgBuf *args)
{ tpn(args[0].sval,args[1].sval);}
/* dblsr */
static const iocshArg dblsrArg0 = { "record name",iocshArgString};
static const iocshArg dblsrArg0 = { "record name",iocshArgStringRecord};
static const iocshArg dblsrArg1 = { "interest level",iocshArgInt};
static const iocshArg * const dblsrArgs[2] = {&dblsrArg0,&dblsrArg1};
static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs,
@@ -487,6 +503,8 @@ static void dbStateShowAllCallFunc (const iocshArgBuf *args)
void dbIocRegister(void)
{
iocshCompleteRecord = &dbCompleteRecord;
iocshRegister(&dbbFuncDef,dbbCallFunc);
iocshRegister(&dbdFuncDef,dbdCallFunc);
iocshRegister(&dbcFuncDef,dbcCallFunc);

View File

@@ -410,8 +410,21 @@ DBCORE_API long dbLoadLinkArray(struct link *, short dbrType, void *pbuffer,
DBCORE_API long dbGetNelements(const struct link *plink, long *pnElements);
DBCORE_API int dbIsLinkConnected(const struct link *plink); /* 0 or 1 */
DBCORE_API int dbGetLinkDBFtype(const struct link *plink);
/** \brief Fetch current value from link.
* \param dbrType Database DBR code
* \param pbuffer Destination buffer
* \param nRequest If !NULL. Caller initializes with number of elements requested,
* On success, set to number of elements written to pbuffer.
* \return 0 on success
*
* When called with `nRequest==NULL`, treated as a request for one (1)
* element.
*
* see lset::getValue
*/
DBCORE_API long dbTryGetLink(struct link *, short dbrType, void *pbuffer,
long *nRequest);
/** see dbTryGetLink() */
DBCORE_API long dbGetLink(struct link *, short dbrType, void *pbuffer,
long *options, long *nRequest);
DBCORE_API long dbGetControlLimits(const struct link *plink, double *low,

View File

@@ -121,8 +121,7 @@ void dbLockIncRef(lockSet* ls)
{
int cnt = epicsAtomicIncrIntT(&ls->refcount);
if(cnt<=1) {
errlogPrintf("dbLockIncRef(%p) on dead lockSet. refs: %d\n", ls, cnt);
cantProceed(NULL);
cantProceed("dbLockIncRef(%p) on dead lockSet. refs: %d\n", ls, cnt);
}
}
@@ -145,9 +144,8 @@ void dbLockDecRef(lockSet *ls)
epicsMutexMustLock(ls->lock);
if(ellCount(&ls->lockRecordList)!=0) {
errlogPrintf("dbLockDecRef(%p) would free lockSet with %d records\n",
ls, ellCount(&ls->lockRecordList));
cantProceed(NULL);
cantProceed("dbLockDecRef(%p) would free lockSet with %d records\n",
ls, ellCount(&ls->lockRecordList));
}
epicsMutexUnlock(ls->lock);
@@ -421,9 +419,8 @@ retry:
#ifdef LOCKSET_DEBUG
if(plock->owner) {
if(plock->owner!=myself || plock->ownercount<1) {
errlogPrintf("dbScanLockMany(%p) ownership violation %p (%p) %u\n",
locker, plock->owner, myself, plock->ownercount);
cantProceed(NULL);
cantProceed("dbScanLockMany(%p) ownership violation %p (%p) %u\n",
locker, plock->owner, myself, plock->ownercount);
}
plock->ownercount++;
} else {
@@ -444,8 +441,7 @@ retry:
/* if we have at least one lockRecord, then we will always lock
* at least its present lockSet
*/
errlogPrintf("dbScanLockMany(%p) didn't lock anything\n", locker);
cantProceed(NULL);
cantProceed("dbScanLockMany(%p) didn't lock anything\n", locker);
}
}
@@ -602,17 +598,15 @@ void dbLockSetMerge(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
#ifdef LOCKSET_DEBUG
if(locker && (A->owner!=myself || B->owner!=myself)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->owner, B->owner, myself);
cantProceed(NULL);
cantProceed("dbLockSetMerge(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->owner, B->owner, myself);
}
#endif
if(locker && (A->ownerlocker!=locker || B->ownerlocker!=locker)) {
errlogPrintf("dbLockSetMerge(%p,\"%s\",\"%s\") locker ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->ownerlocker, B->ownerlocker, locker);
cantProceed(NULL);
cantProceed("dbLockSetMerge(%p,\"%s\",\"%s\") locker ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
A->ownerlocker, B->ownerlocker, locker);
}
if(A==B)
@@ -688,19 +682,17 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
#ifdef LOCKSET_DEBUG
if(ls->owner!=myself || psecond->lset->plockSet->owner!=myself) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
ls->owner, psecond->lset->plockSet->owner, myself);
cantProceed(NULL);
cantProceed("dbLockSetSplit(%p,\"%s\",\"%s\") ownership violation %p %p (%p)\n",
locker, pfirst->name, psecond->name,
ls->owner, psecond->lset->plockSet->owner, myself);
}
#endif
/* lockset consistency violation */
if(ls!=psecond->lset->plockSet) {
errlogPrintf("dbLockSetSplit(%p,\"%s\",\"%s\") consistency violation %p %p\n",
locker, pfirst->name, psecond->name,
pfirst->lset->plockSet, psecond->lset->plockSet);
cantProceed(NULL);
cantProceed("dbLockSetSplit(%p,\"%s\",\"%s\") consistency violation %p %p\n",
locker, pfirst->name, psecond->name,
pfirst->lset->plockSet, psecond->lset->plockSet);
}

View File

@@ -168,9 +168,13 @@ void scanStop(void)
epicsEventSignal(ppsl->loopEvent);
epicsEventWait(startStopEvent);
}
for (i = 0; i < nPeriodic; i++) {
epicsThreadMustJoin(periodicTaskId[i]);
}
scanOnce((dbCommon *)&exitOnce);
epicsEventWait(startStopEvent);
epicsThreadMustJoin(onceTaskId);
}
void scanCleanup(void)
@@ -761,14 +765,16 @@ void scanOnceQueueShow(const int reset)
static void initOnce(void)
{
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = epicsThreadPriorityScanLow + nPeriodic;
opts.stackSize = epicsThreadStackBig;
if ((onceQ = epicsRingBytesLockedCreate(sizeof(onceEntry)*onceQueueSize)) == NULL) {
cantProceed("initOnce: Ring buffer create failed\n");
}
if(!onceSem)
onceSem = epicsEventMustCreate(epicsEventEmpty);
onceTaskId = epicsThreadCreate("scanOnce",
epicsThreadPriorityScanLow + nPeriodic,
epicsThreadGetStackSize(epicsThreadStackBig), onceTask, 0);
onceTaskId = epicsThreadCreateOpt("scanOnce", onceTask, 0, &opts);
epicsEventWait(startStopEvent);
}
@@ -932,14 +938,16 @@ static void spawnPeriodic(int ind)
{
periodic_scan_list *ppsl = papPeriodic[ind];
char taskName[20];
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
opts.joinable = 1;
opts.priority = epicsThreadPriorityScanLow + ind;
opts.stackSize = epicsThreadStackBig;
if (!ppsl) return;
sprintf(taskName, "scan-%g", ppsl->period);
periodicTaskId[ind] = epicsThreadCreate(
taskName, epicsThreadPriorityScanLow + ind,
epicsThreadGetStackSize(epicsThreadStackBig),
periodicTask, (void *)ppsl);
periodicTaskId[ind] = epicsThreadCreateOpt(
taskName, periodicTask, (void *)ppsl, &opts);
epicsEventWait(startStopEvent);
}

View File

@@ -996,8 +996,12 @@ static void printBuffer(
i = 0;
while (len > 0) {
int chunk = (len > MAXLINE - 5) ? MAXLINE - 5 : len;
sprintf(pmsg, "\"%.*s\"", chunk, (char *)pbuffer + i);
strcpy(pmsg, "\"");
while (epicsStrnEscapedFromRawSize((char *)pbuffer + i, chunk) >= MAXLINE - 5)
chunk--;
epicsStrnEscapedFromRaw(pmsg+1, MAXLINE - 5,
(char *)pbuffer + i, chunk);
strcat(pmsg, "\"");
len -= chunk; i += chunk;
if (len > 0)
strcat(pmsg, " +");

View File

@@ -339,7 +339,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
break;
}
#define OP(DBR,Type,pat) case DBR: {Type expect = *(Type*)pbuf, actual = *(Type*)gbuf; assert(vSize==sizeof(Type)); match &= expect==actual; \
if(expect!=actual) testDiag("[%lu] expected=" pat " actual=" pat, n, expect, actual); break;}
if(expect!=actual) {testDiag("[%lu] expected=" pat " actual=" pat, n, expect, actual);} break;}
OP(DBR_CHAR, char, "%c");
OP(DBR_UCHAR, unsigned char, "%u");

View File

@@ -105,7 +105,7 @@ DBCORE_API void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap);
*
* @code
* static const epicsUInt32 putval[] = {1,2,3};
* testdbVGetFieldEqual("some:wf", DBF_ULONG, NELEMENTS(putval), putval);
* testdbPutArrFieldOk("some:wf", DBF_ULONG, NELEMENTS(putval), putval);
* @endcode
*
* @see @ref dbtestactions
@@ -190,6 +190,7 @@ DBCORE_API void testGlobalUnlock(void);
*
* @code
* #include <dbUnitTest.h>
* #include <testMain.h>
*
* int mytest_registerRecordDeviceDriver(DBBASE *pbase);
* void testCase(void) {
@@ -204,7 +205,7 @@ DBCORE_API void testGlobalUnlock(void);
* }
*
* MAIN(mytestmain) {
* testPlan(0);
* testPlan(0); // adjust number of tests
* testCase();
* testCase(); // may be repeated if desirable.
* return testDone();
@@ -212,6 +213,9 @@ DBCORE_API void testGlobalUnlock(void);
* @endcode
*
* @code
* TOP = ..
* include $(TOP)/configure/CONFIG
*
* TARGETS += $(COMMON_DIR)/mytest.dbd
* DBDDEPENDS_FILES += mytest.dbd$(DEP)
* TESTFILES += $(COMMON_DIR)/mytest.dbd
@@ -222,6 +226,8 @@ DBCORE_API void testGlobalUnlock(void);
* mytest_SRCS += mytestmain.c # see above
* mytest_SRCS += mytest_registerRecordDeviceDriver.cpp
* TESTFILES += some.db
*
* include $(TOP)/configure/RULES
* @endcode
*
* @section dbtestactions Actions

View File

@@ -39,12 +39,17 @@ extern "C" {
* will adjust automatically, it just compares field sizes.
*/
union native_value {
epicsInt8 dbf_char;
epicsInt16 dbf_short;
epicsEnum16 dbf_enum;
epicsInt32 dbf_long;
epicsFloat32 dbf_float;
epicsFloat64 dbf_double;
epicsInt8 dbf_char;
epicsUInt8 dbf_uchar;
epicsInt16 dbf_short;
epicsUInt16 dbf_ushort;
epicsEnum16 dbf_enum;
epicsInt32 dbf_long;
epicsUInt32 dbf_ulong;
epicsInt64 dbf_int64;
epicsUInt64 dbf_uint64;
epicsFloat32 dbf_float;
epicsFloat64 dbf_double;
#ifdef DB_EVENT_LOG_STRINGS
char dbf_string[MAX_STRING_SIZE];
#endif
@@ -97,7 +102,6 @@ struct dbfl_val {
* data is still owned by a record. See the macro dbfl_has_copy below.
*/
struct dbfl_ref {
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
void *pvt; /* Private pointer */
void *field; /* Field value */
};
@@ -120,6 +124,7 @@ typedef struct db_field_log {
short field_type; /* DBF type of data */
short field_size; /* Size of a single element */
long no_elements; /* No of valid array elements */
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
union {
struct dbfl_val v;
struct dbfl_ref r;
@@ -136,7 +141,7 @@ typedef struct db_field_log {
* the db_field_log still owns the (empty) data.
*/
#define dbfl_has_copy(p)\
((p) && ((p)->type==dbfl_type_val || (p)->u.r.dtor || (p)->no_elements==0))
((p) && ((p)->type==dbfl_type_val || (p)->dtor || (p)->no_elements==0))
#define dbfl_pfield(p)\
((p)->type==dbfl_type_val ? &p->u.v.field : p->u.r.field)

View File

@@ -56,63 +56,66 @@ static void getMaxRangeValues(short field_type, double *pupper_limit,
double *plower_limit);
void recGblDbaddrError(long status, const struct dbAddr *paddr,
const char *pmessage)
{
dbCommon *precord = 0;
dbFldDes *pdbFldDes = 0;
if(paddr) {
pdbFldDes = paddr->pfldDes;
precord = paddr->precord;
}
errPrintf(status,0,0,
"PV: %s.%s "
"error detected in routine: %s\n",
(precord ? precord->name : "Unknown"),
(pdbFldDes ? pdbFldDes->name : ""),
(pmessage ? pmessage : "Unknown"));
return;
}
void recGblRecordError(long status, void *pdbc,
const char *pmessage)
{
dbCommon *precord = pdbc;
dbCommon *precord = pdbc;
char errMsg[256] = "";
errPrintf(status,0,0,
"PV: %s %s\n",
(precord ? precord->name : "Unknown"),
(pmessage ? pmessage : ""));
return;
if (status)
errSymLookup(status, errMsg, sizeof(errMsg));
errlogPrintf("recGblRecordError: %s %s PV: %s\n",
pmessage ? pmessage : "", errMsg,
precord ? precord->name : "Unknown");
}
void recGblDbaddrError(long status, const struct dbAddr *paddr,
const char *pmessage)
{
dbCommon *precord = 0;
dbFldDes *pdbFldDes = 0;
char errMsg[256] = "";
if (paddr) {
pdbFldDes = paddr->pfldDes;
precord = paddr->precord;
}
if (status)
errSymLookup(status, errMsg, sizeof(errMsg));
errlogPrintf("recGblDbaddrError: %s %s PV: %s.%s\n",
pmessage ? pmessage : "",errMsg,
precord ? precord->name : "Unknown",
pdbFldDes ? pdbFldDes->name : "");
}
void recGblRecSupError(long status, const struct dbAddr *paddr,
const char *pmessage, const char *psupport_name)
{
dbCommon *precord = 0;
dbFldDes *pdbFldDes = 0;
dbRecordType *pdbRecordType = 0;
char errMsg[256] = "";
if(paddr) {
if (paddr) {
precord = paddr->precord;
pdbFldDes = paddr->pfldDes;
if(pdbFldDes) pdbRecordType = pdbFldDes->pdbRecordType;
if (pdbFldDes)
pdbRecordType = pdbFldDes->pdbRecordType;
}
errPrintf(status,0,0,
"Record Support Routine (%s) "
"Record Type %s "
"PV %s.%s "
" %s\n",
(psupport_name ? psupport_name : "Unknown"),
(pdbRecordType ? pdbRecordType->name : "Unknown"),
(precord ? precord->name : "Unknown"),
(pdbFldDes ? pdbFldDes->name : ""),
(pmessage ? pmessage : ""));
return;
if (status)
errSymLookup(status, errMsg, sizeof(errMsg));
errlogPrintf("recGblRecSupError: %s %s %s::%s PV: %s.%s\n",
pmessage ? pmessage : "", errMsg,
pdbRecordType ? pdbRecordType->name : "Unknown",
psupport_name ? psupport_name : "Unknown",
precord ? precord->name : "Unknown",
pdbFldDes ? pdbFldDes->name : "");
}
void recGblGetPrec(const struct dbAddr *paddr, long *precision)
{
dbFldDes *pdbFldDes = paddr->pfldDes;

View File

@@ -75,7 +75,7 @@ DBCORE_API void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat,
epicsEnum16 sevr);
DBCORE_API int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, ...) EPICS_PRINTF_STYLE(4,5);
EPICS_PRINTF_FMT(const char *msg), ...) EPICS_PRINTF_STYLE(4,5);
DBCORE_API int recGblSetSevrVMsg(void *precord, epicsEnum16 new_stat,
epicsEnum16 new_sevr,
const char *msg, va_list args);

View File

@@ -28,5 +28,6 @@ dbCore_SRCS += dbYacc.c
dbCore_SRCS += dbPvdLib.c
dbCore_SRCS += dbStaticRun.c
dbCore_SRCS += dbStaticIocRegister.c
dbCore_SRCS += dbCompleteRecord.cpp
CLEANS += dbLex.c dbYacc.c

View File

@@ -0,0 +1,163 @@
/*************************************************************************\
* Copyright (c) 2022 Michael Davidsaver
* SPDX-License-Identifier: EPICS
* EPICS Base is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <algorithm>
#include <limits>
#include <string>
#include <set>
#include <string.h>
#include <epicsStdio.h>
#include <dbAccess.h>
#include "dbStaticPvt.h"
namespace {
// immutable C string slice. (avoid allocating many temporary std::string)
class CStr {
const char* p;
size_t l;
public:
CStr() :p(NULL), l(0u) {}
CStr(const CStr& o) :p(o.p), l(o.l) {}
explicit CStr(const char* p) :p(p), l(p ? strlen(p) : 0u) {}
CStr(const char* p, size_t n) :p(p), l(n) {}
CStr& operator=(const CStr& o) {
p = o.p;
l = o.l;
return *this;
}
bool operator==(const CStr& o) const {
return l==o.l && (p==o.p || memcmp(p, o.p, l)==0);
}
bool operator!=(const CStr& o) const {
return !(*this==o);
}
bool operator<(const CStr& o) const {
size_t pl = std::min(l, o.l);
int cmp = memcmp(p, o.p, pl);
return cmp<0 || (cmp==0 && l < o.l);
}
bool empty() const { return !l; }
size_t size() const { return l; }
bool prefixOf(const CStr& full) const {
return full.l >= l && memcmp(full.p, p, l)==0;
}
CStr commonPrefix(const CStr& o, size_t startFrom=0u) const {
size_t n, N;
for(n=startFrom, N=std::min(l, o.l); n<N; n++) {
if(p[n]!=o.p[n])
break;
}
return CStr(p, n);
}
void chop_at_first_of(const char* sep, size_t startFrom=0u) {
size_t n;
for(n=startFrom; n<l; n++) {
char c = p[n];
for(const char *s = sep; *s; s++) {
if(c == *s) {
l = n+1u; // include trailing separator
return;
}
}
}
}
char* dup() const {
char* ret = (char*)malloc(l+1u);
if(ret) {
memcpy(ret, p, l);
ret[l] = '\0';
}
return ret;
}
};
} // namespace
char** dbCompleteRecord(const char *cword)
{
const CStr word(cword);
DBENTRY ent;
dbInitEntry(pdbbase, &ent);
try{
// iterating all record twice...
CStr prefix;
bool first = true;
// find longest prefix match
for(long status = dbFirstRecordType(&ent); !status; status = dbNextRecordType(&ent)) {
for(status = dbFirstRecord(&ent); !status; status = dbNextRecord(&ent)) {
const CStr name(ent.precnode->recordname);
if(!word.prefixOf(name))
continue;
if(first) { // first match
prefix = name;
first = false;
} else {
prefix = prefix.commonPrefix(name, word.size());
}
}
}
// with prefix size known, iterate again to find suggestions
typedef std::set<CStr> suggestions_t;
suggestions_t suggestions;
for(long status = dbFirstRecordType(&ent); !status; status = dbNextRecordType(&ent)) {
for(status = dbFirstRecord(&ent); !status; status = dbNextRecord(&ent)) {
CStr name(ent.precnode->recordname);
if(!prefix.prefixOf(name))
continue;
name.chop_at_first_of(":<>{}-", prefix.size());
suggestions.insert(name);
}
}
dbFinishEntry(&ent);
char** ret = NULL;
if(!prefix.empty() || !suggestions.empty()) {
ret = (char**)malloc(sizeof(*ret)*(2u + suggestions.size()));
if(ret) {
ret[0] = prefix.dup();
size_t n=1u;
for(suggestions_t::iterator it(suggestions.begin()), end(suggestions.end());
it!=end; ++it)
{
ret[n++] = it->dup();
}
ret[n] = NULL;
}
}
return ret;
} catch(std::exception& e){
fprintf(stderr, "dbCompleteRecord error: %s\n", e.what());
dbFinishEntry(&ent);
return NULL;
}
}

View File

@@ -15,7 +15,8 @@ doublequote "\""
comment "#"
whitespace [ \t\r\n]
escape {backslash}.
stringchar [^"\n\\]
sqschar [^'\n\\]
dqschar [^"\n\\]
bareword [a-zA-Z0-9_\-+:.\[\]<>;]
punctuation [:,\[\]{}]
@@ -84,7 +85,7 @@ static int yyreset(void)
return(tokenSTRING);
}
{doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */
{doublequote}({dqschar}|{escape})*{doublequote} { /* quoted string */
yylval.Str = dbmfStrdup((char *) yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(tokenSTRING);
@@ -129,14 +130,14 @@ static int yyreset(void)
/* Error patterns */
{doublequote}({stringchar}|{escape})*{newline} {
{doublequote}({dqschar}|{escape})*{newline} {
yyerrorAbort("Newline in string, closing quote missing");
}
<JSON>{doublequote}({stringchar}|{escape})*{doublequote} {
<JSON>{doublequote}({dqschar}|{escape})*{doublequote} {
yyerrorAbort("Bad character in JSON string");
}
<JSON>{singlequote}({stringchar}|{escape})*{singlequote} {
<JSON>{singlequote}({sqschar}|{escape})*{singlequote} {
yyerrorAbort("Bad character in JSON string");
}

View File

@@ -37,7 +37,11 @@
#include "special.h"
#include "iocInit.h"
/* This file is included from dbYacc.y
* Duplicate some declarations to avoid warnings from analysis tools which don't know about this.
*/
static int yyerror(char *str);
static long pvt_yy_parse(void);
/*global declarations*/
char *makeDbdDepends=0;
@@ -99,15 +103,16 @@ static char *my_buffer_ptr=NULL;
static MAC_HANDLE *macHandle = NULL;
typedef struct inputFile{
ELLNODE node;
char *path;
char *filename;
const char *path;
const char *filename;
FILE *fp;
int line_num;
}inputFile;
static ELLLIST inputFileList = ELLLIST_INIT;
static inputFile *pinputFileNow = NULL;
static DBBASE *pdbbase = NULL;
/* The DBBASE most recently allocated/used by dbReadCOM() */
static DBBASE *savedPdbbase = NULL;
typedef struct tempListNode {
ELLNODE node;
@@ -155,7 +160,7 @@ static void *getLastTemp(void)
return(ptempListNode->item);
}
static char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp)
const char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp)
{
ELLLIST *ppathList = (ELLLIST *)pdbbase->pathPvt;
dbPathNode *pdbPathNode;
@@ -223,19 +228,21 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
epicsPrintf("dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
}
if (getIocState() != iocVoid)
return -2;
if (getIocState() != iocVoid) {
status = -2;
goto cleanup;
}
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
pdbbase = *ppdbbase;
savedPdbbase = *ppdbbase;
if(path && strlen(path)>0) {
dbPath(pdbbase,path);
dbPath(savedPdbbase,path);
} else {
penv = getenv("EPICS_DB_INCLUDE_PATH");
if(penv) {
dbPath(pdbbase,penv);
dbPath(savedPdbbase,penv);
} else {
dbPath(pdbbase,".");
dbPath(savedPdbbase,".");
}
}
my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
@@ -265,11 +272,11 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
FILE *fp1 = 0;
if (pinputFile->filename)
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp1);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp1);
if (!pinputFile->filename || !fp1) {
errPrintf(0, __FILE__, __LINE__,
"dbRead opening file %s",pinputFile->filename);
free(pinputFile->filename);
"dbRead opening file %s\n",pinputFile->filename);
free((char*)pinputFile->filename);
free(pinputFile);
status = -1;
goto cleanup;
@@ -277,6 +284,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
pinputFile->fp = fp1;
} else {
pinputFile->fp = fp;
fp = NULL;
}
pinputFile->line_num = 0;
pinputFileNow = pinputFile;
@@ -290,13 +298,13 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
while (ellCount(&tempList))
popFirstTemp(); /* Memory leak on parser failure */
dbFreePath(pdbbase);
dbFreePath(savedPdbbase);
if(!status) { /*add RTYP and VERS as an attribute */
DBENTRY dbEntry;
DBENTRY *pdbEntry = &dbEntry;
long localStatus;
dbInitEntry(pdbbase,pdbEntry);
dbInitEntry(savedPdbbase,pdbEntry);
localStatus = dbFirstRecordType(pdbEntry);
while(!localStatus) {
localStatus = dbPutRecordAttribute(pdbEntry,"RTYP",
@@ -316,7 +324,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
cleanup:
if(dbRecordsAbcSorted) {
ELLNODE *cur;
for(cur = ellFirst(&pdbbase->recordTypeList); cur; cur=ellNext(cur))
for(cur = ellFirst(&savedPdbbase->recordTypeList); cur; cur=ellNext(cur))
{
dbRecordType *rtype = CONTAINER(cur, dbRecordType, node);
@@ -332,6 +340,8 @@ cleanup:
if(my_buffer) free((void *)my_buffer);
my_buffer = NULL;
freeInputFileList();
if(fp)
fclose(fp);
return(status);
}
@@ -407,12 +417,12 @@ static void dbIncludePrint(void)
static void dbPathCmd(char *path)
{
dbPath(pdbbase,path);
dbPath(savedPdbbase,path);
}
static void dbAddPathCmd(char *path)
{
dbAddPath(pdbbase,path);
dbAddPath(savedPdbbase,path);
}
static void dbIncludeNew(char *filename)
@@ -422,7 +432,7 @@ static void dbIncludeNew(char *filename)
pinputFile = dbCalloc(1,sizeof(inputFile));
pinputFile->filename = macEnvExpand(filename);
pinputFile->path = dbOpenFile(pdbbase, pinputFile->filename, &fp);
pinputFile->path = dbOpenFile(savedPdbbase, pinputFile->filename, &fp);
if (!fp) {
epicsPrintf("Can't open include file \"%s\"\n", filename);
yyerror(NULL);
@@ -444,7 +454,7 @@ static void dbMenuHead(char *name)
yyerrorAbort("dbMenuHead: Menu name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->menuList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->menuList);
if(pgphentry) {
duplicate = TRUE;
return;
@@ -492,14 +502,14 @@ static void dbMenuBody(void)
}
if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
/* Add menu in sorted order */
pMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
pMenu = (dbMenu *)ellFirst(&savedPdbbase->menuList);
while(pMenu && strcmp(pMenu->name,pnewMenu->name) >0 )
pMenu = (dbMenu *)ellNext(&pMenu->node);
if(pMenu)
ellInsert(&pdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
ellInsert(&savedPdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
else
ellAdd(&pdbbase->menuList,&pnewMenu->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewMenu->name,&pdbbase->menuList);
ellAdd(&savedPdbbase->menuList,&pnewMenu->node);
pgphentry = gphAdd(savedPdbbase->pgpHash,pnewMenu->name,&savedPdbbase->menuList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
@@ -516,14 +526,14 @@ static void dbRecordtypeHead(char *name)
yyerrorAbort("dbRecordtypeHead: Recordtype name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->recordTypeList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->recordTypeList);
if(pgphentry) {
duplicate = TRUE;
return;
}
pdbRecordType = dbCalloc(1,sizeof(dbRecordType));
pdbRecordType->name = epicsStrDup(name);
if (pdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if (savedPdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if(ellCount(&tempList))
yyerrorAbort("dbRecordtypeHead tempList not empty");
allocTemp(pdbRecordType);
@@ -555,13 +565,13 @@ static short findOrAddGuiGroup(const char *name)
{
dbGuiGroup *pdbGuiGroup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->guiGroupList);
pgphentry = gphFind(savedPdbbase->pgpHash, name, &savedPdbbase->guiGroupList);
if (!pgphentry) {
pdbGuiGroup = dbCalloc(1,sizeof(dbGuiGroup));
pdbGuiGroup->name = epicsStrDup(name);
ellAdd(&pdbbase->guiGroupList, &pdbGuiGroup->node);
pdbGuiGroup->key = ellCount(&pdbbase->guiGroupList);
pgphentry = gphAdd(pdbbase->pgpHash, pdbGuiGroup->name, &pdbbase->guiGroupList);
ellAdd(&savedPdbbase->guiGroupList, &pdbGuiGroup->node);
pdbGuiGroup->key = ellCount(&savedPdbbase->guiGroupList);
pgphentry = gphAdd(savedPdbbase->pgpHash, pdbGuiGroup->name, &savedPdbbase->guiGroupList);
pgphentry->userPvt = pdbGuiGroup;
}
return ((dbGuiGroup *)pgphentry->userPvt)->key;
@@ -644,8 +654,8 @@ static void dbRecordtypeFieldItem(char *name,char *value)
return;
}
if(strcmp(name,"menu")==0) {
pdbFldDes->ftPvt = (dbMenu *)dbFindMenu(pdbbase,value);
if(!pdbbase->ignoreMissingMenus && !pdbFldDes->ftPvt)
pdbFldDes->ftPvt = (dbMenu *)dbFindMenu(savedPdbbase,value);
if(!savedPdbbase->ignoreMissingMenus && !pdbFldDes->ftPvt)
yyerrorAbort("menu not found");
return;
}
@@ -663,7 +673,7 @@ static void dbRecordtypeCdef(char *text) {
tempListNode *ptempListNode;
dbRecordType *pdbRecordType;
if (!pdbbase->loadCdefs || duplicate) return;
if (!savedPdbbase->loadCdefs || duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
@@ -772,14 +782,14 @@ static void dbRecordtypeBody(void)
ellInit(&pdbRecordType->attributeList);
ellInit(&pdbRecordType->recList);
ellInit(&pdbRecordType->devList);
pgphentry = gphAdd(pdbbase->pgpHash,pdbRecordType->name,
&pdbbase->recordTypeList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdbRecordType->name,
&savedPdbbase->recordTypeList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
pgphentry->userPvt = pdbRecordType;
}
ellAdd(&pdbbase->recordTypeList,&pdbRecordType->node);
ellAdd(&savedPdbbase->recordTypeList,&pdbRecordType->node);
}
static void dbDevice(char *recordtype,char *linktype,
@@ -789,7 +799,7 @@ static void dbDevice(char *recordtype,char *linktype,
dbRecordType *pdbRecordType;
GPHENTRY *pgphentry;
int i,link_type;
pgphentry = gphFind(pdbbase->pgpHash,recordtype,&pdbbase->recordTypeList);
pgphentry = gphFind(savedPdbbase->pgpHash,recordtype,&savedPdbbase->recordTypeList);
if(!pgphentry) {
epicsPrintf("Record type \"%s\" not found for device \"%s\"\n",
recordtype, choicestring);
@@ -810,7 +820,7 @@ static void dbDevice(char *recordtype,char *linktype,
return;
}
pdbRecordType = (dbRecordType *)pgphentry->userPvt;
pgphentry = gphFind(pdbbase->pgpHash,choicestring,&pdbRecordType->devList);
pgphentry = gphFind(savedPdbbase->pgpHash,choicestring,&pdbRecordType->devList);
if(pgphentry) {
return;
}
@@ -818,7 +828,7 @@ static void dbDevice(char *recordtype,char *linktype,
pdevSup->name = epicsStrDup(dsetname);
pdevSup->choice = epicsStrDup(choicestring);
pdevSup->link_type = link_type;
pgphentry = gphAdd(pdbbase->pgpHash,pdevSup->choice,&pdbRecordType->devList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdevSup->choice,&pdbRecordType->devList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
} else {
@@ -836,18 +846,18 @@ static void dbDriver(char *name)
yyerrorAbort("dbDriver: Driver name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->drvList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->drvList);
if(pgphentry) {
return;
}
pdrvSup = dbCalloc(1,sizeof(drvSup));
pdrvSup->name = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,pdrvSup->name,&pdbbase->drvList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pdrvSup->name,&savedPdbbase->drvList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pdrvSup;
ellAdd(&pdbbase->drvList,&pdrvSup->node);
ellAdd(&savedPdbbase->drvList,&pdrvSup->node);
}
static void dbLinkType(char *name, char *jlif_name)
@@ -855,19 +865,19 @@ static void dbLinkType(char *name, char *jlif_name)
linkSup *pLinkSup;
GPHENTRY *pgphentry;
pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->linkList);
pgphentry = gphFind(savedPdbbase->pgpHash, name, &savedPdbbase->linkList);
if (pgphentry) {
return;
}
pLinkSup = dbCalloc(1,sizeof(linkSup));
pLinkSup->name = epicsStrDup(name);
pLinkSup->jlif_name = epicsStrDup(jlif_name);
pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList);
pgphentry = gphAdd(savedPdbbase->pgpHash, pLinkSup->name, &savedPdbbase->linkList);
if (!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pLinkSup;
ellAdd(&pdbbase->linkList, &pLinkSup->node);
ellAdd(&savedPdbbase->linkList, &pLinkSup->node);
}
static void dbRegistrar(char *name)
@@ -879,18 +889,18 @@ static void dbRegistrar(char *name)
yyerrorAbort("dbRegistrar: Registrar name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->registrarList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->registrarList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->registrarList);
pgphentry = gphAdd(savedPdbbase->pgpHash,ptext->text,&savedPdbbase->registrarList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->registrarList,&ptext->node);
ellAdd(&savedPdbbase->registrarList,&ptext->node);
}
static void dbFunction(char *name)
@@ -902,18 +912,18 @@ static void dbFunction(char *name)
yyerrorAbort("dbFunction: Function name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->functionList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->functionList);
if(pgphentry) {
return;
}
ptext = dbCalloc(1,sizeof(dbText));
ptext->text = epicsStrDup(name);
pgphentry = gphAdd(pdbbase->pgpHash,ptext->text,&pdbbase->functionList);
pgphentry = gphAdd(savedPdbbase->pgpHash,ptext->text,&savedPdbbase->functionList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = ptext;
ellAdd(&pdbbase->functionList,&ptext->node);
ellAdd(&savedPdbbase->functionList,&ptext->node);
}
static void dbVariable(char *name, char *type)
@@ -925,19 +935,19 @@ static void dbVariable(char *name, char *type)
yyerrorAbort("dbVariable: Variable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->variableList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->variableList);
if(pgphentry) {
return;
}
pvar = dbCalloc(1,sizeof(dbVariableDef));
pvar->name = epicsStrDup(name);
pvar->type = epicsStrDup(type);
pgphentry = gphAdd(pdbbase->pgpHash,pvar->name,&pdbbase->variableList);
pgphentry = gphAdd(savedPdbbase->pgpHash,pvar->name,&savedPdbbase->variableList);
if(!pgphentry) {
yyerrorAbort("gphAdd failed");
}
pgphentry->userPvt = pvar;
ellAdd(&pdbbase->variableList,&pvar->node);
ellAdd(&savedPdbbase->variableList,&pvar->node);
}
static void dbBreakHead(char *name)
@@ -949,7 +959,7 @@ static void dbBreakHead(char *name)
yyerrorAbort("dbBreakHead: Breaktable name can't be empty");
return;
}
pgphentry = gphFind(pdbbase->pgpHash,name,&pdbbase->bptList);
pgphentry = gphFind(savedPdbbase->pgpHash,name,&savedPdbbase->bptList);
if(pgphentry) {
duplicate = TRUE;
return;
@@ -1033,17 +1043,17 @@ static void dbBreakBody(void)
/* Continue with last slope beyond the final point */
paBrkInt[number-1].slope = paBrkInt[number-2].slope;
/* Add brkTable in sorted order */
pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
pbrkTable = (brkTable *)ellFirst(&savedPdbbase->bptList);
while (pbrkTable) {
if (strcmp(pbrkTable->name, pnewbrkTable->name) > 0) {
ellInsert(&pdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
ellInsert(&savedPdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
(ELLNODE *)pnewbrkTable);
break;
}
pbrkTable = (brkTable *)ellNext(&pbrkTable->node);
}
if (!pbrkTable) ellAdd(&pdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(pdbbase->pgpHash,pnewbrkTable->name,&pdbbase->bptList);
if (!pbrkTable) ellAdd(&savedPdbbase->bptList, &pnewbrkTable->node);
pgphentry = gphAdd(savedPdbbase->pgpHash,pnewbrkTable->name,&savedPdbbase->bptList);
if (!pgphentry) {
yyerrorAbort("dbBreakBody: gphAdd failed");
return;
@@ -1094,7 +1104,7 @@ static void dbRecordHead(char *recordType, char *name, int visible)
if(dbRecordNameValidate(name))
return;
pdbentry = dbAllocEntry(pdbbase);
pdbentry = dbAllocEntry(savedPdbbase);
if (ellCount(&tempList))
yyerrorAbort("dbRecordHead: tempList not empty");
allocTemp(pdbentry);
@@ -1251,7 +1261,7 @@ static void dbAlias(char *name, char *alias)
if(dbRecordNameValidate(alias))
return;
dbInitEntry(pdbbase, pdbEntry);
dbInitEntry(savedPdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);

View File

@@ -9,6 +9,7 @@
\*************************************************************************/
#include "iocsh.h"
#include "errSymTbl.h"
#include "dbStaticIocRegister.h"
#include "dbStaticLib.h"
@@ -106,7 +107,13 @@ static void dbDumpDriverCallFunc(const iocshArgBuf *args)
/* dbDumpLink */
static const iocshArg * const dbDumpLinkArgs[] = { &argPdbbase};
static const iocshFuncDef dbDumpLinkFuncDef = {"dbDumpLink",1,dbDumpLinkArgs};
static const iocshFuncDef dbDumpLinkFuncDef = {
"dbDumpLink",
1,
dbDumpLinkArgs,
"Dump list of registered links\n"
"Example: dbDumpLink pdbbase\n",
};
static void dbDumpLinkCallFunc(const iocshArgBuf *args)
{
dbDumpLink(*iocshPpdbbase);
@@ -147,7 +154,13 @@ static void dbDumpVariableCallFunc(const iocshArgBuf *args)
static const iocshArg dbDumpBreaktableArg1 = { "tableName",iocshArgString};
static const iocshArg * const dbDumpBreaktableArgs[] =
{&argPdbbase,&dbDumpBreaktableArg1};
static const iocshFuncDef dbDumpBreaktableFuncDef = {"dbDumpBreaktable",2,dbDumpBreaktableArgs};
static const iocshFuncDef dbDumpBreaktableFuncDef = {
"dbDumpBreaktable",
2,
dbDumpBreaktableArgs,
"Dump the given break table\n"
"Example: dbDumpBreaktable pdbbase typeKdegC\n",
};
static void dbDumpBreaktableCallFunc(const iocshArgBuf *args)
{
dbDumpBreaktable(*iocshPpdbbase,args[1].sval);
@@ -157,7 +170,14 @@ static void dbDumpBreaktableCallFunc(const iocshArgBuf *args)
static const iocshArg dbPvdDumpArg1 = { "verbose",iocshArgInt};
static const iocshArg * const dbPvdDumpArgs[] = {
&argPdbbase,&dbPvdDumpArg1};
static const iocshFuncDef dbPvdDumpFuncDef = {"dbPvdDump",2,dbPvdDumpArgs};
static const iocshFuncDef dbPvdDumpFuncDef = {
"dbPvdDump",
2,
dbPvdDumpArgs,
"Dump the various buckets of the process variable directory.\n"
"If verbose is greater than 0, also print the process variables in each bucket.\n"
"Example: dbPvdDump pdbbase 1\n",
};
static void dbPvdDumpCallFunc(const iocshArgBuf *args)
{
dbPvdDump(*iocshPpdbbase,args[1].ival);
@@ -167,7 +187,16 @@ static void dbPvdDumpCallFunc(const iocshArgBuf *args)
static const iocshArg dbPvdTableSizeArg0 = { "size",iocshArgInt};
static const iocshArg * const dbPvdTableSizeArgs[1] =
{&dbPvdTableSizeArg0};
static const iocshFuncDef dbPvdTableSizeFuncDef = {"dbPvdTableSize",1,dbPvdTableSizeArgs};
static const iocshFuncDef dbPvdTableSizeFuncDef = {
"dbPvdTableSize",
1,
dbPvdTableSizeArgs,
"Change the number of buckets in the process variable directory.\n\n"
"The process variable directory size should be set before loading the database.\n"
"The size of the process variable directory can automatically grow.\n"
"The size must be a power of 2.\n\n"
"Example: dbPvdTableSize 1024\n",
};
static void dbPvdTableSizeCallFunc(const iocshArgBuf *args)
{
dbPvdTableSize(args[0].ival);
@@ -175,12 +204,54 @@ static void dbPvdTableSizeCallFunc(const iocshArgBuf *args)
/* dbReportDeviceConfig */
static const iocshArg * const dbReportDeviceConfigArgs[] = {&argPdbbase};
static const iocshFuncDef dbReportDeviceConfigFuncDef = {"dbReportDeviceConfig",1,dbReportDeviceConfigArgs};
static const iocshFuncDef dbReportDeviceConfigFuncDef = {
"dbReportDeviceConfig",
1,
dbReportDeviceConfigArgs,
"Print the link type, link value, device type, record name,\n"
"and linearisation info (if applicable),\n"
"for every record using a specific device type.\n\n"
"Example: dbReportDeviceConfig pdbbase\n",
};
static void dbReportDeviceConfigCallFunc(const iocshArgBuf *args)
{
dbReportDeviceConfig(*iocshPpdbbase,stdout);
}
static const iocshArg dbCreateAliasArg0 = { "record",iocshArgStringRecord};
static const iocshArg dbCreateAliasArg1 = { "alias",iocshArgStringRecord};
static const iocshArg * const dbCreateAliasArgs[] = {&argPdbbase,&dbCreateAliasArg0, &dbCreateAliasArg1};
static const iocshFuncDef dbCreateAliasFuncDef = {
"dbCreateAlias",
3,
dbCreateAliasArgs,
"Add a new record alias.\n"
"\n"
"Example: dbCreateAlias pdbbase record:name new:alias\n",
};
static void dbCreateAliasCallFunc(const iocshArgBuf *args)
{
DBENTRY ent;
long status;
dbInitEntry(*iocshPpdbbase, &ent);
if(!args[1].sval || !args[2].sval) {
status = S_dbLib_recNotFound;
} else {
status = dbFindRecord(&ent, args[1].sval);
if(!status) {
status = dbCreateAlias(&ent, args[2].sval);
}
}
dbFinishEntry(&ent);
if(status) {
fprintf(stderr, "Error: %ld %s\n", status, errSymMsg(status));
iocshSetError(1);
}
}
void dbStaticIocRegister(void)
{
iocshRegister(&dbDumpPathFuncDef, dbDumpPathCallFunc);
@@ -198,4 +269,5 @@ void dbStaticIocRegister(void)
iocshRegister(&dbPvdDumpFuncDef, dbPvdDumpCallFunc);
iocshRegister(&dbPvdTableSizeFuncDef,dbPvdTableSizeCallFunc);
iocshRegister(&dbReportDeviceConfigFuncDef, dbReportDeviceConfigCallFunc);
iocshRegister(&dbCreateAliasFuncDef, dbCreateAliasCallFunc);
}

View File

@@ -441,6 +441,9 @@ void dbFreeBase(dbBase *pdbbase)
DBENTRY dbentry;
long status;
if(!pdbbase)
return;
dbInitEntry(pdbbase,&dbentry);
status = dbFirstRecordType(&dbentry);
while(!status) {
@@ -1649,6 +1652,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
dbRecordNode *pnewnode;
DBENTRY tempEntry;
PVDENTRY *ppvd;
long status;
if (!precordType)
return S_dbLib_recordTypeNotFound;
@@ -1661,9 +1665,10 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
return S_dbLib_recNotFound;
dbInitEntry(pdbentry->pdbbase, &tempEntry);
if (!dbFindRecord(&tempEntry, alias))
return S_dbLib_recExists;
status = dbFindRecord(&tempEntry, alias);
dbFinishEntry(&tempEntry);
if (!status)
return S_dbLib_recExists;
pnewnode = dbCalloc(1, sizeof(dbRecordNode));
pnewnode->recordname = epicsStrDup(alias);
@@ -1673,15 +1678,16 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
precnode->flags |= DBRN_FLAGS_HASALIAS;
ellInit(&pnewnode->infoList);
ellAdd(&precordType->recList, &pnewnode->node);
precordType->no_aliases++;
ppvd = dbPvdAdd(pdbentry->pdbbase, precordType, pnewnode);
if (!ppvd) {
errMessage(-1, "dbCreateAlias: Add to PVD failed");
free(pnewnode);
return -1;
}
ellAdd(&precordType->recList, &pnewnode->node);
precordType->no_aliases++;
return 0;
}
@@ -2038,13 +2044,17 @@ char *dbGetStringNum(DBENTRY *pdbentry)
{
dbFldDes *pflddes = pdbentry->pflddes;
void *pfield = pdbentry->pfield;
char *message;
char *message = getpMessage(pdbentry);
unsigned char cvttype;
if (!pfield) {
dbMsgCpy(pdbentry, "Field not found");
return message;
}
/* the following assumes that messagesize is large enough
* to hold the base 10 encoded value of a 32-bit integer.
*/
message = getpMessage(pdbentry);
cvttype = pflddes->base;
switch (pflddes->field_type) {
case DBF_CHAR:
@@ -2106,37 +2116,34 @@ char *dbGetStringNum(DBENTRY *pdbentry)
{
dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt;
epicsEnum16 choice_ind;
char *pchoice;
if (!pfield) {
dbMsgCpy(pdbentry, "Field not found");
return message;
}
choice_ind = *((epicsEnum16 *) pdbentry->pfield);
if (!pdbMenu || choice_ind < 0 || choice_ind >= pdbMenu->nChoice)
if (!pdbMenu)
return NULL;
pchoice = pdbMenu->papChoiceValue[choice_ind];
dbMsgCpy(pdbentry, pchoice);
choice_ind = *((epicsEnum16 *) pdbentry->pfield);
if (choice_ind >= pdbMenu->nChoice) {
dbMsgPrint(pdbentry, "%u", choice_ind);
}
else {
dbMsgCpy(pdbentry, pdbMenu->papChoiceValue[choice_ind]);
}
}
break;
case DBF_DEVICE:
{
dbDeviceMenu *pdbDeviceMenu;
dbDeviceMenu *pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
epicsEnum16 choice_ind;
char *pchoice;
if (!pfield) {
dbMsgCpy(pdbentry, "Field not found");
return message;
if (!pdbDeviceMenu) {
dbMsgCpy(pdbentry, "");
break;
}
pdbDeviceMenu = dbGetDeviceMenu(pdbentry);
if (!pdbDeviceMenu)
return NULL;
choice_ind = *((epicsEnum16 *) pdbentry->pfield);
if (choice_ind<0 || choice_ind>=pdbDeviceMenu->nChoice)
if (choice_ind>=pdbDeviceMenu->nChoice)
return NULL;
pchoice = pdbDeviceMenu->papChoice[choice_ind];
dbMsgCpy(pdbentry, pchoice);
dbMsgCpy(pdbentry, pdbDeviceMenu->papChoice[choice_ind]);
}
break;
default:
@@ -2275,7 +2282,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
}
/* generalized extraction of ID character and integer pairs (eg. "#C15 S14") */
ret = sscanf(pinfo->target, "# %c%d %c%d %c%d %c%d %c%d %c",
ret = sscanf(pinfo->target, "# %c%i %c%i %c%i %c%i %c%i %c",
&pinfo->hwid[0], &pinfo->hwnums[0],
&pinfo->hwid[1], &pinfo->hwnums[1],
&pinfo->hwid[2], &pinfo->hwnums[2],
@@ -3293,11 +3300,11 @@ void dbDumpRecordType(DBBASE *pdbbase,const char *recordTypeName)
printf("name(%s) no_fields(%hd) no_prompt(%hd) no_links(%hd)\n",
pdbRecordType->name,pdbRecordType->no_fields,
pdbRecordType->no_prompt,pdbRecordType->no_links);
printf("index name\tsortind sortname\n");
printf("index offset size name\tsortind sortname\n");
for(i=0; i<pdbRecordType->no_fields; i++) {
pdbFldDes = pdbRecordType->papFldDes[i];
printf("%5d %s\t%7d %s\n",
i,pdbFldDes->name,
printf("%5d %6u %4u %s\t%7d %s\n",
i,pdbFldDes->offset,pdbFldDes->size, pdbFldDes->name,
pdbRecordType->sortFldInd[i],pdbRecordType->papsortFldName[i]);
}
printf("link_ind ");

View File

@@ -57,8 +57,26 @@ DBCORE_API void dbCopyEntryContents(DBENTRY *pfrom,
DBCORE_API extern int dbBptNotMonotonic;
/** \brief Open .dbd or .db file and read definitions.
* \param ppdbbase The database. Typically the "pdbbase" global
* \param filename Filename to read/search. May be absolute, or relative.
* \param path If !NULL, search path when filename is relative, of for 'include' statements.
* Split by ':' or ';' (cf. OSI_PATH_LIST_SEPARATOR)
* \param substitutions If !NULL, macro definitions like "NAME=VAL,OTHER=SOME"
* \return 0 on success
*/
DBCORE_API long dbReadDatabase(DBBASE **ppdbbase,
const char *filename, const char *path, const char *substitutions);
/** \brief Read definitions from already opened .dbd or .db file.
* \param ppdbbase The database. Typically the "&pdbbase" global
* \param fp FILE* from which to read definitions. Will always be fclose()'d
* \param path If !NULL, search path when filename is relative, of for 'include' statements.
* Split by ':' or ';' (cf. OSI_PATH_LIST_SEPARATOR)
* \param substitutions If !NULL, macro definitions like "NAME=VAL,OTHER=SOME"
* \return 0 on success
*
* \note This function will always close the provided 'fp'.
*/
DBCORE_API long dbReadDatabaseFP(DBBASE **ppdbbase,
FILE *fp, const char *path, const char *substitutions);
DBCORE_API long dbPath(DBBASE *pdbbase, const char *path);

View File

@@ -16,6 +16,9 @@
#ifndef INCdbStaticPvth
#define INCdbStaticPvth 1
#include "dbCoreAPI.h"
#include "dbStaticLib.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -36,10 +39,15 @@ char *dbRecordName(DBENTRY *pdbentry);
char *dbGetStringNum(DBENTRY *pdbentry);
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3);
void dbMsgPrint(
DBENTRY *pdbentry, EPICS_PRINTF_FMT(const char *fmt), ...
) EPICS_PRINTF_STYLE(2,3);
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring);
DBCORE_API
const char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp);
struct jlink;
typedef struct dbLinkInfo {
@@ -109,6 +117,9 @@ PVDENTRY *dbPvdAdd(DBBASE *pdbbase,dbRecordType *precordType,dbRecordNode *precn
void dbPvdDelete(DBBASE *pdbbase,dbRecordNode *precnode);
void dbPvdFreeMem(DBBASE *pdbbase);
DBCORE_API
char** dbCompleteRecord(const char *word);
#ifdef __cplusplus
}
#endif

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