diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 615332f19..7d6c11b6b 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -79,16 +79,20 @@ CPP = cl -nologo -C -E # Configure OS vendor C++ compiler # -# __STDC__=0 gives us both: -# 1) define STDC for code (pretend ANSI conformance) -# 2) set it to 0 to use MS C "extensions" (open for _open etc.) -# because MS uses: if __STDC__ ... disable many nice things -# # -EHsc - generate code for exceptions # -GR - generate code for run time type identification # CCC = cl -EHsc -GR -CODE_CPPFLAGS += -nologo -D__STDC__=0 + +# Other compiler flags, used for CPP, C and C++ +# +# -FC - Show absolute path of source file in diagnostics +# -D__STDC__=0 gives us both: +# 1) define STDC for code (pretend ANSI conformance) +# 2) set it to 0 to use MS C "extensions" (open for _open etc.) +# because MS uses: if __STDC__ ... disable many nice things +# +CODE_CPPFLAGS += -nologo -FC -D__STDC__=0 CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE diff --git a/documentation/README.1st b/documentation/README.1st index aecb2d637..042cede60 100644 --- a/documentation/README.1st +++ b/documentation/README.1st @@ -67,8 +67,9 @@ Software requirements GNU make - You must use GNU make, gnumake, for any EPICS builds. Set your path so - that a gnumake version 3.81 or later is available. + You must use the GNU version of make for EPICS builds, and we now + recommend version 4.1 or later (version 3.82 may work on Linux, but + doesn't on Windows). Perl You must have Perl version 5.8.1 or later installed. The EPICS @@ -99,20 +100,17 @@ RTEMS For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or - later. + 4.10. The newer 4.11 or 5.x releases are not supported yet. - GNU readline or Tecla library - GNU readline and Tecla libraries can be used by the IOC shell to provide - command line editing and command line history recall and edit. GNU - readline (or Tecla library) must be installed on your target system when - COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target. EPICS - (EPICS shell) is the default specified in CONFIG_COMMON. A READLINE - override is defined for linux-x86 in the EPICS distribution. Comment out - COMMANDLINE_LIBRARY=READLINE in - configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed - on linux-x86. Command-line editing and history will then be those - supplied by the os. On vxWorks the ledLib command-line input library is - used instead. + Command-line editing libraries + GNU readline or other OS-specific libraries can be used by the IOC shell + to provide command line editing and history recall. The default setting + is different for each OS. On Linux the default is to use READLINE since + most distributions include it. On MacOS the default is also READLINE + since Apple provides a compatible library, although it isn't GNU. On + RTEMS we support GNU readline and Tecla, although the default is to use + neither since these have to be added to the RTEMS installation + separately. On vxWorks we support the built-in ledLib library. Host system storage requirements diff --git a/documentation/README.html b/documentation/README.html index d14124a7d..4ab314d05 100644 --- a/documentation/README.html +++ b/documentation/README.html @@ -72,8 +72,8 @@
GNU make
- You must use GNU make, gnumake, for any EPICS builds. Set your path - so that a gnumake version 3.81 or later is available. + You must use the GNU version of make for EPICS builds, and we now recommend + version 4.1 or later (version 3.82 may work on Linux, but doesn't on Windows).Perl
You must have Perl version 5.8.1 or later installed. The EPICS configuration @@ -103,20 +103,20 @@ about configuring your vxWorks operating system for use with EPICS.RTEMS
+ For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or 4.10. The + newer 4.11 or 5.x releases are not supported yet. + +
- For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.Command-line editing libraries
-
+ + GNU readline or other OS-specific libraries can be used by the IOC shell to + provide command line editing and history recall. The default setting is + different for each OS. On Linux the default is to use READLINE since most + distributions include it. On MacOS the default is also READLINE since Apple + provides a compatible library, although it isn't GNU. On RTEMS we support GNU + readline and Tecla, although the default is to use neither since these have to + be added to the RTEMS installation separately. On vxWorks we support the + built-in ledLib library.GNU readline or Tecla library
- GNU readline and Tecla libraries can be used by the IOC shell to - provide command line editing and command line history recall and edit. - GNU readline (or Tecla library) must be installed on your target system - when COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target. - EPICS (EPICS shell) is the default specified in CONFIG_COMMON. A - READLINE override is defined for linux-x86 in the EPICS distribution. - Comment out COMMANDLINE_LIBRARY=READLINE in - configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed - on linux-x86. Command-line editing and history will then be those - supplied by the os. On vxWorks the ledLib command-line input library is - used instead.
The VAL fields of mbbiDirect and mbboDirect records have +been extended from DBF_USHORT (16 bit) to DBF_LONG (32 bit). +New bit fields B10...B1F have been added.
+ +Device support which accesses the bit fields can test if the macro +mbbiDirectRecord1BF or mbboDirectRecord1BF is +defined. Device support which only accesses RVAL needs no modification.
+The epicsReadline refactoring work described below unfortunately disabled the @@ -176,6 +188,27 @@ preprocessor macro):
#endif +If the code uses the old db_access.h types (probably because it's calling +Channel Access APIs) then it will have to test against the EPICS version number +instead, like this:
+ +++#include <epicsVersion.h> + +#ifndef VERSION_INT +# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P)) +#endif +#ifndef EPICS_VERSION_INT +# define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL) +#endif + +#if EPICS_VERSION_INT >= VERSION_INT(3,16,1,0) + /* Code where Base has INT64 support */ +#else + /* Code for older versions */ +#endif +
Channel Access does not (and probably never will) directly support 64-bit integer types, so the new field types are presented to the CA server as DBF_DOUBLE values. This means that field values larger than 2^52 @@ -343,15 +376,15 @@ to implement the link APIs, so will work properly after these conversions:
link type, i.e. change this code:
- if (prec->siml.type == CONSTANT) {
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
+ if (prec->siml.type == CONSTANT) {
+ recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);
}
into this:
- recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm); + recGblInitConstantLink(&prec->siml, DBF_USHORT, &prec->simm);Note that recGblInitConstantLink() still returns TRUE if the field was @@ -364,20 +397,20 @@ or undefined links, FALSE for links whose dbGetLink() routine may return different values on different calls. For example this:
- if (prec->dol.type != CONSTANT) + if (prec->dol.type != CONSTANT)should become this:
- if (!dbLinkIsConstant(&prec->dol)) + if (!dbLinkIsConstant(&prec->dol))When the converted software is also required to build against older versions of Base, this macro definition may be useful:
-#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT) +#define dbLinkIsConstant(lnk) ((lnk)->type == CONSTANT)@@ -385,7 +418,7 @@ Base, this macro definition may be useful: link has been resolved as a CA link using code such as
- if (prec->inp.type == CA_LINK) + if (prec->inp.type == CA_LINK)will still compile and run, but will only work properly with the old CA link @@ -395,7 +428,7 @@ examine or modify data inside the link. After conversion the above line would probably become:
- if (dbLinkIsVolatile(&prec->inp)) + if (dbLinkIsVolatile(&prec->inp))A volatile link is one like a Channel Access link which may disconnect and @@ -405,7 +438,7 @@ same state they started in. For compatibility when building against older versions of Base, this macro definition may be useful:
-#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK) +#define dbLinkIsVolatile(lnk) ((lnk)->type == CA_LINK)@@ -710,6 +743,14 @@ of its CALLBACK objects. +
Changing from numeric to named soft events introduced an incompatibility +when a numeric event 1-255 is converted from a DOUBLE, e.g. from a calc record. +The post_event() API is not marked deprecated any more. + +
Also scanpel has been modified to accept a glob pattern for
+event name filtering and to show events with no connected records as well.
Added a new OS-independent typedef for multicast socket options, and a test @@ -728,6 +769,43 @@ tells git to ignore all configure/*.local files.
+The following launchpad bugs have fixes included:
+ +Removed the settings for 2017; fixed the hour of the change for MET.
+ +Initialize the first time-stamp from the first monitor, not the client-side +current time in this configuration.
+ +Windows builds using Visual Studio 2015 and later now use the -FS +compiler option to allow parallel builds to work properly.
+ +We now give the -FC option to tell the compiler to print absolute +paths for source files in diagnostic messages.
+The Posix implementation of epicsEventWaitWithTimeout() was limiting the diff --git a/modules/ca/src/client/CAref.html b/modules/ca/src/client/CAref.html index 196635e6c..741716116 100644 --- a/modules/ca/src/client/CAref.html +++ b/modules/ca/src/client/CAref.html @@ -1015,7 +1015,7 @@ d:/user/epics/base-3.15/lib/win32-x86/Com.lib
acctst <PV name> [progress logging level] [channel duplication count] +acctst <PV name> [progress logging level] [channel duplication count] [test repetition count] [enable preemptive callback]Description
@@ -2085,7 +2085,7 @@ example, be beneficial when tuning an archiver installation.Significant performance gains can be realized when the CA client library doesn't wait for a response to return from the server after each request. All requests which require interaction with a CA server are accumulated (buffered) -and not forwarded to the IOC until one of
-ca_flush_io(), +and not forwarded to the IOC until one ofca_flush_io(),ca_pend_io(),ca_pend_event(), orca_sg_block()are called allowing several operations to be efficiently sent over the network together. Any process variable values written @@ -2109,16 +2109,16 @@ shouldn't test the success of a CA function call by checking to see if the returned value is zero as is the UNIX convention. Below are several methods to test CA function returns. Seeca_signal()andSEVCHK()for more information on this topic.status = ca_XXXX(); -SEVCHK( status, "ca_XXXX() returned failure status"); +status = ca_XXXX(); +SEVCHK( status, "ca_XXXX() returned failure status"); -if ( status & CA_M_SUCCESS ) { - printf ( "The requested ca_XXXX() operation didn't complete successfully"); -} +if ( status & CA_M_SUCCESS ) { + printf ( "The requested ca_XXXX() operation didn't complete successfully"); +} -if ( status != ECA_NORMAL ) { +if ( status != ECA_NORMAL ) { printf("The requested ca_XXXX() operation didn't complete successfully because \"%s\"\n", - ca_message ( status ) ); + ca_message ( status ) ); }Channel Access Data Types
@@ -2291,7 +2291,7 @@ int main ( int argc, char ** argv ) unsigned nBytes; unsigned elementCount; char timeString[32]; - unsigned i; + unsigned i; chid chan; double sum; int status; @@ -2334,7 +2334,7 @@ int main ( int argc, char ** argv ) epicsTimeToStrftime ( timeString, sizeof ( timeString ), "%a %b %d %Y %H:%M:%S.%f", & pTD->stamp ); - printf ( "The sum of elements in %s at %s was %f\n", + printf ( "The sum of elements in %s at %s was %f\n", argv[1], timeString, sum ); ca_clear_channel ( chan ); @@ -2365,7 +2365,7 @@ executing within the user's callback function.typedef struct event_handler_args { void *usr; /* user argument supplied with request */ chanId chid; /* channel id */ - long type; /* the type of the item returned */ + long type; /* the type of the item returned */ long count; /* the element count of the item returned */ const void *dbr; /* a pointer to the item returned */ int status; /* ECA_XXX status of the requested op from the server */ @@ -2388,7 +2388,7 @@ attached to the request, an exception handler is executed in the client. The default exception handler prints a message on the console and exits if the exception condition is severe. Certain internal exceptions within the CA client library, and failures detected by the SEVCHK macro may also cause the exception -handler to be invoked. To modify this behavior see +handler to be invoked. To modify this behavior seeca_add_exception_event().Server and Client Share the Same Address Space on The Same @@ -2680,6 +2680,14 @@ automatically released by the system when the process exits and vxWorks or RTEMS no cleanup occurs unless the application calls
ca_context_destroy(). +Note: This operation blocks until any user callbacks for any channel +created in the current context have run to completion. If callbacks take a +lock (mutex) then it is the user's responsibility to ensure that this lock +is not held when
+ca_clear_context()is called, otherwise a +deadlock may ensue. (See also +ca_clear_channel()and +ca_clear_subscription().)Returns
ECA_NORMAL - Normal successful completion
@@ -2825,6 +2833,12 @@ efficiently sent over the network in one message. clearing a channel does shutdown and reclaim any channel state change event subscriptions (monitors) registered with the channel. +Note: This operation blocks until any user callbacks for this channel +have run to completion. If callbacks take a lock (mutex) then it is the +user's responsibility to ensure that this lock is not held when +
+ca_clear_channel()is called, otherwise a deadlock may ensue. +(See alsoca_clear_subscription().)Arguments
- @@ -2839,16 +2853,16 @@ subscriptions (monitors) registered with the channel.
CHID
ca_put()#include <cadef.h> -int ca_put ( chtype TYPE, - chid CHID, void *PVALUE ); -int ca_array_put ( chtype TYPE, unsigned long COUNT, +int ca_put ( chtype TYPE, + chid CHID, void *PVALUE ); +int ca_array_put ( chtype TYPE, unsigned long COUNT, chid CHID, const void *PVALUE); typedef void ( caEventCallBackFunc ) (struct event_handler_args); -int ca_put_callback ( chtype TYPE, - chid CHID, const void *PVALUE, - caEventCallBackFunc PFUNC, void *USERARG ); -int ca_array_put_callback ( chtype TYPE, unsigned long COUNT, - chid CHID, const void *PVALUE, +int ca_put_callback ( chtype TYPE, + chid CHID, const void *PVALUE, + caEventCallBackFunc PFUNC, void *USERARG ); +int ca_array_put_callback ( chtype TYPE, unsigned long COUNT, + chid CHID, const void *PVALUE, caEventCallBackFunc PFUNC, void *USERARG );Description
@@ -3075,7 +3089,7 @@ when a CA get request is initiated. typedef void ( caEventCallBackFunc ) (struct event_handler_args); int ca_create_subscription ( chtype TYPE, unsigned long COUNT, chid CHID, unsigned long MASK, - caEventCallBackFunc USERFUNC, void *USERARG, + caEventCallBackFunc USERFUNC, void *USERARG, evid *PEVID );Description
@@ -3159,7 +3173,7 @@ indicating the current state of the channel.
MASKca_flush_io(), c
ca_pend_event(), or ca_sg_block() are called. This allows several requests to be
efficiently sent together in one message.
+Note: This operation blocks until any user callbacks for this channel
+have run to completion. If callbacks take a lock (mutex) then it is the
+user's responsibility to ensure that this lock is not held when
+ca_clear_subscription() is called, otherwise a deadlock may
+ensue. (See also ca_clear_channel().)
+
Arguments
- EVID
@@ -3370,7 +3391,7 @@ becomes full.
ca_signal()
#include <cadef.h>
-int ca_signal ( long CA_STATUS, const char * CONTEXT_STRING );
+int ca_signal ( long CA_STATUS, const char * CONTEXT_STRING );
void SEVCHK( CA_STATUS, CONTEXT_STRING );
Description
@@ -3387,7 +3408,7 @@ recommended error handler for simple applications which do not wish to write
code testing the status returned from each channel access call.
Examples
-status = ca_context_create (...);
+status = ca_context_create (...);
SEVCHK ( status, "Unable to create a CA client context" );
If the application only wishes to print the message associated with an error
@@ -3411,7 +3432,7 @@ this purpose.
ca_add_exception_event()
-#include <cadef.h>
+#include <cadef.h>
typedef void (*pCallback) ( struct exception_handler_args HANDLERARGS );
int ca_add_exception_event ( pCallback USERFUNC, void *USERARG );
@@ -3620,7 +3641,7 @@ specified channel.
PFUNC
- Pointer to a user supplied callback function. A null pointer uninstalls
the current handler. The following arguments are passed by value
- to the supplied callback handler.
+ to the supplied callback handler.
typedef struct ca_access_rights {
unsigned read_access:1;
unsigned write_access:1;
@@ -3960,8 +3981,8 @@ type.
prints diagnostics to standard out.
Examples
-void ca_test_event ();
-status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
+void ca_test_event ();
+status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL );
SEVCHK ( status, .... );
See Also
@@ -3995,8 +4016,8 @@ outstanding within them at any given time.
Examples
-CA_SYNC_GID gid;
-status = ca_sg_create ( &gid );
+CA_SYNC_GID gid;
+status = ca_sg_create ( &gid );
SEVCHK ( status, Sync group create failed );
Returns
@@ -4034,8 +4055,8 @@ int ca_sg_delete ( CA_SYNC_GID GID );
Examples
-CA_SYNC_GID gid;
-status = ca_sg_delete ( gid );
+CA_SYNC_GID gid;
+status = ca_sg_delete ( gid );
SEVCHK ( status, Sync group delete failed );
Returns
@@ -4146,7 +4167,7 @@ will not block unless additional subsequent requests are made.
Examples
-CA_SYNC_GID gid;
+CA_SYNC_GID gid;
status = ca_sg_reset(gid);
Returns
@@ -4159,7 +4180,7 @@ status = ca_sg_reset(gid);
#include <cadef.h>
int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
chid CHID, void *PVALUE );
-int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
+int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
unsigned long COUNT, chid CHID, void *PVALUE );
Write a value, or array of values, to a channel and increment the outstanding
@@ -4300,7 +4321,7 @@ reissued.
ca_client_status()
int ca_client_status ( unsigned level );
-int ca_context_status ( struct ca_client_context *CONTEXT,
+int ca_context_status ( struct ca_client_context *CONTEXT,
unsigned LEVEL );
Description
diff --git a/modules/database/src/ioc/db/callback.c b/modules/database/src/ioc/db/callback.c
index 058dc8d8c..ae074141c 100644
--- a/modules/database/src/ioc/db/callback.c
+++ b/modules/database/src/ioc/db/callback.c
@@ -45,6 +45,7 @@
#include "epicsExport.h"
#include "link.h"
#include "recSup.h"
+#include "dbUnitTest.h" /* for testSyncCallback() */
static int callbackQueueSize = 2000;
@@ -352,3 +353,86 @@ void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback,
callbackSetProcess(pcallback, Priority, pRec);
callbackRequestDelayed(pcallback, seconds);
}
+
+/* Sync. process of testSyncCallback()
+ *
+ * 1. For each priority, make a call to callbackRequest() for each worker.
+ * 2. Wait until all callbacks are concurrently being executed
+ * 3. Last worker to begin executing signals success and begins waking up other workers
+ * 4. Last worker to wake signals testSyncCallback() to complete
+ */
+typedef struct {
+ epicsEventId wait_phase2, wait_phase4;
+ int nphase2, nphase3;
+ epicsCallback cb;
+} sync_helper;
+
+static void sync_callback(epicsCallback *cb)
+{
+ sync_helper *helper;
+ callbackGetUser(helper, cb);
+
+ testGlobalLock();
+
+ assert(helper->nphase2 > 0);
+ if(--helper->nphase2!=0) {
+ /* we are _not_ the last to start. */
+ testGlobalUnlock();
+ epicsEventMustWait(helper->wait_phase2);
+ testGlobalLock();
+ }
+
+ /* we are either the last to start, or have been
+ * woken by the same and must pass the wakeup along
+ */
+ epicsEventMustTrigger(helper->wait_phase2);
+
+ assert(helper->nphase2 == 0);
+ assert(helper->nphase3 > 0);
+
+ if(--helper->nphase3==0) {
+ /* we are the last to wake up. wake up testSyncCallback() */
+ epicsEventMustTrigger(helper->wait_phase4);
+ }
+
+ testGlobalUnlock();
+}
+
+void testSyncCallback(void)
+{
+ sync_helper helper[NUM_CALLBACK_PRIORITIES];
+ unsigned i;
+
+ testDiag("Begin testSyncCallback()");
+
+ for(i=0; iupper_alarm_limit = (epicsInt32) ald.upper_alarm_limit;
- pal->upper_warning_limit = (epicsInt32) ald.upper_warning_limit;
- pal->lower_warning_limit = (epicsInt32) ald.lower_warning_limit;
- pal->lower_alarm_limit = (epicsInt32) ald.lower_alarm_limit;
+ pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ?
+ (epicsInt32) ald.upper_alarm_limit : 0;
+ pal->upper_warning_limit = finite(ald.upper_warning_limit) ?
+ (epicsInt32) ald.upper_warning_limit : 0;
+ pal->lower_warning_limit = finite(ald.lower_warning_limit) ?
+ (epicsInt32) ald.lower_warning_limit : 0;
+ pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ?
+ (epicsInt32) ald.lower_alarm_limit : 0;
if (no_data)
*options ^= DBR_AL_LONG; /*Turn off option*/
diff --git a/modules/database/src/ioc/db/dbScan.c b/modules/database/src/ioc/db/dbScan.c
index 9f7df4c17..e5c78fea1 100644
--- a/modules/database/src/ioc/db/dbScan.c
+++ b/modules/database/src/ioc/db/dbScan.c
@@ -6,7 +6,7 @@
* Copyright (c) 2013 Helmholtz-Zentrum Berlin
* für Materialien und Energie GmbH.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* dbScan.c */
/* tasks and subroutines to scan the database */
@@ -109,8 +109,8 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = {
typedef struct event_list {
CALLBACK callback[NUM_CALLBACK_PRIORITIES];
scan_list scan_list[NUM_CALLBACK_PRIORITIES];
- struct event_list *next;
- char event_name[MAX_STRING_SIZE];
+ struct event_list *next;
+ char eventname[1]; /* actually arbitrary size */
} event_list;
static event_list * volatile pevent_list[256];
static epicsMutexId event_lock;
@@ -247,11 +247,6 @@ void scanAdd(struct dbCommon *precord)
event_list *pel;
eventname = precord->evnt;
- if (strlen(eventname) >= MAX_STRING_SIZE) {
- recGblRecordError(S_db_badField, (void *)precord,
- "scanAdd: too long EVNT value");
- return;
- }
prio = precord->prio;
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
recGblRecordError(-1, (void *)precord,
@@ -315,24 +310,17 @@ void scanDelete(struct dbCommon *precord)
recGblRecordError(-1, (void *)precord,
"scanDelete detected illegal SCAN value");
} else if (scan == menuScanEvent) {
- char* eventname;
int prio;
event_list *pel;
scan_list *psl = 0;
- eventname = precord->evnt;
prio = precord->prio;
if (prio < 0 || prio >= NUM_CALLBACK_PRIORITIES) {
recGblRecordError(-1, (void *)precord,
"scanDelete detected illegal PRIO field");
return;
}
- do /* multithreading: make sure pel is consistent */
- pel = pevent_list[0];
- while (pel != pevent_list[0]);
- for (; pel; pel=pel->next) {
- if (strcmp(pel->event_name, eventname) == 0) break;
- }
+ pel = eventNameToHandle(precord->evnt);
if (pel && (psl = &pel->scan_list[prio]))
deleteFromList(precord, psl);
} else if (scan == menuScanI_O_Intr) {
@@ -420,14 +408,12 @@ int scanpel(const char* eventname) /* print event list */
int prio;
event_list *pel;
- do /* multithreading: make sure pel is consistent */
- pel = pevent_list[0];
- while (pel != pevent_list[0]);
- for (; pel; pel = pel->next) {
- if (!eventname || strcmp(pel->event_name, eventname) == 0) {
+ for (pel = pevent_list[0]; pel; pel = pel->next) {
+ if (!eventname || epicsStrGlobMatch(pel->eventname, eventname)) {
+ printf("Event \"%s\"\n", pel->eventname);
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
if (ellCount(&pel->scan_list[prio].list) == 0) continue;
- sprintf(message, "Event \"%s\" Priority %s", pel->event_name, priorityName[prio]);
+ sprintf(message, " Priority %s", priorityName[prio]);
printList(&pel->scan_list[prio], message);
}
}
@@ -478,20 +464,52 @@ event_list *eventNameToHandle(const char *eventname)
int prio;
event_list *pel;
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
+ double eventnumber = 0;
+ size_t namelength;
- if (!eventname || eventname[0] == 0)
- return NULL;
+ if (!eventname) return NULL;
+ while (isspace((int) eventname[0])) eventname++;
+ if (!eventname[0]) return NULL;
+ namelength = strlen(eventname);
+ while (isspace((int) eventname[namelength-1])) namelength--;
+
+ /* Backward compatibility with numeric events:
+ Treat any string that represents a double with an
+ integer part between 0 and 255 the same as the integer
+ because it is most probably a conversion from double
+ like from a calc record.
+ */
+ if (epicsParseDouble(eventname, &eventnumber, NULL) == 0)
+ {
+ if (eventnumber >= 0 && eventnumber < 256)
+ {
+ if (eventnumber < 1)
+ return NULL; /* 0 is no event */
+ if ((pel = pevent_list[(int)eventnumber]) != NULL)
+ return pel;
+ }
+ else
+ eventnumber = 0; /* not a numeric event between 1 and 255 */
+ }
epicsThreadOnce(&onceId, eventOnce, NULL);
epicsMutexMustLock(event_lock);
for (pel = pevent_list[0]; pel; pel=pel->next) {
- if (strcmp(pel->event_name, eventname) == 0) break;
+ if (strncmp(pel->eventname, eventname, namelength) == 0
+ && pel->eventname[namelength] == 0)
+ break;
}
if (pel == NULL) {
- pel = calloc(1, sizeof(event_list));
+ pel = calloc(1, sizeof(event_list) + namelength);
if (!pel)
goto done;
- strcpy(pel->event_name, eventname);
+ if (eventnumber > 0) {
+ /* backward compatibility: make all numeric events look like integers */
+ sprintf(pel->eventname, "%i", (int)eventnumber);
+ pevent_list[(int)eventnumber] = pel;
+ }
+ else
+ strncpy(pel->eventname, eventname, namelength);
for (prio = 0; prio < NUM_CALLBACK_PRIORITIES; prio++) {
callbackSetUser(&pel->scan_list[prio], &pel->callback[prio]);
callbackSetPriority(prio, &pel->callback[prio]);
@@ -501,12 +519,6 @@ event_list *eventNameToHandle(const char *eventname)
}
pel->next=pevent_list[0];
pevent_list[0]=pel;
- { /* backward compatibility */
- char* p;
- long e = strtol(eventname, &p, 0);
- if (*p == 0 && e > 0 && e <= 255)
- pevent_list[e] = pel;
- }
}
done:
epicsMutexUnlock(event_lock);
@@ -528,13 +540,8 @@ void postEvent(event_list *pel)
/* backward compatibility */
void post_event(int event)
{
- event_list* pel;
-
if (event <= 0 || event > 255) return;
- do { /* multithreading: make sure pel is consistent */
- pel = pevent_list[event];
- } while (pel != pevent_list[event]);
- postEvent(pel);
+ postEvent(pevent_list[event]);
}
static void ioscanOnce(void *arg)
diff --git a/modules/database/src/ioc/db/dbScan.h b/modules/database/src/ioc/db/dbScan.h
index 4ec6dda60..028d09ec8 100644
--- a/modules/database/src/ioc/db/dbScan.h
+++ b/modules/database/src/ioc/db/dbScan.h
@@ -51,7 +51,7 @@ epicsShareFunc void scanCleanup(void);
epicsShareFunc EVENTPVT eventNameToHandle(const char* event);
epicsShareFunc void postEvent(EVENTPVT epvt);
-epicsShareFunc void post_event(int event) EPICS_DEPRECATED;
+epicsShareFunc void post_event(int event);
epicsShareFunc void scanAdd(struct dbCommon *);
epicsShareFunc void scanDelete(struct dbCommon *);
epicsShareFunc double scanPeriod(int scan);
diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c
index 39b551987..6846ef5fb 100644
--- a/modules/database/src/ioc/db/dbUnitTest.c
+++ b/modules/database/src/ioc/db/dbUnitTest.c
@@ -20,6 +20,7 @@
#include "osiUnistd.h"
#include "registry.h"
#include "epicsEvent.h"
+#include "epicsThread.h"
#define epicsExportSharedSymbols
#include "dbAccess.h"
@@ -415,3 +416,26 @@ unsigned testMonitorCount(testMonitor *mon, unsigned reset)
return count;
}
+static
+epicsMutexId test_global;
+
+static
+epicsThreadOnceId test_global_once = EPICS_THREAD_ONCE_INIT;
+
+static
+void test_global_init(void* ignored)
+{
+ test_global = epicsMutexMustCreate();
+}
+
+void testGlobalLock(void)
+{
+ epicsThreadOnce(&test_global_once, &test_global_init, NULL);
+ epicsMutexMustLock(test_global);
+}
+
+void testGlobalUnlock(void)
+{
+ epicsMutexUnlock(test_global);
+}
+
diff --git a/modules/database/src/ioc/db/dbUnitTest.h b/modules/database/src/ioc/db/dbUnitTest.h
index 897e5c67d..e38b8c67a 100644
--- a/modules/database/src/ioc/db/dbUnitTest.h
+++ b/modules/database/src/ioc/db/dbUnitTest.h
@@ -98,6 +98,65 @@ epicsShareFunc void testMonitorWait(testMonitor*);
*/
epicsShareFunc unsigned testMonitorCount(testMonitor*, unsigned reset);
+/** Synchronize the shared callback queues.
+ *
+ * Block until all callback queue jobs which were queued, or running,
+ * have completed.
+ */
+epicsShareFunc void testSyncCallback(void);
+
+/** Global mutex for use by test code.
+ *
+ * This utility mutex is intended to be used to avoid races in situations
+ * where some other syncronization primitive is being destroyed (epicsEvent,
+ * epicsMutex, ...).
+ *
+ * For example. The following has a subtle race where the event may be
+ * destroyed (free()'d) before the call to epicsEventMustSignal() has
+ * returned. On some targets this leads to a use after free() error.
+ *
+ @code
+ epicsEventId evt;
+ void thread1() {
+ evt = epicsEventMustCreate(...);
+ // spawn thread2()
+ epicsEventMustWait(evt);
+ epicsEventDestroy(evt);
+ }
+ // ...
+ void thread2() {
+ epicsEventMustSignal(evt);
+ }
+ @endcode
+ *
+ * One way to avoid this race is to use a global mutex to ensure
+ * that epicsEventMustSignal() has returned before destroying
+ * the event.
+ *
+ @code
+ epicsEventId evt;
+ void thread1() {
+ evt = epicsEventMustCreate(...);
+ // spawn thread2()
+ epicsEventMustWait(evt);
+ testGlobalLock(); // <-- added
+ epicsEventDestroy(evt);
+ testGlobalUnlock(); // <-- added
+ }
+ // ...
+ void thread2() {
+ testGlobalLock(); // <-- added
+ epicsEventMustSignal(evt);
+ testGlobalUnlock(); // <-- added
+ }
+ @endcode
+ *
+ * This must be a global mutex to avoid simply shifting the race
+ * from the event to a locally allocated mutex.
+ */
+epicsShareFunc void testGlobalLock(void);
+epicsShareFunc void testGlobalUnlock(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c
index 97a85ff54..59eb345f3 100644
--- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c
+++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c
@@ -1064,32 +1064,39 @@ static void dbRecordHead(char *recordType, char *name, int visible)
static void dbRecordField(char *name,char *value)
{
- DBENTRY *pdbentry;
- tempListNode *ptempListNode;
- long status;
+ DBENTRY *pdbentry;
+ tempListNode *ptempListNode;
+ long status;
- if(duplicate) return;
+ if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbFindField(pdbentry,name);
- if(status) {
- epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
- dbGetRecordName(pdbentry), name);
- yyerror(NULL);
- return;
+ if (status) {
+ epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
+ dbGetRecordName(pdbentry), name);
+ yyerror(NULL);
+ return;
+ }
+ if (pdbentry->indfield == 0) {
+ epicsPrintf("Can't set \"NAME\" field of record \"%s\"\n",
+ dbGetRecordName(pdbentry));
+ yyerror(NULL);
+ return;
}
if (*value == '"') {
- /* jsonSTRING values still have their quotes */
+ /* jsonSTRING values still have their quotes */
value++;
- value[strlen(value) - 1] = 0;
+ value[strlen(value) - 1] = 0;
}
dbTranslateEscape(value, value); /* in-place; safe & legal */
status = dbPutString(pdbentry,value);
- if(status) {
+ if (status) {
char msg[128];
+
errSymLookup(status, msg, sizeof(msg));
epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s\n",
- dbGetRecordName(pdbentry), name, value, msg);
+ dbGetRecordName(pdbentry), name, value, msg);
yyerror(NULL);
return;
}
@@ -1097,39 +1104,39 @@ static void dbRecordField(char *name,char *value)
static void dbRecordInfo(char *name, char *value)
{
- DBENTRY *pdbentry;
- tempListNode *ptempListNode;
- long status;
+ DBENTRY *pdbentry;
+ tempListNode *ptempListNode;
+ long status;
- if(duplicate) return;
+ if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
if (*value == '"') {
- /* jsonSTRING values still have their quotes */
+ /* jsonSTRING values still have their quotes */
value++;
- value[strlen(value) - 1] = 0;
+ value[strlen(value) - 1] = 0;
}
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
status = dbPutInfo(pdbentry,name,value);
- if(status) {
- epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
+ if (status) {
+ epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
dbGetRecordName(pdbentry), name, value);
- yyerror(NULL);
- return;
+ yyerror(NULL);
+ return;
}
}
static void dbRecordAlias(char *name)
{
- DBENTRY *pdbentry;
- tempListNode *ptempListNode;
- long status;
+ DBENTRY *pdbentry;
+ tempListNode *ptempListNode;
+ long status;
- if(duplicate) return;
+ if (duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbCreateAlias(pdbentry, name);
- if(status) {
+ if (status) {
epicsPrintf("Can't create alias \"%s\" for \"%s\"\n",
name, dbGetRecordName(pdbentry));
yyerror(NULL);
@@ -1139,15 +1146,16 @@ static void dbRecordAlias(char *name)
static void dbAlias(char *name, char *alias)
{
- DBENTRY dbEntry;
- DBENTRY *pdbEntry = &dbEntry;
+ DBENTRY dbEntry;
+ DBENTRY *pdbEntry = &dbEntry;
dbInitEntry(pdbbase, pdbEntry);
if (dbFindRecord(pdbEntry, name)) {
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
alias, name);
yyerror(NULL);
- } else if (dbCreateAlias(pdbEntry, alias)) {
+ }
+ else if (dbCreateAlias(pdbEntry, alias)) {
epicsPrintf("Can't create alias \"%s\" referring to \"%s\"\n",
alias, name);
yyerror(NULL);
@@ -1157,14 +1165,14 @@ static void dbAlias(char *name, char *alias)
static void dbRecordBody(void)
{
- DBENTRY *pdbentry;
+ DBENTRY *pdbentry;
- if(duplicate) {
- duplicate = FALSE;
- return;
+ if (duplicate) {
+ duplicate = FALSE;
+ return;
}
pdbentry = (DBENTRY *)popFirstTemp();
- if(ellCount(&tempList))
- yyerrorAbort("dbRecordBody: tempList not empty");
+ if (ellCount(&tempList))
+ yyerrorAbort("dbRecordBody: tempList not empty");
dbFreeEntry(pdbentry);
}
diff --git a/modules/database/src/std/dev/devMbbiDirectSoft.c b/modules/database/src/std/dev/devMbbiDirectSoft.c
index 9c929b2b6..861952f8d 100644
--- a/modules/database/src/std/dev/devMbbiDirectSoft.c
+++ b/modules/database/src/std/dev/devMbbiDirectSoft.c
@@ -47,7 +47,7 @@ epicsExportAddress(dset, devMbbiDirectSoft);
static long init_record(mbbiDirectRecord *prec)
{
- if (recGblInitConstantLink(&prec->inp, DBF_ENUM, &prec->val))
+ if (recGblInitConstantLink(&prec->inp, DBR_ULONG, &prec->val))
prec->udf = FALSE;
return 0;
@@ -56,7 +56,7 @@ static long init_record(mbbiDirectRecord *prec)
static long readLocked(struct link *pinp, void *dummy)
{
mbbiDirectRecord *prec = (mbbiDirectRecord *) pinp->precord;
- long status = dbGetLink(pinp, DBR_USHORT, &prec->val, 0, 0);
+ long status = dbGetLink(pinp, DBR_ULONG, &prec->val, 0, 0);
if (status) return status;
diff --git a/modules/database/src/std/dev/devMbbiDirectSoftCallback.c b/modules/database/src/std/dev/devMbbiDirectSoftCallback.c
index 93016329f..d785f7386 100644
--- a/modules/database/src/std/dev/devMbbiDirectSoftCallback.c
+++ b/modules/database/src/std/dev/devMbbiDirectSoftCallback.c
@@ -41,7 +41,7 @@ typedef struct devPvt {
struct {
DBRstatus
DBRtime
- epicsUInt16 value;
+ epicsUInt32 value;
} buffer;
} devPvt;
@@ -58,7 +58,7 @@ static void getCallback(processNotify *ppn, notifyGetType type)
}
assert(type == getFieldType);
- pdevPvt->status = dbChannelGetField(ppn->chan, DBR_USHORT,
+ pdevPvt->status = dbChannelGetField(ppn->chan, DBR_ULONG,
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
}
@@ -153,7 +153,7 @@ static long init(int pass)
static long init_record(mbbiDirectRecord *prec)
{
- if (recGblInitConstantLink(&prec->inp, DBR_ENUM, &prec->val))
+ if (recGblInitConstantLink(&prec->inp, DBR_ULONG, &prec->val))
prec->udf = FALSE;
return 0;
diff --git a/modules/database/src/std/dev/devMbbiDirectSoftRaw.c b/modules/database/src/std/dev/devMbbiDirectSoftRaw.c
index f6172cdec..98b4673fc 100644
--- a/modules/database/src/std/dev/devMbbiDirectSoftRaw.c
+++ b/modules/database/src/std/dev/devMbbiDirectSoftRaw.c
@@ -59,7 +59,7 @@ static long init_record(mbbiDirectRecord *prec)
static long read_mbbi(mbbiDirectRecord *prec)
{
- if (!dbGetLink(&prec->inp, DBR_LONG, &prec->rval, 0, 0)) {
+ if (!dbGetLink(&prec->inp, DBR_ULONG, &prec->rval, 0, 0)) {
prec->rval &= prec->mask;
if (dbLinkIsConstant(&prec->tsel) &&
prec->tse == epicsTimeEventDeviceTime)
diff --git a/modules/database/src/std/dev/devMbboDirectSoft.c b/modules/database/src/std/dev/devMbboDirectSoft.c
index 0c0851980..75359f283 100644
--- a/modules/database/src/std/dev/devMbboDirectSoft.c
+++ b/modules/database/src/std/dev/devMbboDirectSoft.c
@@ -21,7 +21,7 @@
static long write_mbbo(mbboDirectRecord *prec)
{
- dbPutLink(&prec->out, DBR_USHORT, &prec->val, 1);
+ dbPutLink(&prec->out, DBR_ULONG, &prec->val, 1);
return 0;
}
diff --git a/modules/database/src/std/dev/devMbboDirectSoftCallback.c b/modules/database/src/std/dev/devMbboDirectSoftCallback.c
index e64c3d41c..6d86507ae 100644
--- a/modules/database/src/std/dev/devMbboDirectSoftCallback.c
+++ b/modules/database/src/std/dev/devMbboDirectSoftCallback.c
@@ -29,11 +29,11 @@ static long write_mbbo(mbboDirectRecord *prec)
if (prec->pact)
return 0;
- status = dbPutLinkAsync(plink, DBR_USHORT, &prec->val, 1);
+ status = dbPutLinkAsync(plink, DBR_ULONG, &prec->val, 1);
if (!status)
prec->pact = TRUE;
else if (status == S_db_noLSET)
- status = dbPutLink(plink, DBR_USHORT, &prec->val, 1);
+ status = dbPutLink(plink, DBR_ULONG, &prec->val, 1);
return status;
}
diff --git a/modules/database/src/std/filters/filters.dbd.pod b/modules/database/src/std/filters/filters.dbd.pod
index db97907a5..f1a848469 100644
--- a/modules/database/src/std/filters/filters.dbd.pod
+++ b/modules/database/src/std/filters/filters.dbd.pod
@@ -146,9 +146,9 @@ Note: Negative index numbers address from the end of the array, with C<-1> being
=item Square bracket notation C<[start:increment:end]> (shorthand)
-The common square bracket notation with can be used in place of JSON.
+The common square bracket notation which can be used in place of JSON.
Any parameter may be omitted (keeping the colons) to use the default value.
-If only one colon is included, this means C<[start:end]> with a increment of 1.
+If only one colon is included, this means C<[start:end]> with an increment of 1.
If only a single parameter is used C<[index]> the filter returns one element.
=item Start index C<"s">
diff --git a/modules/database/src/std/rec/longinRecord.c b/modules/database/src/std/rec/longinRecord.c
index a302a3d29..f72ac9137 100644
--- a/modules/database/src/std/rec/longinRecord.c
+++ b/modules/database/src/std/rec/longinRecord.c
@@ -22,6 +22,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
+#include "epicsMath.h"
#include "alarm.h"
#include "callback.h"
#include "dbAccess.h"
@@ -248,15 +249,17 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
{
longinRecord *prec=(longinRecord *)paddr->precord;
- if(dbGetFieldIndex(paddr) == indexof(VAL)){
- pad->upper_alarm_limit = prec->hihi;
- pad->upper_warning_limit = prec->high;
- pad->lower_warning_limit = prec->low;
- pad->lower_alarm_limit = prec->lolo;
- } else recGblGetAlarmDouble(paddr,pad);
- return(0);
+ if (dbGetFieldIndex(paddr) == indexof(VAL)){
+ pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
+ pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
+ pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
+ pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
+ }
+ else
+ recGblGetAlarmDouble(paddr,pad);
+ return 0;
}
-
+
static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast)
{
enum {
diff --git a/modules/database/src/std/rec/longoutRecord.c b/modules/database/src/std/rec/longoutRecord.c
index 0b1d66d50..5e13e09b9 100644
--- a/modules/database/src/std/rec/longoutRecord.c
+++ b/modules/database/src/std/rec/longoutRecord.c
@@ -19,6 +19,7 @@
#include "dbDefs.h"
#include "epicsPrint.h"
+#include "epicsMath.h"
#include "alarm.h"
#include "callback.h"
#include "dbAccess.h"
@@ -282,15 +283,17 @@ static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
longoutRecord *prec=(longoutRecord *)paddr->precord;
- if(dbGetFieldIndex(paddr) == indexof(VAL)) {
- pad->upper_alarm_limit = prec->hihi;
- pad->upper_warning_limit = prec->high;
- pad->lower_warning_limit = prec->low;
- pad->lower_alarm_limit = prec->lolo;
- } else recGblGetAlarmDouble(paddr,pad);
- return(0);
+ if (dbGetFieldIndex(paddr) == indexof(VAL)) {
+ pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
+ pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
+ pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
+ pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
+ }
+ else
+ recGblGetAlarmDouble(paddr,pad);
+ return 0;
}
-
+
static void checkAlarms(longoutRecord *prec)
{
epicsInt32 val, hyst, lalm;
diff --git a/modules/database/src/std/rec/mbbiDirectRecord.c b/modules/database/src/std/rec/mbbiDirectRecord.c
index 566bbe21d..afb59c83f 100644
--- a/modules/database/src/std/rec/mbbiDirectRecord.c
+++ b/modules/database/src/std/rec/mbbiDirectRecord.c
@@ -6,10 +6,10 @@
* Copyright (c) 2002 Southeastern Universities Research Association, as
* Operator of Thomas Jefferson National Accelerator Facility.
* EPICS BASE is distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
-/* mbbiDirectRecord.c - Record Support routines for mbboDirect records */
+/* mbbiDirectRecord.c - Record Support routines for mbbiDirect records */
/*
* Original Authors: Bob Dalesio and Matthew Needes
* Date: 10-07-93
@@ -93,7 +93,7 @@ struct mbbidset { /* multi bit binary input dset */
static void monitor(mbbiDirectRecord *);
static long readValue(mbbiDirectRecord *);
-#define NUM_BITS 16
+#define NUM_BITS 32
static long init_record(struct dbCommon *pcommon, int pass)
{
@@ -114,7 +114,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
}
recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
- recGblInitConstantLink(&prec->siol, DBF_USHORT, &prec->sval);
+ recGblInitConstantLink(&prec->siol, DBF_ULONG, &prec->sval);
/* Initialize MASK if the user set NOBT instead */
if (prec->mask == 0 && prec->nobt <= 32)
@@ -123,11 +123,11 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (pdset->init_record) {
status = pdset->init_record(prec);
if (status == 0) {
- epicsUInt16 val = prec->val;
+ epicsUInt32 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
- /* Initialize B0 - BF from VAL */
+ /* Initialize B0 - B1F from VAL */
for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1)
*pBn = !! (val & 1);
}
@@ -208,7 +208,7 @@ static void monitor(mbbiDirectRecord *prec)
{
epicsUInt16 events = recGblResetAlarms(prec);
epicsUInt16 vl_events = events | DBE_VALUE | DBE_LOG;
- epicsUInt16 val = prec->val;
+ epicsUInt32 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
diff --git a/modules/database/src/std/rec/mbbiDirectRecord.dbd b/modules/database/src/std/rec/mbbiDirectRecord.dbd
index c7ca0f466..bb432e58f 100644
--- a/modules/database/src/std/rec/mbbiDirectRecord.dbd
+++ b/modules/database/src/std/rec/mbbiDirectRecord.dbd
@@ -8,7 +8,7 @@
#*************************************************************************
recordtype(mbbiDirect) {
include "dbCommon.dbd"
- field(VAL,DBF_USHORT) {
+ field(VAL,DBF_LONG) {
prompt("Current Value")
promptgroup("40 - Input")
asl(ASL0)
@@ -39,7 +39,7 @@ recordtype(mbbiDirect) {
special(SPC_NOMOD)
interest(1)
}
- field(MLST,DBF_USHORT) {
+ field(MLST,DBF_LONG) {
prompt("Last Value Monitored")
special(SPC_NOMOD)
interest(3)
@@ -54,7 +54,7 @@ recordtype(mbbiDirect) {
promptgroup("90 - Simulate")
interest(1)
}
- field(SVAL,DBF_ULONG) {
+ field(SVAL,DBF_LONG) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
@@ -151,32 +151,112 @@ recordtype(mbbiDirect) {
interest(1)
}
field(BA,DBF_UCHAR) {
- prompt("Bit A")
+ prompt("Bit 10")
pp(TRUE)
interest(1)
}
field(BB,DBF_UCHAR) {
- prompt("Bit B")
+ prompt("Bit 11")
pp(TRUE)
interest(1)
}
field(BC,DBF_UCHAR) {
- prompt("Bit C")
+ prompt("Bit 12")
pp(TRUE)
interest(1)
}
field(BD,DBF_UCHAR) {
- prompt("Bit D")
+ prompt("Bit 13")
pp(TRUE)
interest(1)
}
field(BE,DBF_UCHAR) {
- prompt("Bit E")
+ prompt("Bit 14")
pp(TRUE)
interest(1)
}
field(BF,DBF_UCHAR) {
- prompt("Bit F")
+ prompt("Bit 15")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B10,DBF_UCHAR) {
+ prompt("Bit 16")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B11,DBF_UCHAR) {
+ prompt("Bit 17")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B12,DBF_UCHAR) {
+ prompt("Bit 18")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B13,DBF_UCHAR) {
+ prompt("Bit 19")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B14,DBF_UCHAR) {
+ prompt("Bit 20")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B15,DBF_UCHAR) {
+ prompt("Bit 21")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B16,DBF_UCHAR) {
+ prompt("Bit 22")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B17,DBF_UCHAR) {
+ prompt("Bit 23")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B18,DBF_UCHAR) {
+ prompt("Bit 24")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B19,DBF_UCHAR) {
+ prompt("Bit 25")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1A,DBF_UCHAR) {
+ prompt("Bit 26")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1B,DBF_UCHAR) {
+ prompt("Bit 27")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1C,DBF_UCHAR) {
+ prompt("Bit 28")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1D,DBF_UCHAR) {
+ prompt("Bit 29")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1E,DBF_UCHAR) {
+ prompt("Bit 30")
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1F,DBF_UCHAR) {
+ prompt("Bit 31")
pp(TRUE)
interest(1)
}
diff --git a/modules/database/src/std/rec/mbboDirectRecord.c b/modules/database/src/std/rec/mbboDirectRecord.c
index 750228bc9..9260fbda1 100644
--- a/modules/database/src/std/rec/mbboDirectRecord.c
+++ b/modules/database/src/std/rec/mbboDirectRecord.c
@@ -95,7 +95,7 @@ static void convert(mbboDirectRecord *);
static void monitor(mbboDirectRecord *);
static long writeValue(mbboDirectRecord *);
-#define NUM_BITS 16
+#define NUM_BITS 32
static long init_record(struct dbCommon *pcommon, int pass)
{
@@ -117,7 +117,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
- if (recGblInitConstantLink(&prec->dol, DBF_USHORT, &prec->val))
+ if (recGblInitConstantLink(&prec->dol, DBF_ULONG, &prec->val))
prec->udf = FALSE;
/* Initialize MASK if the user set NOBT instead */
@@ -142,8 +142,8 @@ static long init_record(struct dbCommon *pcommon, int pass)
if (!prec->udf &&
prec->omsl == menuOmslsupervisory) {
- /* Set initial B0 - BF from VAL */
- epicsUInt16 val = prec->val;
+ /* Set initial B0 - B1F from VAL */
+ epicsUInt32 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
@@ -175,9 +175,9 @@ static long process(struct dbCommon *pcommon)
if (!pact) {
if (!dbLinkIsConstant(&prec->dol) &&
prec->omsl == menuOmslclosed_loop) {
- epicsUInt16 val;
+ epicsUInt32 val;
- if (dbGetLink(&prec->dol, DBR_USHORT, &val, 0, 0)) {
+ if (dbGetLink(&prec->dol, DBR_ULONG, &val, 0, 0)) {
recGblSetSevr(prec, LINK_ALARM, INVALID_ALARM);
goto CONTINUE;
}
@@ -185,11 +185,11 @@ static long process(struct dbCommon *pcommon)
}
else if (prec->omsl == menuOmslsupervisory) {
epicsUInt8 *pBn = &prec->b0;
- epicsUInt16 val = 0;
- epicsUInt16 bit = 1;
+ epicsUInt32 val = 0;
+ epicsUInt32 bit = 1;
int i;
- /* Construct VAL from B0 - BF */
+ /* Construct VAL from B0 - B1F */
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
if (*pBn++)
val |= bit;
@@ -264,7 +264,7 @@ static long special(DBADDR *paddr, int after)
if (prec->omsl == menuOmslsupervisory) {
/* Adjust VAL corresponding to the bit changed */
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
- int bit = 1 << (pBn - &prec->b0);
+ epicsUInt32 bit = 1 << (pBn - &prec->b0);
if (*pBn)
prec->val |= bit;
@@ -278,9 +278,9 @@ static long special(DBADDR *paddr, int after)
case SPC_RESET: /* OMSL field modified */
if (prec->omsl == menuOmslclosed_loop) {
- /* Construct VAL from B0 - BF */
+ /* Construct VAL from B0 - B1F */
epicsUInt8 *pBn = &prec->b0;
- epicsUInt16 val = 0, bit = 1;
+ epicsUInt32 val = 0, bit = 1;
int i;
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
@@ -289,8 +289,8 @@ static long special(DBADDR *paddr, int after)
prec->val = val;
}
else if (prec->omsl == menuOmslsupervisory) {
- /* Set B0 - BF from VAL and post monitors */
- epicsUInt16 val = prec->val;
+ /* Set B0 - B1F from VAL and post monitors */
+ epicsUInt32 val = prec->val;
epicsUInt8 *pBn = &prec->b0;
int i;
@@ -362,7 +362,7 @@ static long writeValue(mbboDirectRecord *prec)
case menuYesNoYES: {
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
if (prec->pact || (prec->sdly < 0.)) {
- status = dbPutLink(&prec->siol, DBR_USHORT, &prec->val, 1);
+ status = dbPutLink(&prec->siol, DBR_ULONG, &prec->val, 1);
prec->pact = FALSE;
} else { /* !prec->pact && delay >= 0. */
CALLBACK *pvt = prec->simpvt;
diff --git a/modules/database/src/std/rec/mbboDirectRecord.dbd b/modules/database/src/std/rec/mbboDirectRecord.dbd
index 241199d9e..a6a43b4f0 100644
--- a/modules/database/src/std/rec/mbboDirectRecord.dbd
+++ b/modules/database/src/std/rec/mbboDirectRecord.dbd
@@ -7,8 +7,8 @@
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(mbboDirect) {
- include "dbCommon.dbd"
- field(VAL,DBF_USHORT) {
+ include "dbCommon.dbd"
+ field(VAL,DBF_LONG) {
prompt("Word")
promptgroup("50 - Output")
asl(ASL0)
@@ -38,6 +38,99 @@ recordtype(mbboDirect) {
promptgroup("50 - Output")
interest(1)
}
+ field(RVAL,DBF_ULONG) {
+ prompt("Raw Value")
+ special(SPC_NOMOD)
+ pp(TRUE)
+ }
+ field(ORAW,DBF_ULONG) {
+ prompt("Prev Raw Value")
+ special(SPC_NOMOD)
+ interest(3)
+ }
+ field(RBV,DBF_ULONG) {
+ prompt("Readback Value")
+ special(SPC_NOMOD)
+ }
+ field(ORBV,DBF_ULONG) {
+ prompt("Prev Readback Value")
+ special(SPC_NOMOD)
+ interest(3)
+ }
+ field(MASK,DBF_ULONG) {
+ prompt("Hardware Mask")
+ special(SPC_NOMOD)
+ interest(1)
+ }
+ field(MLST,DBF_LONG) {
+ prompt("Last Value Monitored")
+ special(SPC_NOMOD)
+ interest(3)
+ }
+ field(SHFT,DBF_USHORT) {
+ prompt("Shift")
+ promptgroup("50 - Output")
+ interest(1)
+ }
+ field(SIOL,DBF_OUTLINK) {
+ prompt("Simulation Output Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(SIML,DBF_INLINK) {
+ prompt("Simulation Mode Link")
+ promptgroup("90 - Simulate")
+ interest(1)
+ }
+ field(SIMM,DBF_MENU) {
+ prompt("Simulation Mode")
+ special(SPC_MOD)
+ interest(1)
+ menu(menuYesNo)
+ }
+ field(SIMS,DBF_MENU) {
+ prompt("Simulation Mode Severity")
+ promptgroup("90 - Simulate")
+ interest(2)
+ menu(menuAlarmSevr)
+ }
+ field(OLDSIMM,DBF_MENU) {
+ prompt("Prev. Simulation Mode")
+ special(SPC_NOMOD)
+ interest(4)
+ menu(menuSimm)
+ }
+ field(SSCN,DBF_MENU) {
+ prompt("Sim. Mode Scan")
+ promptgroup("90 - Simulate")
+ interest(1)
+ menu(menuScan)
+ initial("65535")
+ }
+ field(SDLY,DBF_DOUBLE) {
+ prompt("Sim. Mode Async Delay")
+ promptgroup("90 - Simulate")
+ interest(2)
+ initial("-1.0")
+ }
+ %#include "callback.h"
+ field(SIMPVT,DBF_NOACCESS) {
+ prompt("Sim. Mode Private")
+ special(SPC_NOMOD)
+ interest(4)
+ extra("CALLBACK *simpvt")
+ }
+ field(IVOA,DBF_MENU) {
+ prompt("INVALID outpt action")
+ promptgroup("50 - Output")
+ interest(2)
+ menu(menuIvoa)
+ }
+ field(IVOV,DBF_LONG) {
+ prompt("INVALID output value")
+ promptgroup("50 - Output")
+ interest(2)
+ }
field(B0,DBF_UCHAR) {
prompt("Bit 0")
promptgroup("51 - Output 0-7")
@@ -96,151 +189,170 @@ recordtype(mbboDirect) {
}
field(B8,DBF_UCHAR) {
prompt("Bit 8")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(B9,DBF_UCHAR) {
prompt("Bit 9")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BA,DBF_UCHAR) {
prompt("Bit 10")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BB,DBF_UCHAR) {
prompt("Bit 11")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BC,DBF_UCHAR) {
prompt("Bit 12")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BD,DBF_UCHAR) {
prompt("Bit 13")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BE,DBF_UCHAR) {
prompt("Bit 14")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
field(BF,DBF_UCHAR) {
prompt("Bit 15")
- promptgroup("52 - Output 9-F")
+ promptgroup("52 - Output 8-15")
special(SPC_MOD)
pp(TRUE)
interest(1)
}
- field(RVAL,DBF_ULONG) {
- prompt("Raw Value")
- special(SPC_NOMOD)
- pp(TRUE)
- }
- field(ORAW,DBF_ULONG) {
- prompt("Prev Raw Value")
- special(SPC_NOMOD)
- interest(3)
- }
- field(RBV,DBF_ULONG) {
- prompt("Readback Value")
- special(SPC_NOMOD)
- }
- field(ORBV,DBF_ULONG) {
- prompt("Prev Readback Value")
- special(SPC_NOMOD)
- interest(3)
- }
- field(MASK,DBF_ULONG) {
- prompt("Hardware Mask")
- special(SPC_NOMOD)
- interest(1)
- }
- field(MLST,DBF_ULONG) {
- prompt("Last Value Monitored")
- special(SPC_NOMOD)
- interest(3)
- }
- field(SHFT,DBF_ULONG) {
- prompt("Shift")
- promptgroup("50 - Output")
- interest(1)
- }
- field(SIOL,DBF_OUTLINK) {
- prompt("Simulation Output Link")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(SIML,DBF_INLINK) {
- prompt("Simulation Mode Link")
- promptgroup("90 - Simulate")
- interest(1)
- }
- field(SIMM,DBF_MENU) {
- prompt("Simulation Mode")
+ field(B10,DBF_UCHAR) {
+ prompt("Bit 16")
+ promptgroup("53 - Output 16-23")
special(SPC_MOD)
+ pp(TRUE)
interest(1)
- menu(menuYesNo)
}
- field(SIMS,DBF_MENU) {
- prompt("Simulation Mode Severity")
- promptgroup("90 - Simulate")
- interest(2)
- menu(menuAlarmSevr)
- }
- field(OLDSIMM,DBF_MENU) {
- prompt("Prev. Simulation Mode")
- special(SPC_NOMOD)
- interest(4)
- menu(menuSimm)
- }
- field(SSCN,DBF_MENU) {
- prompt("Sim. Mode Scan")
- promptgroup("90 - Simulate")
+ field(B11,DBF_UCHAR) {
+ prompt("Bit 17")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
interest(1)
- menu(menuScan)
- initial("65535")
}
- field(SDLY,DBF_DOUBLE) {
- prompt("Sim. Mode Async Delay")
- promptgroup("90 - Simulate")
- interest(2)
- initial("-1.0")
+ field(B12,DBF_UCHAR) {
+ prompt("Bit 18")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
}
- %#include "callback.h"
- field(SIMPVT,DBF_NOACCESS) {
- prompt("Sim. Mode Private")
- special(SPC_NOMOD)
- interest(4)
- extra("CALLBACK *simpvt")
+ field(B13,DBF_UCHAR) {
+ prompt("Bit 19")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
}
- field(IVOA,DBF_MENU) {
- prompt("INVALID outpt action")
- promptgroup("50 - Output")
- interest(2)
- menu(menuIvoa)
+ field(B14,DBF_UCHAR) {
+ prompt("Bit 20")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
}
- field(IVOV,DBF_USHORT) {
- prompt("INVALID output value")
- promptgroup("50 - Output")
- interest(2)
+ field(B15,DBF_UCHAR) {
+ prompt("Bit 21")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B16,DBF_UCHAR) {
+ prompt("Bit 22")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B17,DBF_UCHAR) {
+ prompt("Bit 23")
+ promptgroup("53 - Output 16-23")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B18,DBF_UCHAR) {
+ prompt("Bit 24")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B19,DBF_UCHAR) {
+ prompt("Bit 25")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1A,DBF_UCHAR) {
+ prompt("Bit 26")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1B,DBF_UCHAR) {
+ prompt("Bit 27")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1C,DBF_UCHAR) {
+ prompt("Bit 28")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1D,DBF_UCHAR) {
+ prompt("Bit 29")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1E,DBF_UCHAR) {
+ prompt("Bit 30")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
+ }
+ field(B1F,DBF_UCHAR) {
+ prompt("Bit 31")
+ promptgroup("54 - Output 24-31")
+ special(SPC_MOD)
+ pp(TRUE)
+ interest(1)
}
}
diff --git a/modules/database/src/std/rec/printfRecord.c b/modules/database/src/std/rec/printfRecord.c
index 7011453d4..576b9632a 100644
--- a/modules/database/src/std/rec/printfRecord.c
+++ b/modules/database/src/std/rec/printfRecord.c
@@ -34,12 +34,13 @@
/* Flag bits */
-#define F_CHAR 1
-#define F_SHORT 2
-#define F_LONG 4
-#define F_LEFT 8
-#define F_BADFMT 0x10
-#define F_BADLNK 0x20
+#define F_CHAR 1
+#define F_SHORT 2
+#define F_LONG 4
+#define F_LONGLONG 8
+#define F_LEFT 0x10
+#define F_BADFMT 0x40
+#define F_BADLNK 0x80
#define F_BAD (F_BADFMT | F_BADLNK)
#define GET_PRINT(VALTYPE, DBRTYPE) \
@@ -129,13 +130,20 @@ static void doPrintf(printfRecord *prec)
flags |= F_BADLNK;
break;
case 'h':
- if (flags & F_SHORT)
+ if (flags & (F_LONGLONG | F_LONG | F_CHAR))
+ flags |= F_BADFMT;
+ else if (flags & F_SHORT)
flags = (flags & ~F_SHORT) | F_CHAR;
else
flags |= F_SHORT;
break;
case 'l':
- flags |= F_LONG;
+ if (flags & (F_LONGLONG | F_SHORT | F_CHAR))
+ flags |= F_BADFMT;
+ else if (flags & F_LONG)
+ flags = (flags & ~F_LONG) | F_LONGLONG;
+ else
+ flags |= F_LONG;
break;
default:
if (strchr("diouxXeEfFgGcs%", ch) == NULL)
@@ -175,6 +183,9 @@ static void doPrintf(printfRecord *prec)
else if (flags & F_SHORT) {
GET_PRINT(epicsInt16, DBR_SHORT);
}
+ else if (flags & F_LONGLONG) {
+ GET_PRINT(epicsInt64, DBR_INT64);
+ }
else { /* F_LONG has no real effect */
GET_PRINT(epicsInt32, DBR_LONG);
}
@@ -187,6 +198,9 @@ static void doPrintf(printfRecord *prec)
else if (flags & F_SHORT) {
GET_PRINT(epicsUInt16, DBR_USHORT);
}
+ else if (flags & F_LONGLONG) {
+ GET_PRINT(epicsUInt64, DBR_UINT64);
+ }
else { /* F_LONG has no real effect */
GET_PRINT(epicsUInt32, DBR_ULONG);
}
diff --git a/modules/database/src/template/top/exampleApp/src/xxxRecord.c b/modules/database/src/template/top/exampleApp/src/xxxRecord.c
index c2693c48e..97640d2b6 100644
--- a/modules/database/src/template/top/exampleApp/src/xxxRecord.c
+++ b/modules/database/src/template/top/exampleApp/src/xxxRecord.c
@@ -198,8 +198,8 @@ static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
static void checkAlarms(xxxRecord *prec)
{
- double val;
- float hyst, lalm, hihi, high, low, lolo;
+ double val, hyst, lalm;
+ float hihi, high, low, lolo;
unsigned short hhsv, llsv, hsv, lsv;
if(prec->udf == TRUE ){
diff --git a/modules/database/src/template/top/exampleBoot/ioc/Makefile@Common b/modules/database/src/template/top/exampleBoot/ioc/Makefile@Common
index e064d7344..e1b9aa4ab 100644
--- a/modules/database/src/template/top/exampleBoot/ioc/Makefile@Common
+++ b/modules/database/src/template/top/exampleBoot/ioc/Makefile@Common
@@ -1,4 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
+ARCH = $(EPICS_HOST_ARCH)
TARGETS = envPaths
include $(TOP)/configure/RULES.ioc
diff --git a/modules/database/src/template/top/iocBoot/ioc/Makefile@Common b/modules/database/src/template/top/iocBoot/ioc/Makefile@Common
index e064d7344..e1b9aa4ab 100644
--- a/modules/database/src/template/top/iocBoot/ioc/Makefile@Common
+++ b/modules/database/src/template/top/iocBoot/ioc/Makefile@Common
@@ -1,4 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
+ARCH = $(EPICS_HOST_ARCH)
TARGETS = envPaths
include $(TOP)/configure/RULES.ioc
diff --git a/modules/database/src/tools/dbdToHtml.pl b/modules/database/src/tools/dbdToHtml.pl
index 76b187147..542e140cf 100644
--- a/modules/database/src/tools/dbdToHtml.pl
+++ b/modules/database/src/tools/dbdToHtml.pl
@@ -46,7 +46,7 @@ BEGIN {
my $tool = 'dbdToHtml';
-use vars qw($opt_D @opt_I $opt_o);
+our ($opt_D, @opt_I, $opt_o);
getopts('DI@o:') or
die "Usage: $tool [-D] [-I dir] [-o file.html] file.dbd.pod\n";
diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl
index 6bdcb8a6a..ac4345b42 100644
--- a/modules/database/src/tools/dbdToMenuH.pl
+++ b/modules/database/src/tools/dbdToMenuH.pl
@@ -21,7 +21,7 @@ use EPICS::Readfile;
my $tool = 'dbdToMenuH.pl';
-use vars qw($opt_D @opt_I $opt_o $opt_s);
+our ($opt_D, @opt_I, $opt_o, $opt_s);
getopts('DI@o:') or
die "Usage: $tool: [-D] [-I dir] [-o menu.h] menu.dbd [menu.h]\n";
diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl
index 730599029..b1eb77d93 100644
--- a/modules/database/src/tools/dbdToRecordtypeH.pl
+++ b/modules/database/src/tools/dbdToRecordtypeH.pl
@@ -21,7 +21,7 @@ use EPICS::Readfile;
my $tool = 'dbdToRecordtypeH.pl';
-use vars qw($opt_D @opt_I $opt_o $opt_s);
+our ($opt_D, @opt_I, $opt_o, $opt_s);
getopts('DI@o:s') or
die "Usage: $tool [-D] [-I dir] [-o xRecord.h] xRecord.dbd [xRecord.h]\n";
diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile
index 892f6cc10..7c78ac93c 100644
--- a/modules/database/test/std/rec/Makefile
+++ b/modules/database/test/std/rec/Makefile
@@ -96,6 +96,17 @@ testHarness_SRCS += analogMonitorTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/analogMonitorTest.dbd ../analogMonitorTest.db
TESTS += analogMonitorTest
+TARGETS += $(COMMON_DIR)/scanEventTest.dbd
+DBDDEPENDS_FILES += scanEventTest.dbd$(DEP)
+scanEventTest_DBD += base.dbd
+TESTPROD_HOST += scanEventTest
+scanEventTest_SRCS += scanEventTest.c
+scanEventTest_SRCS += scanEventTest_registerRecordDeviceDriver.cpp
+testHarness_SRCS += scanEventTest.c
+testHarness_SRCS += scanEventTest_registerRecordDeviceDriver.cpp
+TESTFILES += $(COMMON_DIR)/scanEventTest.dbd ../scanEventTest.db
+TESTS += scanEventTest
+
TARGETS += $(COMMON_DIR)/regressTest.dbd
DBDDEPENDS_FILES += regressTest.dbd$(DEP)
regressTest_DBD += base.dbd
@@ -118,6 +129,13 @@ testHarness_SRCS += simmTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/simmTest.dbd $(COMMON_DIR)/simmTest.db
TESTS += simmTest
+TESTPROD_HOST += mbbioDirectTest
+mbbioDirectTest_SRCS += mbbioDirectTest.c
+mbbioDirectTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
+testHarness_SRCS += mbbioDirectTest.c
+TESTFILES += ../mbbioDirectTest.db
+TESTS += mbbioDirectTest
+
# epicsRunRecordTests runs all the test programs in a known working order.
testHarness_SRCS += epicsRunRecordTests.c
diff --git a/modules/database/test/std/rec/epicsRunRecordTests.c b/modules/database/test/std/rec/epicsRunRecordTests.c
index 6214f4aec..8e8a645d3 100644
--- a/modules/database/test/std/rec/epicsRunRecordTests.c
+++ b/modules/database/test/std/rec/epicsRunRecordTests.c
@@ -21,6 +21,8 @@ int linkRetargetLinkTest(void);
int linkInitTest(void);
int asyncSoftTest(void);
int simmTest(void);
+int mbbioDirectTest(void);
+int scanEventTest(void);
void epicsRunRecordTests(void)
{
@@ -44,5 +46,9 @@ void epicsRunRecordTests(void)
runTest(simmTest);
+ runTest(mbbioDirectTest);
+
+ runTest(scanEventTest);
+
epicsExit(0); /* Trigger test harness */
}
diff --git a/modules/database/test/std/rec/mbbioDirectTest.c b/modules/database/test/std/rec/mbbioDirectTest.c
new file mode 100644
index 000000000..fb011f662
--- /dev/null
+++ b/modules/database/test/std/rec/mbbioDirectTest.c
@@ -0,0 +1,145 @@
+/*************************************************************************\
+* Copyright (c) 2017 Dirk Zimoch
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+\*************************************************************************/
+
+/* Theory of Operation
+ *
+ * For each of the two soft device supports (soft/raw soft/soft),
+ * there is a combination of mbboDirect -> val / sim -> mbbiDirect.
+ *
+ * The intermediate records are of type double (val) and long (sim) to
+ * check conversion from/to double.
+ *
+ * For each device support, the following is done:
+ * 1. The mbboDirect record is set to a specific value through the database.
+ * 2. The initial value is checked on both ends.
+ * 3. Two single bits (5 & 31) are toggled, values checked on both ends.
+ * 4. Sim mode is activated, one bit (0) is toggled, values are checked,
+ * data path (old value in val, new value in sim) is checked.
+ */
+
+#include
+
+#include "dbAccess.h"
+#include "errlog.h"
+#include "dbStaticLib.h"
+#include "dbTest.h"
+#include "dbUnitTest.h"
+#include "testMain.h"
+#include "epicsThread.h"
+#include "epicsExport.h"
+
+static
+void testmbbioFields(const char* rec, unsigned int value)
+{
+ char field[40];
+ unsigned int i;
+
+ testdbGetFieldEqual(rec, DBF_ULONG, value);
+ for (i=0; i < 32; i++)
+ {
+ sprintf(field,"%s.B%X", rec, i);
+ testdbGetFieldEqual(field, DBF_ULONG, (value>>i)&1);
+ }
+}
+
+static
+void testmbbioRecords(unsigned int count, unsigned int value)
+{
+ char rec[40];
+ unsigned int i;
+
+ for (i = 1; i <= count; i++)
+ {
+ sprintf(rec, "do%d", i);
+ testDiag(" ### %s ###", rec);
+ testmbbioFields(rec, value);
+ sprintf(rec, "di%d", i);
+ testmbbioFields(rec, value);
+ }
+}
+
+static
+void putN(const char* pattern, unsigned int count, unsigned int value)
+{
+ char field[40];
+ unsigned int i;
+
+ for (i = 1; i <= count; i++)
+ {
+ sprintf(field, pattern, i);
+ testdbPutFieldOk(field, DBF_ULONG, value);
+ }
+}
+
+static
+void testN(const char* pattern, unsigned int count, unsigned int value)
+{
+ char field[40];
+ unsigned int i;
+
+ for (i = 1; i <= count; i++)
+ {
+ sprintf(field, pattern, i);
+ testdbGetFieldEqual(field, DBF_ULONG, value);
+ }
+}
+
+
+void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
+
+MAIN(mbbioDirectTest)
+{
+ unsigned int value = 0xdeadbeef;
+ unsigned int simvalue = 0;
+ char macros [40];
+ const unsigned int N = 2;
+
+ testPlan(N*((32+1)*2*4+4+3));
+
+ testdbPrepare();
+
+ testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
+
+ recTestIoc_registerRecordDeviceDriver(pdbbase);
+
+ sprintf(macros, "INIT=%#x", value);
+ testdbReadDatabase("mbbioDirectTest.db", NULL, macros);
+
+ eltc(0);
+ testIocInitOk();
+ eltc(1);
+
+ testDiag("##### check initial value #####");
+ testmbbioRecords(N, value);
+
+ testDiag("##### set bit 5 #####");
+ putN("do%u.B5", N, 1);
+ value |= (1<<5);
+ testN("val%d", N, value);
+ testmbbioRecords(N, value);
+
+ testDiag("##### clear bit 31 (0x1f) #####");
+ putN("do%u.B1F", N, 0);
+ value &= ~(1<<31);
+ testN("val%d", N, value);
+ testmbbioRecords(N, value);
+
+ testDiag("##### simulation mode #####");
+ dbpf("sim", "1");
+ simvalue = value & ~1;
+ putN("do%u.B0", N, 0);
+ /* old value in lo* */
+ testN("val%d", N, value);
+ /* sim value in sim* */
+ testN("sim%d", N, simvalue);
+ testmbbioRecords(N, simvalue);
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+
+ return testDone();
+}
diff --git a/modules/database/test/std/rec/mbbioDirectTest.db b/modules/database/test/std/rec/mbbioDirectTest.db
new file mode 100644
index 000000000..ed6e09175
--- /dev/null
+++ b/modules/database/test/std/rec/mbbioDirectTest.db
@@ -0,0 +1,47 @@
+record(bo, "sim") {
+ field(ZNAM, "off")
+ field(ONAM, "simulation")
+}
+
+record(mbboDirect, "do1") {
+ field(DOL, "$(INIT=0)")
+ field(DTYP, "Soft Channel")
+ field(OUT, "val1 PP")
+ field(SIOL, "sim1 PP")
+ field(SIML, "sim")
+ field(PINI, "YES")
+}
+record(ao, "val1") {
+ field(FLNK, "di1")
+}
+record(longout, "sim1") {
+ field(FLNK, "di1")
+}
+record(mbbiDirect, "di1") {
+ field(DTYP, "Soft Channel")
+ field(INP, "val1")
+ field(SIOL, "sim1 PP")
+ field(SIML, "sim")
+}
+
+
+record(mbboDirect, "do2") {
+ field(DOL, "$(INIT=0)")
+ field(DTYP, "Raw Soft Channel")
+ field(OUT, "val2 PP")
+ field(SIOL, "sim2 PP")
+ field(SIML, "sim")
+ field(PINI, "YES")
+}
+record(ao, "val2") {
+ field(FLNK, "di2")
+}
+record(longout, "sim2") {
+ field(FLNK, "di2")
+}
+record(mbbiDirect, "di2") {
+ field(DTYP, "Raw Soft Channel")
+ field(INP, "val2")
+ field(SIML, "sim")
+ field(SIOL, "sim2")
+}
diff --git a/modules/database/test/std/rec/scanEventTest.c b/modules/database/test/std/rec/scanEventTest.c
new file mode 100644
index 000000000..6b90a413b
--- /dev/null
+++ b/modules/database/test/std/rec/scanEventTest.c
@@ -0,0 +1,143 @@
+/*************************************************************************\
+* Copyright (c) 2018 Paul Scherrer Institut
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
+ \*************************************************************************/
+
+/*
+ * Author: Dirk Zimoch
+ */
+
+#include
+#include "dbStaticLib.h"
+#include "dbAccessDefs.h"
+#include "dbUnitTest.h"
+#include "testMain.h"
+#include "osiFileName.h"
+#include "epicsThread.h"
+#include "dbScan.h"
+
+void scanEventTest_registerRecordDeviceDriver(struct dbBase *);
+
+/* test name to event number:
+ num = 0 is no event,
+ num > 0 is numeric event
+ num < 0 is string event (use same unique number for aliases)
+*/
+const struct {char* name; int num;} events[] = {
+/* No events */
+ {NULL, 0},
+ {"", 0},
+ {" ", 0},
+ {"0", 0},
+ {"0.000000", 0},
+ {"-0.00000", 0},
+ {"0.9", 0},
+/* Numeric events */
+ {"2", 2},
+ {"2.000000", 2},
+ {"2.5", 2},
+ {" 2.5 ", 2},
+ {"+0x02", 2},
+ {"3", 3},
+/* Named events */
+ {"info 1", -1},
+ {" info 1 ", -1},
+ {"-0.9", -2},
+ {"-2", -3},
+ {"-2.000000", -4},
+ {"-2.5", -5},
+ {" -2.5 ", -5},
+ {"nan", -6},
+ {"NaN", -7},
+ {"-NAN", -8},
+ {"-inf", -9},
+ {"inf", -10},
+};
+
+MAIN(scanEventTest)
+{
+ int i, e;
+ int aliases[512] ;
+ int expected_count[512];
+ #define INDX(i) 256-events[i].num
+ #define MAXEV 5
+
+ testPlan(NELEMENTS(events)*2+(MAXEV+1)*5);
+
+ testdbPrepare();
+
+ memset(aliases, 0, sizeof(aliases));
+ memset(expected_count, 0, sizeof(expected_count));
+
+ testdbReadDatabase("scanEventTest.dbd", NULL, NULL);
+
+ scanEventTest_registerRecordDeviceDriver(pdbbase);
+ for (i = 0; i < NELEMENTS(events); i++) {
+ char substitutions[256];
+ sprintf(substitutions, "N=%d,EVENT=%s", i, events[i].name);
+ testdbReadDatabase("scanEventTest.db", NULL, substitutions);
+ }
+ testIocInitOk();
+ testDiag("Test if eventNameToHandle() strips spaces and handles numeric events");
+ for (i = 0; i < NELEMENTS(events); i++) {
+ EVENTPVT pev = eventNameToHandle(events[i].name);
+ /* test that some names are not events (num=0) */
+ if (events[i].num == 0)
+ testOk(pev == NULL, "\"%s\" -> no event", events[i].name);
+ else
+ {
+ expected_count[INDX(i)]++; /* +1 for postEvent */
+ if (events[i].num > 0)
+ {
+ testOk(pev != NULL, "\"%s\" -> numeric event %d", events[i].name, events[i].num);
+ expected_count[INDX(i)]++; /* +1 for post_event */
+ }
+ else
+ {
+ /* test that some strings resolve the same event (num!=0) */
+ if (!aliases[INDX(i)])
+ {
+ aliases[INDX(i)] = i;
+ testOk(pev != NULL, "\"%s\" -> new named event", events[i].name);
+ }
+ else
+ {
+ testOk(pev == eventNameToHandle(events[aliases[INDX(i)]].name),
+ "\"%s\" alias for \"%s\"", events[i].name, events[aliases[INDX(i)]].name);
+ }
+ }
+ }
+ post_event(events[i].num); /* triggers numeric events only */
+ postEvent(pev);
+ }
+
+ testDiag("Check calculated numeric events (backward compatibility)");
+ for (e = 0; e <= MAXEV; e++) {
+ testdbPutFieldOk("eventnum", DBR_LONG, e);
+ testdbGetFieldEqual("e1", DBR_LONG, e);
+ testdbGetFieldEqual("e2", DBR_LONG, e);
+ testdbPutFieldOk("e3", DBR_LONG, e);
+ testdbPutFieldOk("e3.PROC", DBR_LONG, 1);
+ for (i = 0; i < NELEMENTS(events); i++)
+ if (e > 0 && e < 256 && events[i].num == e) { /* numeric events */
+ expected_count[INDX(i)]+=3; /* +1 for eventnum->e1, +1 for e2<-eventnum, +1 for e3 */
+ break;
+ }
+ }
+ /* Allow records to finish processing */
+ testSyncCallback();
+ testDiag("Check if events have been processed the expected number of times");
+ for (i = 0; i < NELEMENTS(events); i++) {
+ char pvname[100];
+ sprintf(pvname, "c%d", i);
+ testDiag("Event \"%s\" expected %d times", events[i].name, expected_count[INDX(i)]);
+ testdbGetFieldEqual(pvname, DBR_LONG, expected_count[INDX(i)]);
+ }
+
+ testIocShutdownOk();
+
+ testdbCleanup();
+
+ return testDone();
+}
diff --git a/modules/database/test/std/rec/scanEventTest.db b/modules/database/test/std/rec/scanEventTest.db
new file mode 100644
index 000000000..9118823d8
--- /dev/null
+++ b/modules/database/test/std/rec/scanEventTest.db
@@ -0,0 +1,16 @@
+record(calc, "c$(N)") {
+ field(SCAN, "Event")
+ field(EVNT, "$(EVENT)")
+ field(CALC, "VAL+1")
+}
+record(dfanout, "eventnum") {
+ field(OUTA, "e1 PP")
+ field(FLNK, "e2")
+}
+record(event, "e1") {
+}
+record(event, "e2") {
+ field(INP, "eventnum")
+}
+record(event, "e3") {
+}
diff --git a/src/tools/convertRelease.pl b/src/tools/convertRelease.pl
index 677b43744..a5a1a77d8 100644
--- a/src/tools/convertRelease.pl
+++ b/src/tools/convertRelease.pl
@@ -24,8 +24,7 @@ use lib ("$Bin/../../lib/perl", $Bin);
use EPICS::Path;
use EPICS::Release;
-use vars qw($arch $top $iocroot $root);
-
+our ($arch, $top, $iocroot, $root);
our ($opt_a, $opt_t, $opt_T);
getopts('a:t:T:') or HELP_MESSAGE();