Compare commits

..

47 Commits

Author SHA1 Message Date
Janet B. Anderson
25a6340993 Added filio.h include for solaris build. 1995-11-13 16:55:03 +00:00
Jeff Hill
a3652fd54e improvents for better client reconnect 1995-11-08 23:48:26 +00:00
Jeff Hill
107ae2cee8 fixed log client reconnect problems 1995-11-08 23:46:27 +00:00
Jeff Hill
deb5e9c973 add log entries 1995-11-08 23:45:10 +00:00
Jeff Hill
196f2302a4 changes associated with fixing the log client 1995-11-08 23:44:41 +00:00
Jeff Hill
2a21b01b0e fixed bug occuring when diagnostic is printed and the env var cant be found 1995-11-08 23:43:51 +00:00
Jeff Hill
56465da07f log entries changed 1995-11-08 23:38:41 +00:00
Jeff Hill
ee9457970a changes froim chris T 1995-11-08 23:36:31 +00:00
Jeff Hill
89a3746869 changes from Chris T 1995-11-08 23:20:56 +00:00
Janet B. Anderson
5be8f4999d Removed "-s" compile option 1995-11-08 19:28:51 +00:00
Marty Kraimer
b278c803ce When calling db_post_event for argument fields ass DBE_LOG 1995-11-08 15:01:36 +00:00
Jeff Hill
50b8361078 more changes from Chris Timossi 1995-10-25 16:46:01 +00:00
Jeff Hill
2a121a4276 changes from Chris Timossi 1995-10-24 21:21:31 +00:00
Jeff Hill
7b03ab0182 Changes to avoid spurious ECONREFUSED returned from recvfrom() under linux 1995-10-22 22:27:47 +00:00
cvs2svn
73a224a6ce This commit was manufactured by cvs2svn to create tag 'R3.12.1.4'. 1995-10-20 20:21:33 +00:00
Marty Kraimer
f4af420e22 Changes to make stop work 1995-10-20 20:21:32 +00:00
Janet B. Anderson
b0177729b8 Sequencer V1.9.0(3.12.1) form lanl. 1995-10-19 21:35:38 +00:00
Jeff Hill
c7b5592846 make certain we dont use CPU while waiting for a flush to complete 1995-10-19 20:37:19 +00:00
Janet B. Anderson
2f5202a4e4 Assume no DST if tsMinWest is 600 (includes Hawaii and may be exclusively
Hawaii?). (WFL, 95/08/15)
1995-10-19 13:54:50 +00:00
Ned Arnold
ecb106fb71 WAIT Record Version 3.01, channel access dynamic links 1995-10-19 13:42:38 +00:00
Ned Arnold
b637c15e18 SCAN Record Version 3.00. Many changes. 1995-10-19 13:41:47 +00:00
Jeff Hill
d1102b06c0 recv task is now running at a lower priority than the send task under vxWorks 1995-10-18 16:49:23 +00:00
Jeff Hill
2fb23fd27b Use recast delay greater than one vxWorks tick 1995-10-18 16:45:40 +00:00
Jeff Hill
752b7e257e select time out must be greater than a vxWorks tick 1995-10-18 16:44:36 +00:00
John Quintana
025b13b977 *** empty log message *** 1995-10-12 20:50:36 +00:00
Jeff Hill
4c2822dd2e added SOLARIS ifdef around ioctl includes 1995-10-12 18:55:22 +00:00
Jeff Hill
9dcee4c068 removed unused variable 1995-10-12 18:54:41 +00:00
Janet B. Anderson
9bf802557e Updated for R3.12.1.3 1995-10-12 17:09:20 +00:00
Jeff Hill
2566ee1e26 If the IOC is out of memory allow them to connect if they stop
some of the clients.
1995-10-12 01:40:48 +00:00
Jeff Hill
5a16ba053b Changes from Bob Dalesio:
lrd     fix init to limit in overshoot check and retry post monitors
	   for mcw and mccw reprocess records if the setpoint changed
	   while they were moving
1995-10-12 01:38:41 +00:00
Jeff Hill
ad3e5a3272 New ca_flush_io() mechanism 1995-10-12 01:36:39 +00:00
Jeff Hill
17511136a1 Use of port is consistent unsigned short now 1995-10-12 01:36:13 +00:00
Jeff Hill
ffa22f89bd Moved cac_mux_io() to iocinf.c 1995-10-12 01:35:33 +00:00
Jeff Hill
2e7075bd31 Dont include filio.h and sockio.h. They are included by ioctl.h
and dont exist under linux.
1995-10-12 01:34:00 +00:00
Jeff Hill
278eaf84d7 Initial delay between search frames went from .1 to .01 sec,
Added flush pending flag, Make all usage of port be unsigned short.
1995-10-12 01:33:12 +00:00
Jeff Hill
d957aebbf4 make the use of unsigend short for a port consistent. Moved
cac_mux_io() out of os dependent code and into this module.
Added caSendMsgPending() routine.
1995-10-12 01:31:54 +00:00
Jeff Hill
5ac2a99686 improved the test 1995-10-12 01:30:28 +00:00
Jeff Hill
b782f63a7d new ca_flush_io() mechanism prevents deadlock when they call
ca_flush_io() from within an event routine. Also forces early
transmission of leading search UDP frames.
1995-10-12 01:30:10 +00:00
Marty Kraimer
e62f7d0ae2 cvtDoubleToString: honor precision for wierd numbers 1995-10-11 19:42:52 +00:00
Marty Kraimer
1ca96e0116 recGblGetAlarmDouble was not setting upper_warning_limit and lower_alarm_limit 1995-10-11 19:41:22 +00:00
Andrew Johnson
44d65d9477 Fixed main() for use as host tool - was *really* broken. 1995-10-04 20:42:05 +00:00
Andrew Johnson
dc3ba94fc8 Updated for Solaris Native mode compilation instructions. 1995-10-03 22:52:50 +00:00
Andrew Johnson
41ad7ae2ab Generating LIBOBJS automatically from SRCS.c 1995-10-03 21:18:50 +00:00
Andrew Johnson
017c55f9d9 Generating TARGETS automatically from SRCS.c 1995-10-03 21:13:45 +00:00
Andrew Johnson
196d7538c3 Generating LIBOBJS automatically from SRCS.c 1995-10-03 21:04:57 +00:00
Andrew Johnson
5ace66b609 Generating LIBOBJS automatically from SRCS.c 1995-10-03 20:59:44 +00:00
cvs2svn
0be218bed4 This commit was manufactured by cvs2svn to create tag 'R3.12.1.3'. 1995-10-03 15:42:27 +00:00
62 changed files with 6101 additions and 3990 deletions

72
README
View File

@@ -7,23 +7,13 @@ $Id$
Notes:
1. Before you can build or really use EPICS, you must set your
path properly:
set path = ( $path EPICS/base/tools EPICS/base/bin/HOST_ARCH \
EPICS/extensions/bin HOST_ARCH )
e.g.:
set path = ( $path /home/epics/base/tools /home/epics/base/bin/sun4 \
/home/epics/extensions/bin/sun4 )
1. Before you can build or really use EPICS, you must properly set the
environemnt variable HOST_ARCH. The epics/startup/HostArch script file
has been provided to set HOST_ARCH.
2. You must use GNU make (which is now THE supported make utility) for
the build. A script, gmake, exists in the base/tools directory to invoke
it with the --no-print-directory option. This option will turn off the
annoying messages GNU make produces upon entering a directory.
gmake
the build, gnumake. Set your path so that a recent version (e.g.
V3.70) of gnumake is available (as make) before any system supplied makes.
----------------------------------------------------------------------------
Part 1 - Configuring and Building EPICS Base
@@ -39,63 +29,63 @@ gmake
cd epics/config
cp CONFIG_ARCH.mv167 CONFIG_ARCH.YOUR_ARCH
edit CONFIG_ARCH.YOUR_ARCH - For compiler flags / etc.
edit CONFIG_ARCH.YOUR_ARCH - For compiler flags / etc.
cp CONFIG.Vx.68k CONFIG.Vx.YOUR_ARCH_CLASS
cp CONFIG_SITE.Vx.68k CONFIG_SITE.Vx.YOUR_ARCH_CLASS
- ONLY IF you are adding a new architecture class,
see note in Appendix A.
edit CONFIG_BASE - Add architecture to list.
edit CONFIG_BASE - Add architecture to list.
1.3 To build EPICS:
cd epics/base
gmake - To build and install EPICS.
gmake clean - To clean temporary object files. Clean will
gnumake - To build and install EPICS.
gnumake clean - To clean temporary object files. Clean will
remove files from ALL O.ARCH dirs, not
only those specified in BUILD_ARCHS.
1.4 To create an EPICS release:
edit base/include/version.h - ONLY IF you need to change the EPICS
version number.
edit base/include/version.h - ONLY IF you need to change the EPICS
version number.
gmake release - Will create Tar file
gnumake release - Will create Tar file
gmake built_release - Will create Tar file, after generating
dependencies, INCLUDING BINARIES.
gnumake built_release - Will create Tar file, after generating
dependencies, INCLUDING BINARIES.
1.5 "Partial" build commands:
gmake clean.sun4 - Cleans sun4 binaries in O.sun4 dirs only.
gmake install.sun4 - Builds sun4 only.
gmake install.mv167 - Builds mv167 only (a HOST_ARCH build must
be complete before this can be issued).
gnumake clean.sun4 - Cleans sun4 binaries in O.sun4 dirs only.
gnumake install.sun4 - Builds sun4 only.
gnumake install.mv167 - Builds mv167 only (a HOST_ARCH build must
be complete before this can be issued).
NOTES:
1. base/MakeRelease will create tar files in the directory ABOVE
base. These tar files are then meant to be untarred at that level.
This release will include the "epics/config" directory.
base. These tar files are then meant to be untarred at that level.
This release will include the "epics/config" directory.
2. EPICS binaries are kept in the bin/ARCH and lib/ARCH directories.
EPICS shellscripts are kept in the tools directory.
EPICS shellscripts are kept in the tools directory.
3. During a normal build (a "make" or "make install"), the "depends"
dependency will NOT be invoked. Only if "make depends" is run
explicitly, or a "make built_release" is performed will dependencies
be generated automatically.
dependency will NOT be invoked. Only if "make depends" is run
explicitly, or a "make built_release" is performed will dependencies
be generated automatically.
4. Temporary objects are stored in src/DIR/O.ARCH, This allows objects
for multiple architectures to be maintained at the same time.
While developing source for EPICS, merely cd src/DIR/O.ARCH, and
invoke "make":
for multiple architectures to be maintained at the same time.
While developing source for EPICS, merely cd src/DIR/O.ARCH, and
invoke "make":
cd epics/base/src/db/O.mv167
make dbAccess.o
cd epics/base/src/db/O.mv167
make dbAccess.o
The above example instructs make to build dbAccess.o for the
mv167 target.
The above example instructs make to build dbAccess.o for the
mv167 target.
----------------------------------------------------------------------------
Part 2 --- Configuration Files in epics/config

34
README.Linux Normal file
View File

@@ -0,0 +1,34 @@
Special Notes on Linux
1) The epics makefiles use GNU make which is the make that comes
with Linux. You need to make a link from make to gnumake and
have it in your path. After you have defined the EPICS environement
variable, you can use:
ln -s /usr/bin/make $EPICS/base/tools/gnumake
2) At this point, support for Linux only involves channel access
clients. Since Vxworks is not available for Linux, you must
use other platforms for developing server side code. As for
building databases with dct and gdct, this requires that the
$EPICS/base/tools/makesdr script works properly. Since makesdr
is slated to be removed from the EPICS distribution in a future
release, we didn't feel it was important to include this capability
now. Consequently, when you run make you will receive the error
gnumake[4]: *** [bldDefaultSdr] Error 127
and
gnumake[3]: *** [comsubs.o] Error 1
3) You MUST start caRepeater by hand before running a client.
Prior to running a client, you must run:
caRepeater &
---
jpq@nwu.edu

View File

@@ -4,42 +4,11 @@
# M. Anderson and J. Tang
- EPICS environment variable - set by hand prior to build
For EPICS builds on HP700 and Alpha OSF/1, set an environment variable "EPICS"
to the base of the EPICS directory to do builds in (the directory where
this file resides, for instance).
If you are currently in the base directory, then do the following:
% setenv EPICS $cwd
- set path to include gnu make and base/tools and base/bin/<arch>
Then set the path such that a recent version (e.g. V3.70) of gnumake
is available (as make) before any system supplied makes, and that
$EPICS/base/tools and $EPICS/base/bin/<arch> are included as well.
For example:
% set path=(/usr/local/bin $EPICS/base/tools $EPICS/base/bin/hp700 $path)
- to build multiple architectures in same tree
To build multiple architectures in the same directory tree, you
can avoid editing CONFIG_SITE by simply issuing make with HOST_ARCH=<arch>
For example:
% make HOST_ARCH=hp700
Also, directory permissions may not be correct across multiple machines,
so a
- Directory permissions may not be correct across multiple machines, so a
% chmod -R ugo+rw base extensions
might be necessary.
- bsdinstall is written to replace install for hp.
- epics/base/tools/bsdinstall was written to replace install for hp.

View File

@@ -1,29 +1,21 @@
----------------------------------------------------------------------------
EPICS R3.12 Notes for Solaris 2.3
EPICS R3.12.2 Notes for Solaris
- By Andrew Johnson
----------------------------------------------------------------------------
Notes:
1. In order to build and use EPICS under Solaris 2, you must include
various directories in your path in the order given below, in addition
to those named in base/README. Some of these directories may already be
included in your path from your .login script or .cshrc file, so be
careful that the ordering is correct.
1. In order to build EPICS under Solaris 2, you must ensure that the
solaris directory /usr/ccs/bin is in your search path.
setenv PATH /usr/ucb:/usr/bin:/usr/ccs/bin:$PATH
2. It is not possible to compile EPICS under Solaris 2 using only the
GNU gcc compiler -- you must have the Sun SPARCworks ANSI C compiler.
2. It is not possible to compile the whole of EPICS under Solaris 2
using only the GNU gcc compiler - some routines which are needed (for
example quiet_nan()) have been unbundled by Sun and are provided with
their ANSI C compiler. The path to the Sun compiler is explicitly set
using the SPARCWORKS definition in the file CONFIG_SITE.Unix.solaris
3. EPICS must be compiled and linked using the UCB compatability
libraries. The definitions UCB_LIB and UCB_INCLUDE are used here to
refer to these libraries and their header files, and the tools provided
within /usr/ucb must be used in preference to the System V ones, hence
the above path ordering.
3. EPICS under Solaris 2 no longer uses the UCB compatability
libraries. It does require the /usr/ucb/install program however. In
order to ensure that the /usr/ucblib files are not inherited, you
should ensure that your LD_LIBRARY_PATH environment variable does not
include /usr/ucblib when you build any of the host tools.
--
anj@mail.ast.cam.ac.uk
anj@ast.cam.ac.uk

View File

@@ -99,6 +99,16 @@
/************************************************************************/
/*
* $Log$
* Revision 1.79 1995/10/12 01:30:10 jhill
* new ca_flush_io() mechanism prevents deadlock when they call
* ca_flush_io() from within an event routine. Also forces early
* transmission of leading search UDP frames.
*
* Revision 1.78 1995/09/29 21:47:33 jhill
* alignment fix for SPARC IOC client and changes to prevent running of
* access rights or connection handlers when the connection is lost just
* after deleting a channel
*
* Revision 1.77 1995/09/01 14:31:32 mrk
* Fixed bug causing memory problem
*
@@ -320,6 +330,22 @@ void *pext
while(TRUE){
struct timeval itimeout;
/*
* record the time if we end up blocking so that
* we can time out
*/
if (bytesAvailable>=msgsize){
piiu->sendPending = FALSE;
break;
}
else {
if (!piiu->sendPending) {
piiu->timeAtSendBlock =
ca_static->currentTime;
piiu->sendPending = TRUE;
}
}
/*
* if connection drops request
* cant be completed
@@ -339,21 +365,6 @@ void *pext
bytesAvailable = cacRingBufferWriteSize(
&piiu->send,
FALSE);
/*
* record the time if we end up blocking so that
* we can time out
*/
if (bytesAvailable>=extsize+sizeof(msg)) {
piiu->sendPending = FALSE;
break;
}
else {
if (!piiu->sendPending) {
piiu->timeAtSendBlock =
ca_static->currentTime;
piiu->sendPending = TRUE;
}
}
}
}
@@ -576,6 +587,8 @@ int ca_os_independent_init (void)
ca_spawn_repeater();
}
ca_static->ca_flush_pending = FALSE;
return ECA_NORMAL;
}
@@ -618,7 +631,7 @@ LOCAL void create_udp_fd()
status = taskSpawn(
name,
pri-1,
pri+1,
VX_FP_TASK,
4096,
(FUNCPTR)cac_recv_task,
@@ -2682,18 +2695,16 @@ void clearChannelResources(unsigned id)
/* if the argument early is specified TRUE then CA_NORMAL is */
/* returned early (prior to timeout experation) when outstanding */
/* IO completes. */
/* ca_flush_io() is called by this routine. */
/* Output buffers are flushed by this routine */
/************************************************************************/
int epicsShareAPI ca_pend (ca_real timeout, int early)
{
struct timeval beg_time;
ca_real delay;
struct timeval tmo;
INITCHK;
if(timeout<0.0){
return ECA_TIMEOUT;
}
if(EVENTLOCKTEST){
return ECA_EVDISALLOW;
@@ -2706,19 +2717,37 @@ int epicsShareAPI ca_pend (ca_real timeout, int early)
* (guarantees that we wait for all send buffer to be
* flushed even if this requires blocking)
*/
ca_flush_io();
ca_static->ca_flush_pending = TRUE;
if(pndrecvcnt<1 && early){
/*
* force the flush
*/
LD_CA_TIME (0.0, &tmo);
cac_mux_io(&tmo);
return ECA_NORMAL;
}
if(timeout<0.0){
/*
* force the flush
*/
LD_CA_TIME (0.0, &tmo);
cac_mux_io(&tmo);
return ECA_TIMEOUT;
}
beg_time = ca_static->currentTime;
delay = 0.0;
while(TRUE){
ca_real remaining;
struct timeval tmo;
if (pndrecvcnt<1 && early) {
/*
* force the flush
*/
LD_CA_TIME (0.0, &tmo);
cac_mux_io(&tmo);
return ECA_NORMAL;
}
@@ -2749,14 +2778,16 @@ int epicsShareAPI ca_pend (ca_real timeout, int early)
if (remaining <= (1.0/USEC_PER_SEC)) {
if(early){
ca_pend_io_cleanup();
ca_flush_io();
ca_static->ca_flush_pending = TRUE;
}
/*
* be certain that we processed
* recv backlog at least once
*/
tmo.tv_sec = 0L;
tmo.tv_usec = 0L;
/*
* force the flush
*/
LD_CA_TIME (0.0, &tmo);
cac_block_for_io_completion (&tmo);
return ECA_TIMEOUT;
}
@@ -2864,55 +2895,27 @@ LOCAL void ca_pend_io_cleanup()
/*
* CA_FLUSH_IO()
*
* reprocess connection state and
* flush the send buffer
*
*/
int epicsShareAPI ca_flush_io()
{
struct ioc_in_use *piiu;
struct timeval timeout;
unsigned long bytesPending;
INITCHK;
while (TRUE) {
int pending;
/*
* force early transmission of the first few search frames
*/
manage_conn(TRUE);
/*
* wait for all buffers to flush
*/
pending = FALSE;
LOCK;
for( piiu = (IIU *) iiuList.node.next;
piiu;
piiu = (IIU *) piiu->node.next){
if(piiu == piiuCast || piiu->conn_up == FALSE){
continue;
}
bytesPending = cacRingBufferReadSize(
&piiu->send,
FALSE);
if(bytesPending != 0){
pending = TRUE;
}
}
UNLOCK;
if (!pending) {
break;
}
/*
* perform socket io
* and process recv backlog
*/
LD_CA_TIME (SELECT_POLL, &timeout);
cac_mux_io (&timeout);
}
/*
* Wait for all send buffers to be flushed
* while performing socket io and processing recv backlog
*/
ca_static->ca_flush_pending = TRUE;
LD_CA_TIME (0.0, &timeout);
cac_mux_io (&timeout);
return ECA_NORMAL;
}

View File

@@ -7,6 +7,9 @@ static char *sccsId = "@(#) $Id$";
/*
* $Log$
* Revision 1.30 1995/09/29 21:47:58 jhill
* MS windows changes
*
* Revision 1.29 1995/08/22 00:16:34 jhill
* Added test of the duration of ca_pend_event()
*
@@ -646,6 +649,11 @@ unsigned iterations)
void null_event(struct event_handler_args args)
{
static int i;
dbr_double_t fval = 3.8;
int status;
status = ca_put (DBR_DOUBLE, args.chid, &fval);
SEVCHK (status, NULL);
if (i++ > 1000) {
printf("1000 occurred\n");

View File

@@ -1,4 +1,5 @@
/************************************************************************/
/* $Id$ */
/* */
/* L O S A L A M O S */
/* Los Alamos National Laboratory */
@@ -45,6 +46,7 @@
/* 021794 joh turn on SO_REUSEADDR only after the test for */
/* address in use so that test works on UNIX */
/* kernels that support multicast */
/* $Log$ */
/* */
/*_begin */
/************************************************************************/
@@ -95,7 +97,7 @@ LOCAL char *getToken(char **ppString);
*/
int alloc_ioc(
const struct in_addr *pnet_addr,
int port,
unsigned short port,
struct ioc_in_use **ppiiu
)
{
@@ -148,7 +150,7 @@ struct ioc_in_use **ppiiu
int create_net_chan(
struct ioc_in_use **ppiiu,
const struct in_addr *pnet_addr, /* only used by TCP connections */
int port,
unsigned short port,
int net_proto
)
{
@@ -400,7 +402,7 @@ int net_proto
* let slib pick lcl addr
*/
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(0);
saddr.sin_port = htons(0U);
status = bind( sock,
(struct sockaddr *) &saddr,
@@ -1044,6 +1046,16 @@ LOCAL void udp_recv_msg(struct ioc_in_use *piiu)
UNLOCK;
return;
}
# ifdef linux
/*
* Avoid spurious ECONNREFUSED bug
* in linux
*/
if (MYERRNO==ECONNREFUSED) {
UNLOCK;
return;
}
# endif
ca_printf("Unexpected UDP failure %s\n", strerror(MYERRNO));
}
else if(status > 0){
@@ -1196,7 +1208,7 @@ void close_ioc (struct ioc_in_use *piiu)
piiuCast = NULL;
}
else {
chid *pNext;
chid pNext;
/*
* remove IOC from the hash table
@@ -1756,3 +1768,86 @@ unsigned short caFetchPortConfig(ENV_PARAM *pEnv, unsigned short defaultPort)
return port;
}
/*
* CAC_MUX_IO()
*/
void cac_mux_io(struct timeval *ptimeout)
{
int count;
struct timeval timeout;
cac_clean_iiu_list();
/*
* manage search timers and detect disconnects
*/
manage_conn(TRUE);
timeout = *ptimeout;
while (TRUE) {
count = cac_select_io(&timeout, CA_DO_RECVS|CA_DO_SENDS);
if (count<=0) {
/*
* if its a flush then loop until all
* of the send buffers are empty
*/
if (ca_static->ca_flush_pending) {
/*
* complete flush is postponed if we are
* inside an event routine
*/
if (EVENTLOCKTEST) {
break;
}
else {
if (caSendMsgPending()) {
LD_CA_TIME (SELECT_POLL, &timeout);
}
else {
ca_static->ca_flush_pending
= FALSE;
break;
}
}
}
else {
break;
}
}
else {
LD_CA_TIME (0.0, &timeout);
}
ca_process_input_queue();
}
}
/*
* caSendMsgPending()
*/
int caSendMsgPending()
{
int pending = FALSE;
unsigned long bytesPending;
struct ioc_in_use *piiu;
LOCK;
for( piiu = (IIU *) ellFirst(&iiuList);
piiu;
piiu = (IIU *) ellNext(&piiu->node)){
if(piiu == piiuCast || piiu->conn_up == FALSE){
continue;
}
bytesPending = cacRingBufferReadSize(&piiu->send, FALSE);
if(bytesPending > 0U){
pending = TRUE;
}
}
UNLOCK;
return pending;
}

View File

@@ -29,11 +29,20 @@
/* .17 121892 joh added TCP send buf size var */
/* .18 122192 joh added outstanding ack var */
/* .19 012094 joh added minor version (for each server) */
/************************************************************************/
/* $Log$
* Revision 1.49 1995/10/12 01:33:12 jhill
* Initial delay between search frames went from .1 to .01 sec,
* Added flush pending flag, Make all usage of port be unsigned short.
*
* Revision 1.48 1995/09/29 21:55:38 jhill
* added func proto for cacDisconnectChannel()
*
* Revision 1.47 1995/08/22 00:20:27 jhill
* added KLUDGE def of S_db_Pending
* */
/* */
*/
/*_begin */
/************************************************************************/
/* */
@@ -164,8 +173,8 @@ struct putCvrtBuf{
/*
* for use with cac_select_io()
*/
#define CA_DO_SENDS 1
#define CA_DO_RECVS 2
#define CA_DO_SENDS (1<<0)
#define CA_DO_RECVS (1<<1)
struct pending_io_event{
ELLNODE node;
@@ -196,8 +205,12 @@ extern const ca_time CA_CURRENT_TIME;
*/
#define MAXCONNTRIES 30 /* N conn retries on unchanged net */
#define SELECT_POLL (0.05) /* units sec - polls into recast */
#define CA_RECAST_DELAY (0.1) /* initial delay to next recast (sec) */
/*
* NOTE: These must be larger than one vxWorks tick or we will end up
* using the CPU. A vxWorks tick is usually 1/60th of a sec.
*/
#define SELECT_POLL (0.025) /* units sec - polls into recast */
#define CA_RECAST_DELAY (0.025) /* initial delay to next recast (sec) */
#define CA_RECAST_PORT_MASK 0xff /* random retry interval off port */
#define CA_RECAST_PERIOD (5.0) /* ul on retry period long term (sec) */
@@ -438,6 +451,7 @@ struct ca_static{
unsigned ca_post_msg_active:1;
unsigned ca_manage_conn_active:1;
unsigned ca_repeater_contacted:1;
unsigned ca_flush_pending:1;
#if defined(vxWorks)
SEM_ID ca_io_done_sem;
SEM_ID ca_blockSem;
@@ -541,7 +555,7 @@ int post_msg(
);
int alloc_ioc(
const struct in_addr *pnet_addr,
int port,
unsigned short port,
struct ioc_in_use **ppiiu
);
unsigned long cacRingBufferWrite(
@@ -575,7 +589,7 @@ char *localHostName(void);
int create_net_chan(
struct ioc_in_use **ppiiu,
const struct in_addr *pnet_addr, /* only used by TCP connections */
int port,
unsigned short port,
int net_proto
);
@@ -612,8 +626,10 @@ ca_real cac_time_diff(ca_time *pTVA, ca_time *pTVB);
ca_time cac_time_sum(ca_time *pTVA, ca_time *pTVB);
void caIOBlockFree(evid pIOBlock);
void clearChannelResources(unsigned id);
void caSetDefaultPrintfHandler ();
void caSetDefaultPrintfHandler (void);
void cacDisconnectChannel(chid chix, int fullDisconnect);
int caSendMsgPending(void);
/*
* !!KLUDGE!!
*

View File

@@ -25,7 +25,9 @@
* .11 GeG 120992 support VMS/UCX
* .12 CJM 130794 define MYERRNO properly for UCX
* .13 CJM 311094 mods to support DEC C compiler
*
* .14 joh 100695 removed UNIX include of filio.h and sockio.h
* because they are include by ioctl.h under
* BSD and SVR4 (and they dont exist under linux)
*/
#ifndef INCos_depenh
@@ -52,8 +54,13 @@ static char *os_depenhSccsId = "$Id$";
# include <net/if.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <sys/filio.h>
# include <sys/sockio.h>
/*
* normally these are included by ioctl.h
*/
# ifdef SOLARIS
# include <sys/filio.h>
# include <sys/sockio.h>
# endif
# define CA_OS_CONFIGURED
#endif

View File

@@ -29,6 +29,9 @@
* Modification Log:
* -----------------
* $Log$
* Revision 1.15 1995/08/22 00:22:07 jhill
* Dont recompute connection timers if the time stamp hasnt changed
*
*
*/
@@ -54,41 +57,6 @@ void cac_gettimeval(struct timeval *pt)
assert(status == 0);
}
/*
* CAC_MUX_IO()
*
* Asynch notification of incomming messages under UNIX
* 1) Wait no longer than timeout
* 2) Return early if nothing outstanding
*
*
*/
void cac_mux_io(struct timeval *ptimeout)
{
int count;
struct timeval timeout;
cac_clean_iiu_list();
/*
* manage search timers and detect disconnects
*/
manage_conn(TRUE);
timeout = *ptimeout;
do{
count = cac_select_io(
&timeout,
CA_DO_RECVS | CA_DO_SENDS);
ca_process_input_queue();
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
while(count>0);
}
/*
* cac_block_for_io_completion()

View File

@@ -1,4 +1,6 @@
/*
* $Id$
*
* REPEATER.C
*
* CA broadcast repeater
@@ -59,6 +61,8 @@
* .08 102993 joh toggle set sock opt to set
* .09 070195 joh discover client has vanished by connecting its
* datagram socket (and watching for ECONNREFUSED)
*
* $Log$
*/
static char *sccsId = "@(#)$Id$";
@@ -149,6 +153,15 @@ void ca_repeater()
&from_size);
if(size < 0){
# ifdef linux
/*
* Avoid spurious ECONNREFUSED bug
* in linux
*/
if (MYERRNO==ECONNREFUSED) {
continue;
}
# endif
ca_printf("CA Repeater: recv err %s\n",
strerror(MYERRNO));
continue;

View File

@@ -748,7 +748,7 @@ const struct in_addr *pnet_addr
)
{
int v42;
int port;
unsigned short port;
char rej[64];
chid chan;
int status;

View File

@@ -29,6 +29,9 @@
* Modification Log:
* -----------------
* $Log$
* Revision 1.17 1995/09/29 22:13:59 jhill
* check for nill dbr pointer
*
* Revision 1.16 1995/08/22 00:27:55 jhill
* added cvs style mod log
*
@@ -252,7 +255,7 @@ int epicsShareAPI ca_sg_block(CA_SYNC_GID gid, ca_real timeout)
/*
* always flush at least once.
*/
ca_flush_io();
ca_static->ca_flush_pending = TRUE;
cac_gettimeval (&ca_static->currentTime);
beg_time = ca_static->currentTime;

View File

@@ -29,6 +29,9 @@
* Modification Log:
* -----------------
* $Log$
* Revision 1.17 1995/08/22 00:27:56 jhill
* added cvs style mod log
*
*
*/
@@ -56,44 +59,6 @@ void cac_gettimeval(struct timeval *pt)
assert(status==0);
}
/*
* CAC_MUX_IO()
*
* Wait for send ready under VMS
* 1) Wait no longer than timeout
*
* Under VMS all recv's and input processing
* handled by ASTs
*/
void cac_mux_io(struct timeval *ptimeout)
{
int count;
struct timeval timeout;
cac_clean_iiu_list();
/*
* manage search timers and detect disconnects
*/
manage_conn(TRUE);
timeout = *ptimeout;
do{
count = cac_select_io(
&timeout,
CA_DO_RECVS | CA_DO_SENDS);
ca_process_input_queue();
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
while(count>0);
}
/*
* cac_block_for_io_completion()

View File

@@ -29,6 +29,12 @@
* Modification Log:
* -----------------
* $Log$
* Revision 1.20 1995/10/12 01:35:31 jhill
* Moved cac_mux_io() to iocinf.c
*
* Revision 1.19 1995/08/22 00:27:58 jhill
* added cvs style mod log
*
*
*/
@@ -43,6 +49,7 @@ LOCAL int cac_os_depen_exit_tid (struct ca_static *pcas, int tid);
LOCAL int cac_add_task_variable (struct ca_static *ca_temp);
LOCAL void deleteCallBack(CALLBACK *pcb);
/*
* cac_gettimeval()
@@ -86,40 +93,6 @@ void cac_gettimeval(struct timeval *pt)
pt->tv_usec = ((current-sec*rate)*USEC_PER_SEC)/rate;
}
/*
* CAC_MUX_IO()
*
* Asynch notification of send unblocked for vxWorks
* 1) Wait no longer than timeout
* 2) Return early if nothing outstanding
*
*
*/
void cac_mux_io(struct timeval *ptimeout)
{
int count;
struct timeval timeout;
#if NOASYNCRECV
cac_clean_iiu_list();
#endif
timeout = *ptimeout;
do{
count = cac_select_io(
&timeout,
CA_DO_SENDS | CA_DO_RECVS);
timeout.tv_usec = 0;
timeout.tv_sec = 0;
}
while(count>0);
#if NOASYNCRECV
ca_process_input_queue();
manage_conn(TRUE);
#endif
}
/*
* cac_block_for_io_completion()
@@ -130,7 +103,7 @@ void cac_block_for_io_completion(struct timeval *pTV)
unsigned long ticks;
unsigned long rate = sysClkRateGet();
#if NOASYNCRECV
#ifdef NOASYNCRECV
cac_mux_io(pTV);
#else
/*
@@ -198,7 +171,7 @@ void cac_block_for_sg_completion(CASG *pcasg, struct timeval *pTV)
unsigned long ticks;
unsigned long rate = sysClkRateGet();
#if NOASYNCRECV
#ifdef NOASYNCRECV
cac_mux_io(pTV);
#else
/*
@@ -873,17 +846,18 @@ void cac_recv_task(int tid)
* ca_task_exit() is called.
*/
while(TRUE){
#if NOASYNCRECV
#ifdef NOASYNCRECV
taskDelay(60);
#else
cac_clean_iiu_list();
timeout.tv_usec = 50000;
/*
* NOTE: this must be longer than one vxWorks
* tick or we will infinite loop
*/
timeout.tv_usec = (4*USEC_PER_SEC)/sysClkRateGet();
timeout.tv_sec = 0;
count = cac_select_io(
&timeout,
CA_DO_SENDS | CA_DO_RECVS);
count = cac_select_io(&timeout, CA_DO_RECVS);
ca_process_input_queue();
manage_conn(TRUE);
#endif

View File

@@ -13,6 +13,7 @@
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
@@ -26,17 +27,18 @@
* Advanced Photon Source
* Argonne National Laboratory
*
* Lawrence Berkley National Laboratory
* Lawrence Berkley National Laboratory
*
* Modification Log:
* -----------------
*
*/
/*
* Windows includes
*/
#include <windows.h>
#include <process.h>
#include <mmsystem.h>
#include "iocinf.h"
@@ -44,6 +46,10 @@
#error This source is specific to WIN32
#endif
long offset_time; /* time diff (sec) between 1970 and when windows started */
DWORD prev_time;
static void init_timers();
static int get_subnet_mask ( char SubNetMaskStr[256]);
static int RegTcpParams (char IpAddr[256], char SubNetMask[256]);
static int RegKeyData (CHAR *RegPath, HANDLE hKeyRoot, LPSTR lpzValueName,
@@ -55,47 +61,25 @@ static int RegKeyData (CHAR *RegPath, HANDLE hKeyRoot, LPSTR lpzValueName,
*/
void cac_gettimeval(struct timeval *pt)
{
SYSTEMTIME st;
/**
The multi-media timers used here should be good to a millisecond
resolution. However, since the timer rolls back to 0 every 49.7
days (2^32 ms, 4,294,967.296 sec), it's not very good for
time stamping over long periods (if Windows is restarted more
often than 49 days, it wont be a problem). An attempt is made
to keep the time returned increasing, but there is no guarantee
the UTC time is right after 49 days.
**/
GetSystemTime(&st);
pt->tv_sec = time(NULL);
pt->tv_usec = st.wMilliseconds*1000;
}
DWORD win_sys_time; /* time (ms) since windows started */
/*
* CAC_MUX_IO()
*
* Asynch notification of incomming messages under UNIX
* 1) Wait no longer than timeout
* 2) Return early if nothing outstanding
*
*
*/
void cac_mux_io(struct timeval *ptimeout)
{
int count;
struct timeval timeout;
cac_clean_iiu_list();
timeout = *ptimeout;
do{
count = cac_select_io(
&timeout,
CA_DO_RECVS | CA_DO_SENDS);
ca_process_input_queue();
/*
* manage search timers and detect disconnects
*/
manage_conn(TRUE);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
while(count>0);
win_sys_time = timeGetTime();
if (prev_time > win_sys_time) { /* must have been a timer roll-over */
offset_time += 4294967; /* add number of seconds in 49.7 days */
}
pt->tv_sec = (long)win_sys_time/1000 + offset_time; /* time (sec) since 1970 */
pt->tv_usec = (long)((win_sys_time % 1000) * 1000);
prev_time = win_sys_time;
}
@@ -138,8 +122,7 @@ void cac_block_for_sg_completion(CASG *pcasg, struct timeval *pTV)
*/
int cac_os_depen_init(struct ca_static *pcas)
{
int status;
WSADATA WsaData;
int status;
ca_static = pcas;
@@ -153,10 +136,7 @@ int cac_os_depen_init(struct ca_static *pcas)
/* signal(SIGPIPE,SIG_IGN); */
# ifdef _WINSOCKAPI_
status = WSAStartup(MAKEWORD(1,1), &WsaData);
assert (status==0);
# endif
/* DllMain does most OS dependent init & cleanup */
status = ca_os_independent_init ();
@@ -450,7 +430,6 @@ static int RegKeyData (CHAR *RegPath, HANDLE hKeyRoot, LPSTR lpzValueName,
retCode = RegQueryValueEx (hKey, // Key handle returned from
RegOpenKeyEx.
lpzValueName, // Name of value.
NULL, // Reserved, dword = NULL.
lpdwType, // Type of data.
@@ -471,37 +450,56 @@ BOOL epicsShareAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
int status;
WSADATA WsaData;
TIMECAPS tc;
UINT wTimerRes;
switch (dwReason) {
case DLL_PROCESS_ATTACH:
if ((status = WSAStartup(MAKEWORD(1,1), &WsaData)) != 0)
return FALSE;
#if _DEBUG
#if _DEBUG /* for gui applications, setup console for error messages */
if (AllocConsole()) {
SetConsoleTitle("Channel Access Status");
freopen( "CONOUT$", "a", stderr );
fprintf(stderr, "Process attached to ca.dll R12\n");
}
#endif
fprintf(stderr, "Process attached to ca.dll R3.12.1\n");
#endif /* init. winsock */
if ((status = WSAStartup(MAKEWORD(1,1), &WsaData)) != 0) {
fprintf(stderr,"Cant init winsock \n");
return FALSE;
}
/* setup multi-media timer */
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
fprintf(stderr,"cant get timer info \n");
return FALSE;
}
/* set for 1 ms resoulution */
wTimerRes = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
status = timeBeginPeriod(wTimerRes);
if (status != TIMERR_NOERROR)
fprintf(stderr,"timer setup failed\n");
offset_time = (long)time(NULL) - (long)timeGetTime()/1000;
prev_time = timeGetTime();
break;
case DLL_PROCESS_DETACH:
timeEndPeriod(wTimerRes);
if ((status = WSACleanup()) !=0)
return FALSE;
break;
case DLL_THREAD_ATTACH:
#if _DEBUG
fprintf(stderr, "Thread attached to ca.dll R12\n");
fprintf(stderr, "Thread attached to ca.dll R3.12.1\n");
#endif
break;
case DLL_THREAD_DETACH:
#if _DEBUG
fprintf(stderr, "Thread detached from ca.dll R12\n");
fprintf(stderr, "Thread detached from ca.dll R3.12.1\n");
#endif
break;
@@ -511,6 +509,8 @@ BOOL epicsShareAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
return TRUE;
}

View File

@@ -45,6 +45,7 @@
#include <sys/types.h>
#include <string.h>
#include <dbDefs.h>
#include <dbStaticLib.h>
#include <errno.h>
#else
#include <vxWorks.h>
@@ -74,8 +75,7 @@
#include <sdrHeader.h>
#ifndef vxWorks
struct dbBase *pdbBase=NULL;
extern long dbLoad();
DBBASE *pdbBase=NULL;
#ifndef MYERRNO
#define MYERRNO (int errno)
#endif
@@ -163,14 +163,25 @@ static struct PRTAB {
#ifndef vxWorks
main()
{
/* load the default.dctsdr file */
long status;
FILE *fp;
status=dbRead(&pdbBase, "default.dctsdr");
/* Create the database */
pdbBase=dbAllocBase();
/* open the default.dctsdr file */
if ((fp = fopen("default.dctsdr", "rb")) == NULL) {
printf("dbls can't open default.dctsdr\n");
return(-1);
}
/* read in the database */
status=dbRead(pdbBase, fp);
if(status!=0) {
printf("dbls aborting because dbRead failed\n");
return(-1);
}
fclose(fp);
dbls();
return(0);
}

View File

@@ -202,9 +202,9 @@ void recGblGetGraphicDouble(struct dbAddr *paddr,struct dbr_grDouble *pgd)
void recGblGetAlarmDouble(struct dbAddr *paddr,struct dbr_alDouble *pad)
{
pad->upper_alarm_limit = 0;
pad->upper_alarm_limit = 0;
pad->lower_warning_limit = 0;
pad->upper_warning_limit = 0;
pad->lower_warning_limit = 0;
pad->lower_alarm_limit = 0;
return;
}

View File

@@ -45,10 +45,10 @@ SRCS.c += ../devEventTestIoEvent.c
SRCS.c += ../devHistogramSoft.c
SRCS.c += ../devHistogramTestAsyn.c
SRCS.c += ../devHpe1368a.c
# OBJS += devLiCamac.c
# SRCS.c += ../devLiCamac.c
SRCS.c += ../devLiSoft.c
SRCS.c += ../devLiSymb.c
# OBJS += devLoCamac.c
# SRCS.c += ../devLoCamac.c
SRCS.c += ../devLoSoft.c
SRCS.c += ../devLoSymb.c
# SRCS.c += ../devMbbiCamac.c
@@ -106,106 +106,7 @@ SRCS.c += ../devABBINARY.c
SRCS.c += ../devABStatus.c
SRCS.c += ../devMpc.c
# LIBOBJS += devAaiCamac.o
# LIBOBJS += devAiCamac.o
LIBOBJS += devAiDvx2502.o
LIBOBJS += devAiKscV215.o
LIBOBJS += devAiSoft.o
LIBOBJS += devAiSoftRaw.o
LIBOBJS += devAiSymb.o
LIBOBJS += devAiTestAsyn.o
LIBOBJS += devAiXy566Di.o
LIBOBJS += devAiXy566DiL.o
LIBOBJS += devAiXy566Se.o
# LIBOBJS += devAaoCamac.o
# LIBOBJS += devAoCamac.o
LIBOBJS += devAoSoft.o
LIBOBJS += devAoSoftRaw.o
LIBOBJS += devAoSymb.o
LIBOBJS += devAoTestAsyn.o
LIBOBJS += devAoVmiVme4100.o
LIBOBJS += devApsEg.o
LIBOBJS += devApsEr.o
LIBOBJS += devAt5Vxi.o
LIBOBJS += devAt8Fp.o
LIBOBJS += devAvme9440.o
# LIBOBJS += devBiCamac.o
LIBOBJS += devBiMpv910.o
LIBOBJS += devBiSoft.o
LIBOBJS += devBiSoftRaw.o
LIBOBJS += devBiTestAsyn.o
LIBOBJS += devBiXVme210.o
# LIBOBJS += devBoCamac.o
LIBOBJS += devBoMpv902.o
LIBOBJS += devBoSoft.o
LIBOBJS += devBoSoftRaw.o
LIBOBJS += devBoTestAsyn.o
LIBOBJS += devBoXVme220.o
LIBOBJS += devCommonGpib.o
LIBOBJS += devEventSoft.o
LIBOBJS += devEventTestIoEvent.o
LIBOBJS += devHistogramSoft.o
LIBOBJS += devHistogramTestAsyn.o
LIBOBJS += devHpe1368a.o
# LIBOBJS += devLiCamac.o
LIBOBJS += devLiSoft.o
LIBOBJS += devLiSymb.o
# LIBOBJS += devLoCamac.o
LIBOBJS += devLoSoft.o
LIBOBJS += devLoSymb.o
# LIBOBJS += devMbbiCamac.o
# LIBOBJS += devMbbiDirectCamac.o
LIBOBJS += devMbbiDirectMpv910.o
LIBOBJS += devMbbiDirectSoft.o
LIBOBJS += devMbbiDirectSoftRaw.o
LIBOBJS += devMbbiDirectXVme210.o
LIBOBJS += devMbbiMpv910.o
LIBOBJS += devMbbiSoft.o
LIBOBJS += devMbbiSoftRaw.o
LIBOBJS += devMbbiTestAsyn.o
LIBOBJS += devMbbiXVme210.o
# LIBOBJS += devMbboCamac.o
# LIBOBJS += devMbboDirectCamac.o
LIBOBJS += devMbboDirectMpv902.o
LIBOBJS += devMbboDirectSoft.o
LIBOBJS += devMbboDirectSoftRaw.o
LIBOBJS += devMbboDirectXVme220.o
LIBOBJS += devMbboMpv902.o
LIBOBJS += devMbboSoft.o
LIBOBJS += devMbboSoftRaw.o
LIBOBJS += devMbboTestAsyn.o
LIBOBJS += devMbboXVme220.o
LIBOBJS += devMz8310.o
LIBOBJS += devPtSoft.o
LIBOBJS += devSASoft.o
LIBOBJS += devSiSoft.o
LIBOBJS += devSiSymb.o
LIBOBJS += devSiTestAsyn.o
LIBOBJS += devSmCompumotor1830.o
LIBOBJS += devSmOms6Axis.o
LIBOBJS += devSoSoft.o
LIBOBJS += devSoSymb.o
LIBOBJS += devSoTestAsyn.o
LIBOBJS += devSysmon.o
LIBOBJS += devTimerMz8310.o
LIBOBJS += devVxiTDM.o
# LIBOBJS += devWfCamac.o
LIBOBJS += devWfComet.o
LIBOBJS += devWfDvx2502.o
LIBOBJS += devWfJoergerVtr1.o
LIBOBJS += devWfSoft.o
LIBOBJS += devWfTestAsyn.o
LIBOBJS += devWfXy566Sc.o
LIBOBJS += devWfPentek4261.o
LIBOBJS += devXy240.o
LIBOBJS += devAB1771IFE.o
LIBOBJS += devAB1771IL.o
LIBOBJS += devAB1771IR.o
LIBOBJS += devAB1771IXE.o
LIBOBJS += devAB1771OFE.o
LIBOBJS += devABBINARY.o
LIBOBJS += devABStatus.o
LIBOBJS += devMpc.o
LIBOBJS = $(SRCS.c:../%.c=%.o)
LIBNAME = devSup

View File

@@ -15,16 +15,7 @@ SRCS.c += ../devXxDc5009Gpib.c
SRCS.c += ../devXxK263Gpib.c
SRCS.c += ../devXxSkeletonGpib.c
LIBOBJS += devAnalytekGpib.o
LIBOBJS += devXxDg535Gpib.o
LIBOBJS += devBBInteract.o
LIBOBJS += devGpibInteract.o
LIBOBJS += devXxSr620Gpib.o
LIBOBJS += devK486Gpib.o
LIBOBJS += devXxK196Gpib.o
LIBOBJS += devXxDc5009Gpib.o
LIBOBJS += devXxK263Gpib.o
LIBOBJS += devXxSkeletonGpib.o
LIBOBJS = $(SRCS.c:../%.c=%.o)
LIBNAME = devLibOpt

View File

@@ -23,18 +23,7 @@ SRCS.c += ../drvStc.c
SRCS.c += ../drvTime.c
# SRCS.c += ../drvCaenV265.c
TARGETS += drvAb.o
TARGETS += drvAt5Vxi.o
TARGETS += drvEpvxi.o
TARGETS += drvEpvxiMsg.o
TARGETS += drvHp1404a.o
TARGETS += drvHpe1368a.o
TARGETS += drvHpe1445a.o
TARGETS += drvKscV215.o
TARGETS += drvMz8310.o
TARGETS += drvStc.o
TARGETS += drvTime.o
# TARGETS += drvCaenV265.o
TARGETS = $(SRCS.c:../%.c=%.o)
include $(EPICS)/config/RULES.Vx

View File

@@ -30,27 +30,7 @@ SRCS.c += ../drvXy220.c
SRCS.c += ../drvXy240.c
SRCS.c += ../drvXy566.c
TARGETS += module_types.o
TARGETS += drvBB232.o
TARGETS += drvBb902.o
TARGETS += drvBb910.o
TARGETS += drvBitBus.o
TARGETS += drvComet.o
TARGETS += drvCompuSm.o
TARGETS += drvDvx.o
TARGETS += drvFp.o
TARGETS += drvFpm.o
TARGETS += drvGpib.o
TARGETS += drvJgvtr1.o
TARGETS += drvMsg.o
TARGETS += drvOms.o
# TARGETS += drvTranServ.o
TARGETS += drvVmi4100.o
TARGETS += drvXy010.o
TARGETS += drvXy210.o
TARGETS += drvXy220.o
TARGETS += drvXy240.o
TARGETS += drvXy566.o
TARGETS = $(SRCS.c:../%.c=%.o)
include $(EPICS)/config/RULES.Vx

View File

@@ -151,7 +151,8 @@ int cvtDoubleToString(
/* can this routine handle this conversion */
if (precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) {
if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) {
sprintf(pstr_value,"%12.5e\0",flt_value);
sprintf(pstr_value,"%*.*e\0",precision+7,precision,
flt_value);
} else {
sprintf(pstr_value,"%.0f\0",flt_value);
}

View File

@@ -151,7 +151,8 @@ int cvtDoubleToString(
/* can this routine handle this conversion */
if (precision > 8 || flt_value > 10000000.0 || flt_value < -10000000.0) {
if (precision > 8 || flt_value > 1e16 || flt_value < -1e16) {
sprintf(pstr_value,"%12.5e\0",flt_value);
sprintf(pstr_value,"%*.*e\0",precision+7,precision,
flt_value);
} else {
sprintf(pstr_value,"%.0f\0",flt_value);
}

View File

@@ -32,6 +32,8 @@
* vars under vxWorks
* .05 04-20-95 anj changes to use CONFIG_ENV
* .06 05-24-95 joh added return stmnt to epicsPrtEnvParams()
* .07 11-03-96 joh fixed bug occuring when diagnostic is
* printed and the env var cant be found
*
* make options
* -DvxWorks makes a version for VxWorks
@@ -195,8 +197,9 @@ double *pDouble; /* O pointer to place to store value */
if (count == 1) {
return 0;
}
(void)printf("Unable to find a real number in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}
@@ -250,8 +253,9 @@ struct in_addr *pAddr; /* O pointer to struct to receive inet addr */
pAddr->s_addr = status;
return 0;
}
(void)printf("Unable to find an IP address in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}
@@ -303,8 +307,9 @@ long *pLong; /* O pointer to place to store value */
count = sscanf(text, "%ld", pLong);
if (count == 1)
return 0;
(void)printf("Unable to find an integer in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}

View File

@@ -32,6 +32,8 @@
* vars under vxWorks
* .05 04-20-95 anj changes to use CONFIG_ENV
* .06 05-24-95 joh added return stmnt to epicsPrtEnvParams()
* .07 11-03-96 joh fixed bug occuring when diagnostic is
* printed and the env var cant be found
*
* make options
* -DvxWorks makes a version for VxWorks
@@ -195,8 +197,9 @@ double *pDouble; /* O pointer to place to store value */
if (count == 1) {
return 0;
}
(void)printf("Unable to find a real number in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}
@@ -250,8 +253,9 @@ struct in_addr *pAddr; /* O pointer to struct to receive inet addr */
pAddr->s_addr = status;
return 0;
}
(void)printf("Unable to find an IP address in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}
@@ -303,8 +307,9 @@ long *pLong; /* O pointer to place to store value */
count = sscanf(text, "%ld", pLong);
if (count == 1)
return 0;
(void)printf("Unable to find an integer in %s=%s\n",
pParam->name, text);
}
(void)printf("illegal value for %s:%s\n", pParam->name, text);
return -1;
}

View File

@@ -27,6 +27,7 @@
* Modification Log: errPrintfVX.c
* -----------------
* .01 02-16-95 mrk Extracted from errSymLib.c
* $Log$
***************************************************************************
*/
@@ -59,8 +60,6 @@
static int mprintf (const char *pFormat, ...);
static int vmprintf (const char *pFormat, va_list pvar);
extern FILE *iocLogFile;
LOCAL SEM_ID clientWaitForTask;
LOCAL SEM_ID clientWaitForCompletion;
LOCAL SEM_ID serverWaitForWork;
@@ -263,8 +262,7 @@ LOCAL int vmprintf (const char *pFormat, va_list pvar)
s0 = vfprintf(stdout,pFormat,pvar);
fflush(stdout);
s1 = vfprintf(iocLogFile,pFormat,pvar);
fflush(iocLogFile);
s1 = iocLogVPrintf(pFormat,pvar);
va_end(pvar);
if (s1<0) {
return s1;

View File

@@ -70,6 +70,7 @@
* routines in a backwards compatible way so that
* we eliminate delete ambiguity (chance of the same
* being reused).
* $Log$
*
* NOTES:
*

View File

@@ -807,6 +807,13 @@ struct tsDetail *pT; /* I pointer to time structure to convert */
else if (pT->dstOverlapChar == 'd')
dst = 1;
}
/*----------------------------------------------------------------------------
* assume no DST if tsMinWest is 600 (includes Hawaii and may be
* exclusively Hawaii?). (WFL, 95/08/15)
*----------------------------------------------------------------------------*/
if (tsMinWest == 600)
dst = 0;
if (dst)
stamp.secPastEpoch -= TS_DST_HRS_ADD * 3600;
stamp.secPastEpoch += tsMinWest*60;
@@ -869,6 +876,13 @@ struct tsDetail *pT; /* O pointer to time structure for conversion */
dst = 1;
}
/*----------------------------------------------------------------------------
* assume no DST if tsMinWest is 600 (includes Hawaii and may be
* exclusively Hawaii?). (WFL, 95/08/15)
*----------------------------------------------------------------------------*/
if (tsMinWest == 600)
dst = 0;
/*----------------------------------------------------------------------------
* now, if necessary, change the time stamp to daylight and then convert
* the resultant stamp to local time.

View File

@@ -1,5 +1,4 @@
/* $Id$
* archive logMsg() from several IOC's to a common rotating file
*
*
* Author: Jeffrey O. Hill
@@ -33,64 +32,114 @@
* .00 joh 080791 Created
* .01 joh 081591 Added epics env config
* .02 joh 011995 Allow stdio also
* $Log$
*/
#include <string.h>
#include <stdio.h>
#include <vxWorks.h>
#include <ioLib.h>
#include <taskLib.h>
#include <errno.h>
#include <assert.h>
#include <socket.h>
#include <in.h>
#include <inetLib.h>
#include <errnoLib.h>
#include <ioLib.h>
#include <taskLib.h>
#include <logLib.h>
#include <inetLib.h>
#include <sockLib.h>
#include <sysLib.h>
#include <semLib.h>
#include <rebootLib.h>
#include <epicsPrint.h>
#include <envDefs.h>
#include <task_params.h>
LOCAL FILE *iocLogFile = NULL;
LOCAL int iocLogFD = ERROR;
LOCAL int iocLogDisable = 0;
LOCAL unsigned iocLogTries = 0U;
LOCAL unsigned iocLogConnectCount = 0U;
FILE *iocLogFile = NULL;
int iocLogFD = ERROR;
int iocLogDisable;
LOCAL long ioc_log_port;
LOCAL struct in_addr ioc_log_addr;
static long ioc_log_port;
static struct in_addr ioc_log_addr;
int iocLogInit(void);
LOCAL int getConfig(void);
LOCAL void failureNotify(ENV_PARAM *pparam);
LOCAL void logClientShutdown(void);
LOCAL void logRestart(void);
LOCAL int iocLogAttach(void);
LOCAL void logClientRollLocalPort(void);
int iocLogInit();
static int getConfig();
static void failureNoptify();
LOCAL SEM_ID iocLogMutex; /* protects stdio */
LOCAL SEM_ID iocLogSignal; /* reattach to log server */
/*
*
* iocLogInit()
*
*
*/
int
iocLogInit()
int iocLogInit(void)
{
int sock;
struct sockaddr_in addr;
int status;
int status;
int attachStatus;
int options;
if(iocLogDisable){
return OK;
}
options = SEM_Q_PRIORITY|SEM_DELETE_SAFE|SEM_INVERSION_SAFE;
iocLogMutex = semMCreate(options);
if(!iocLogMutex){
return ERROR;
}
iocLogSignal = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
if(!iocLogSignal){
return ERROR;
}
attachStatus = iocLogAttach();
status = rebootHookAdd((FUNCPTR)logClientShutdown);
if (status<0) {
epicsPrintf("Unable to add log server reboot hook\n");
}
status = taskSpawn(
LOG_RESTART_NAME,
LOG_RESTART_PRI,
LOG_RESTART_OPT,
LOG_RESTART_STACK,
(FUNCPTR)logRestart,
0,0,0,0,0,0,0,0,0,0);
if (status<0) {
epicsPrintf("Unable to start log server connection watch dog\n");
}
return attachStatus;
}
/*
* iocLogAttach()
*/
int iocLogAttach(void)
{
int sock;
struct sockaddr_in addr;
int status;
int optval;
FILE *fp;
status = getConfig();
if(status<0){
logMsg (
"iocLogClient: EPICS environment under specified\n",
0,0,0,0,0,0);
logMsg (
"iocLogClient: failed to initialize\n",
0,0,0,0,0,0);
epicsPrintf (
"iocLogClient: EPICS environment under specified\n");
epicsPrintf ("iocLogClient: failed to initialize\n");
return ERROR;
}
@@ -99,9 +148,8 @@ iocLogInit()
SOCK_STREAM, /* type */
0); /* deflt proto */
if (sock < 0){
logMsg( "iocLogClient: no socket errno %d\n",
errnoGet(),
0,0,0,0,0);
epicsPrintf ("iocLogClient: no socket error %s\n",
strerror(errno));
return ERROR;
}
@@ -111,7 +159,7 @@ iocLogInit()
/* set the port */
addr.sin_port = htons(ioc_log_port);
/* set the port */
/* set the addr */
addr.sin_addr.s_addr = ioc_log_addr.s_addr;
/* connect */
@@ -123,25 +171,213 @@ iocLogInit()
char name[INET_ADDR_LEN];
inet_ntoa_b(addr.sin_addr, name);
logMsg(
if (iocLogTries==0U) {
epicsPrintf(
"iocLogClient: unable to connect to %s port %d because \"%s\"\n",
(int) name,
addr.sin_port,
(int) strerror(errnoGet()),
0,0,0);
name,
addr.sin_port,
strerror(errno));
}
iocLogTries++;
close(sock);
return ERROR;
}
logFdAdd (sock);
iocLogTries=0U;
iocLogConnectCount++;
iocLogFile = fdopen (sock, "a");
/*
* discover that the connection has expired
* (after a long delay)
*/
optval = TRUE;
status = setsockopt( sock,
SOL_SOCKET,
SO_KEEPALIVE,
(char *) &optval,
sizeof(optval));
if(status<0){
epicsPrintf ("iocLogClient: %s\n", strerror(errno));
close(sock);
return ERROR;
}
/*
* set how long we will wait for the TCP state machine
* to clean up when we issue a close(). This
* guarantees that messages are serialized when we
* switch connections.
*/
{
struct linger lingerval;
lingerval.l_onoff = TRUE;
lingerval.l_linger = 60*5;
status = setsockopt( sock,
SOL_SOCKET,
SO_LINGER,
(char *) &lingerval,
sizeof(lingerval));
if(status<0){
epicsPrintf ("iocLogClient: %s\n", strerror(errno));
close(sock);
return ERROR;
}
}
fp = fdopen (sock, "a");
/*
* mutex on
*/
status = semTake(iocLogMutex, WAIT_FOREVER);
assert(status==OK);
/*
* close any preexisting connection to the log server
*/
if (iocLogFile) {
logFdDelete(iocLogFD);
fclose(iocLogFile);
iocLogFile = NULL;
iocLogFD = ERROR;
}
else if (iocLogFD!=ERROR) {
logFdDelete(iocLogFD);
close(iocLogFD);
iocLogFD = ERROR;
}
/*
* export the new connection
*/
iocLogFD = sock;
logFdAdd (iocLogFD);
iocLogFile = fp;
/*
* mutex off
*/
status = semGive(iocLogMutex);
assert(status==OK);
return OK;
}
/*
* logRestart()
*/
LOCAL void logRestart(void)
{
int status;
int reattach;
int delay = LOG_RESTART_DELAY;
/*
* roll the local port forward so that we dont collide
* with the first port assigned when we reboot
*/
logClientRollLocalPort();
while (1) {
semTake(iocLogSignal, delay);
/*
* mutex on
*/
status = semTake(iocLogMutex, WAIT_FOREVER);
assert(status==OK);
if (iocLogFile==NULL) {
reattach = TRUE;
}
else {
reattach = ferror(iocLogFile);
}
/*
* mutex off
*/
status = semGive(iocLogMutex);
assert(status==OK);
if (reattach==FALSE) {
continue;
}
/*
* restart log server
*/
iocLogConnectCount = 0U;
logClientRollLocalPort();
}
}
/*
* logClientRollLocalPort()
*/
LOCAL void logClientRollLocalPort(void)
{
int status;
/*
* roll the local port forward so that we dont collide
* with it when we reboot
*/
while (iocLogConnectCount<10U) {
/*
* switch to a new log server connection
*/
status = iocLogAttach();
if (status==OK) {
/*
* only print a message after the first connect
*/
if (iocLogConnectCount==1U) {
printf(
"iocLogClient: reconnected to the log server\n");
}
}
else {
/*
* if we cant connect then we will roll
* the port later when we can
* (we must not spin on connect fail)
*/
if (errno!=ETIMEDOUT) {
return;
}
}
}
}
/*
* logClientShutdown()
*/
LOCAL void logClientShutdown(void)
{
if (iocLogFD!=ERROR) {
/*
* unfortunately this does not currently work because WRS
* runs the reboot hooks in the order the order that
* they are installed (and the network is already shutdown
* by the time we get here)
*/
#if 0
/*
* this aborts the connection because we
* have specified a nill linger interval
*/
printf("log client: lingering for connection close...");
close(iocLogFD);
printf("done\n");
#endif
}
}
/*
@@ -151,8 +387,7 @@ iocLogInit()
*
*
*/
static int
getConfig()
LOCAL int getConfig(void)
{
long status;
@@ -160,7 +395,7 @@ getConfig()
&EPICS_IOC_LOG_PORT,
&ioc_log_port);
if(status<0){
failureNoptify(&EPICS_IOC_LOG_PORT);
failureNotify(&EPICS_IOC_LOG_PORT);
return ERROR;
}
@@ -168,7 +403,7 @@ getConfig()
&EPICS_IOC_LOG_INET,
&ioc_log_addr);
if(status<0){
failureNoptify(&EPICS_IOC_LOG_INET);
failureNotify(&EPICS_IOC_LOG_INET);
return ERROR;
}
@@ -178,42 +413,59 @@ getConfig()
/*
*
* failureNotify()
*
*
*/
static void
failureNoptify(pparam)
ENV_PARAM *pparam;
LOCAL void failureNotify(ENV_PARAM *pparam)
{
logMsg( "IocLogClient: EPICS environment variable \"%s\" undefined\n",
(int) pparam->name,
0,0,0,0,0);
epicsPrintf(
"IocLogClient: EPICS environment variable \"%s\" undefined\n",
pparam->name);
}
/*
*
* unused
*
*
* iocLogVPrintf()
*/
#ifdef JUNKYARD
ioTaskStdSet(taskIdSelf(), 1, sock);
int iocLogVPrintf(const char *pFormat, va_list pvar)
{
int status;
int semStatus;
while (1) {
date();
/*
memShow(0);
i(0);
checkStack(0);
*/
/*
* 60 min
*/
taskDelay(sysClkRateGet() * 60 * 60);
if (!pFormat || iocLogDisable) {
return 0;
}
#endif
/*
* mutex on
*/
semStatus = semTake(iocLogMutex, WAIT_FOREVER);
assert(semStatus==OK);
if (iocLogFile) {
status = vfprintf(iocLogFile, pFormat, pvar);
if (status>0) {
status = fflush(iocLogFile);
}
if (status<0) {
logFdDelete(iocLogFD);
fclose(iocLogFile);
iocLogFile = NULL;
iocLogFD = ERROR;
semStatus = semGive(iocLogSignal);
assert(semStatus==OK);
}
}
else {
status = EOF;
}
/*
* mutex off
*/
semStatus = semGive(iocLogMutex);
assert(semStatus==OK);
return status;
}

View File

@@ -49,50 +49,7 @@ SRCS.c += ../recDynLink.c
SRCS.c += ../recDynLinkTest.c
SRCS.c += ../recWaveform.c
# LIBOBJS += recAai.o
# LIBOBJS += recAao.o
LIBOBJS += recAi.o
LIBOBJS += recAo.o
LIBOBJS += recBi.o
LIBOBJS += recBo.o
LIBOBJS += recCalc.o
LIBOBJS += recCompress.o
LIBOBJS += recDfanout.o
LIBOBJS += recEg.o
LIBOBJS += recEgevent.o
LIBOBJS += recEr.o
LIBOBJS += recErevent.o
LIBOBJS += recEvent.o
LIBOBJS += recFanout.o
# LIBOBJS += recGsub.o
LIBOBJS += recHistogram.o
LIBOBJS += recLongin.o
LIBOBJS += recLongout.o
LIBOBJS += recMbbi.o
LIBOBJS += recMbbiDirect.o
LIBOBJS += recMbbo.o
LIBOBJS += recMbboDirect.o
# LIBOBJS += recPal.o
LIBOBJS += recPermissive.o
LIBOBJS += recPid.o
LIBOBJS += recPulseCounter.o
LIBOBJS += recPulseDelay.o
LIBOBJS += recPulseTrain.o
LIBOBJS += recScan.o
LIBOBJS += recSel.o
LIBOBJS += recSeq.o
LIBOBJS += recState.o
LIBOBJS += recSteppermotor.o
LIBOBJS += recStringin.o
LIBOBJS += recStringout.o
LIBOBJS += recSub.o
LIBOBJS += recSubArray.o
LIBOBJS += recTimer.o
LIBOBJS += recWait.o
LIBOBJS += recWaitCa.o
LIBOBJS += recDynLink.o
LIBOBJS += recDynLinkTest.o
LIBOBJS += recWaveform.o
LIBOBJS = $(SRCS.c:../%.c=%.o)
LIBNAME = recSup

View File

@@ -406,7 +406,7 @@ static void monitor(pcalc)
/* check all input fields for changes*/
for(i=0, pnew=&pcalc->a, pprev=&pcalc->la; i<ARG_MAX; i++, pnew++, pprev++) {
if((*pnew != *pprev) || (monitor_mask&DBE_ALARM)) {
db_post_events(pcalc,pnew,monitor_mask|DBE_VALUE);
db_post_events(pcalc,pnew,monitor_mask|DBE_VALUE|DBE_LOG);
*pprev = *pnew;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -94,6 +94,8 @@
* Stops
* .36 09-15-93 mrk call monitor when starting
* .37 03-29-94 mcn converted to fast links
* .38 09-27-95 lrd fix init to limit in overshoot check and retry
* post monitors for mcw and mccw
*/
#include <vxWorks.h>
@@ -524,14 +526,18 @@ struct steppermotorRecord *psm;
if (psm->mcw != psm_data->cw_limit){
psm->mcw = psm_data->cw_limit;
psm->cw = (psm->mcw)?0:1; /* change sense for VMS OPI */
if (psm->mlis.count)
if (psm->mlis.count){
db_post_events(psm,&psm->cw,DBE_VALUE|DBE_LOG);
db_post_events(psm,&psm->mcw,DBE_VALUE|DBE_LOG);
}
}
if (psm->mccw != psm_data->ccw_limit){
psm->mccw = psm_data->ccw_limit;
psm->ccw = (psm->mccw)?0:1; /* change sense for VMS OPI */
if (psm->mlis.count)
if (psm->mlis.count){
db_post_events(psm,&psm->ccw,DBE_VALUE|DBE_LOG);
db_post_events(psm,&psm->mccw,DBE_VALUE|DBE_LOG);
}
}
/* alarm conditions for limit switches */
@@ -565,7 +571,7 @@ struct steppermotorRecord *psm;
db_post_events(psm,&psm->sevr,DBE_VALUE|DBE_LOG);
}
/* stop motor on overshoot */
if (psm->movn){
if ((psm->movn) && (psm->init == 1)){
if (psm->posm){ /* moving in the positive direction */
if (psm->rbv > (psm->val + psm->rdbd))
(*pdset->sm_command)(psm,SM_MOTION,0,0);
@@ -574,7 +580,7 @@ struct steppermotorRecord *psm;
(*pdset->sm_command)(psm,SM_MOTION,0,0);
}
}
if(!psm->movn) {
if((!psm->movn) && (psm->init == 1)) {
/* difference between desired position and readback pos */
if ( (psm->rbv < (psm->val - psm->rdbd))
|| (psm->rbv > (psm->val + psm->rdbd)) ){
@@ -590,6 +596,7 @@ struct steppermotorRecord *psm;
/* should we retry */
if (psm->rcnt < psm->rtry){
/* convert */
temp = psm->val / psm->dist;
psm->rval = temp;
@@ -680,9 +687,9 @@ struct steppermotorRecord *psm;
if (psm->mode == POSITION){
if (psm->ialg != 0){
if (psm->ialg == POSITIVE_LIMIT){
status = (*pdset->sm_command)(psm,SM_MOVE,0x0fffffff,0);
status = (*pdset->sm_command)(psm,SM_MOVE,0x0fffff,0);
}else if (psm->ialg == NEGATIVE_LIMIT){
status = (*pdset->sm_command)(psm,SM_MOVE,-0x0fffffff,0);
status = (*pdset->sm_command)(psm,SM_MOVE,-0x0fffff,0);
}
psm->sthm = 1;
/* force a read of the position and status */
@@ -947,3 +954,4 @@ struct steppermotorRecord *psm;
}
}

View File

@@ -389,7 +389,7 @@ static void monitor(psub)
/* check all input fields for changes*/
for(i=0, pnew=&psub->a, pprev=&psub->la; i<ARG_MAX; i++, pnew++, pprev++) {
if(*pnew != *pprev) {
db_post_events(psub,pnew,monitor_mask|DBE_VALUE);
db_post_events(psub,pnew,monitor_mask|DBE_VALUE|DBE_LOG);
*pprev = *pnew;
}
}

View File

@@ -30,27 +30,38 @@
* 1.01 05-31-94 nda initial try
* 1.02 07-11-94 mrk/nda added "process on input change" feature
* 1.03 08-16-94 mrk/nda continuing "process on input change" feature
* 1.04 08-16-94 nda record does not get notified when a SCAN related field changes,
* so for now we have to always add monitors. Search for MON_ALWAYS
* Modifications for this are flagged with MON_ALWAYS
* 1.05 08-18-94 nda Starting with R3.11.6, dbGetField locks the record before fetching
* the data. This can cause deadlocks within a database. Change all
* 1.04 08-16-94 nda record does not get notified when a SCAN
* related field changes,so for now we have to
* always add Monitors
* 1.05 08-18-94 nda Starting with R3.11.6, dbGetField locks the
* record before fetching the data. This can
* cause deadlocks within a database. Change all
* dbGetField() to dbGet()
* 1.06 08-19-94 nda added Output data option of VAL or DOL
* 1.07 09-14-94 nda corrected bug that caused SCAN_DISABLE to lock up the record forever
* 1.06 08-19-94 nda added Output data option of VAL or DOL
* 1.07 09-14-94 nda corrected bug that caused SCAN_DISABLE to
* lock up the record forever
* 1.08 02-01-95 nda added VERS and ODLY (output execution delay)
* 1.09 02-15-95 nda addedd INxP to determine which inputs should cause the record
* to process when in I/O INTR mode.
* 2.00 02-20-95 nda added queuing to SCAN_IO_EVENT mode so no transitions of data
* would be missed. Can put back to cached mode by setting
* recWaitCacheMode (effects all wait records !)
* 1.09 02-15-95 nda added INxP to specify which inputs should
* cause the record to process when in I/O INTR
* 2.00 02-20-95 nda added queuing to SCAN_IO_EVENT mode so no
* transitions of data would be missed.
* 2.01 08-07-95 nda Multiple records with DOLN's didn't work,
* added calloc for dola structure.
* 3.00 08-28-95 nda Significant rewrite to add Channel Access
* for dynamic links using recDynLink.c . All
* inputs are now "monitored" via Channel Access.
* Removed some "callbacks" because recDynLink
* lib uses it's own task context.
* INxV field is used to keep track of PV
* connection status: 0-PV_OK,
* 1-NotConnected, 2-NO_PV
* 3.01 10-03-95 nda Also post monitors on .la, .lb, .lc etc
* when new values are written
*
*
*/
#define VERSION 2.01
#define VERSION 3.01
@@ -82,7 +93,7 @@
#include <choiceWait.h>
#include <waitRecord.h>
#include <recWaitCa.h>
#include <recDynLink.h>
/* Create RSET - Record Support Entry Table*/
@@ -146,9 +157,17 @@ struct {
/* DEFINES */
#define ARG_MAX 12
#define PVN_SIZE 40 /* must match the string length defined in waitRecord.ascii */
#define ARG_MAX 12 /* Number of input arguments of the record */
#define IN_PVS 1 /* Number of other input dynamic links(DOLN) */
#define OUT_PVS 1 /* Number of "non-input" dynamic links(OUTN) */
#define DOL_INDEX ARG_MAX
#define OUT_INDEX (ARG_MAX + IN_PVS)
#define NUM_LINKS (ARG_MAX + IN_PVS + OUT_PVS)
#define PVN_SIZE 40 /*must match the length defined in waitRecord.ascii*/
#define Q_SIZE 50
#define PV_OK REC_WAIT_DYNL_OK /* from choiceWait.h */
#define PV_NC REC_WAIT_DYNL_NC /* from choiceWait.h */
#define NO_PV REC_WAIT_DYNL_NO_PV /* from choiceWait.h */
/**********************************************
Declare constants and structures
@@ -156,24 +175,29 @@ struct {
/* callback structures and record private data */
struct cbStruct {
CALLBACK doOutCb; /* callback structure for executing the output link */
CALLBACK ioProcCb; /* callback structure for io_event scanning */
struct waitRecord *pwait; /* pointer to wait record which needs work done */
WDOG_ID wd_id; /* Watchdog used for delays */
RECWAITCA inpMonitor[ARG_MAX]; /* required structures for each input variable */
RING_ID monitorQ; /* queue to store ca callback data */
unsigned short inpMonFlag[ARG_MAX];
IOSCANPVT ioscanpvt; /* used for IO_EVENT scanning */
int outputWait; /* flag to indicate waiting to do output */
int procPending; /* flag to indicate record processing is pending */
unsigned long tickStart; /* used for timing */
CALLBACK doOutCb; /* cback struct for doing the OUT link*/
CALLBACK ioProcCb; /* cback struct for io_event scanning */
struct waitRecord *pwait; /* pointer to wait record */
WDOG_ID wd_id; /* Watchdog used for delays */
recDynLink caLinkStruct[NUM_LINKS]; /* req'd for recDynLink*/
RING_ID monitorQ; /* queue to store ca callback data */
IOSCANPVT ioscanpvt; /* used for IO_EVENT scanning */
int outputWait;/* waiting to do output */
int procPending;/*record processing is pending */
unsigned long tickStart; /* used for timing */
};
typedef struct recDynLinkPvt {
struct waitRecord *pwait; /* pointer to wait record */
unsigned short linkIndex; /* specifies which dynamic link */
}recDynLinkPvt;
static long get_ioint_info(cmd,pwait,ppvt)
int cmd;
struct waitRecord *pwait;
IOSCANPVT *ppvt;
int cmd;
struct waitRecord *pwait;
IOSCANPVT *ppvt;
{
*ppvt = (((struct cbStruct *)pwait->cbst)->ioscanpvt);
return(0);
@@ -182,8 +206,8 @@ static long get_ioint_info(cmd,pwait,ppvt)
/* This is the data that will be put on the work queue ring buffer */
struct qStruct {
char inputIndex;
double monData;
char inputIndex;
double monData;
};
@@ -191,14 +215,16 @@ int recWaitDebug=0;
int recWaitCacheMode=0;
static unsigned long tickStart;
static void schedOutput(struct waitRecord *pwait);
static void reqOutput(struct waitRecord *pwait);
static void execOutput(struct cbStruct *pcbst);
static int fetch_values(struct waitRecord *pwait);
static void monitor(struct waitRecord *pwait);
static long initSiml();
static void inputChanged(struct recWaitCa *pcamonitor, char inputIndex, double monData);
static void ioIntProcess(CALLBACK *pioProcCb);
static void pvSearchCallback(recDynLink *precDynLink);
static void pvMonitorCallback(recDynLink *precDynLink);
static void inputChanged(recDynLink *precDynLink);
static long init_record(pwait,pass)
struct waitRecord *pwait;
@@ -209,39 +235,26 @@ static long init_record(pwait,pass)
int i;
char *ppvn[PVN_SIZE];
struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */
long *paddrValid;
unsigned short *pPvStat;
unsigned short *piointInc; /* include for IO_INT ? */
recDynLinkPvt *puserPvt;
char rpbuf[184];
short error_number;
if (pass==0) {
pwait->vers = VERSION;
pwait->inaa = calloc(1,sizeof(struct dbAddr));
pwait->inba = calloc(1,sizeof(struct dbAddr));
pwait->inca = calloc(1,sizeof(struct dbAddr));
pwait->inda = calloc(1,sizeof(struct dbAddr));
pwait->inea = calloc(1,sizeof(struct dbAddr));
pwait->infa = calloc(1,sizeof(struct dbAddr));
pwait->inga = calloc(1,sizeof(struct dbAddr));
pwait->inha = calloc(1,sizeof(struct dbAddr));
pwait->inia = calloc(1,sizeof(struct dbAddr));
pwait->inja = calloc(1,sizeof(struct dbAddr));
pwait->inka = calloc(1,sizeof(struct dbAddr));
pwait->inla = calloc(1,sizeof(struct dbAddr));
pwait->outa = calloc(1,sizeof(struct dbAddr));
pwait->dola = calloc(1,sizeof(struct dbAddr));
pwait->cbst = calloc(1,sizeof(struct cbStruct));
/* init as much as we can */
*ppvn = &pwait->inan[0];
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE) {
((struct cbStruct *)pwait->cbst)->inpMonitor[i].channame = (char *)*ppvn;
((struct cbStruct *)pwait->cbst)->inpMonitor[i].inputIndex = i;
((struct cbStruct *)pwait->cbst)->inpMonitor[i].callback = inputChanged;
((struct cbStruct *)pwait->cbst)->inpMonitor[i].userPvt = pwait;
/* init the private area of the caLinkStruct's */
for(i=0;i<NUM_LINKS; i++) {
((struct cbStruct *)pwait->cbst)->caLinkStruct[i].puserPvt
= calloc(1,sizeof(struct recDynLinkPvt));
puserPvt = ((struct cbStruct *)pwait->cbst)->caLinkStruct[i].puserPvt;
puserPvt->pwait = pwait;
puserPvt->linkIndex = i;
}
/* do scanIoInit here because init_dev doesn't know which record */
@@ -250,23 +263,10 @@ static long init_record(pwait,pass)
return(0);
}
/* Do initial lookup of PV Names to dbAddr's */
/* This is pass == 1, so pwait->cbst is valid */
pcbst = (struct cbStruct *)pwait->cbst;
*ppvn = &pwait->inan[0];
ppdbAddr = (struct dbAddr **)&pwait->inaa;
paddrValid = &pwait->inav;
for(i=0;i<ARG_MAX; i++, *ppvn += PVN_SIZE, ppdbAddr++, paddrValid++) {
*paddrValid = dbNameToAddr(*ppvn, *ppdbAddr);
}
pwait->outv = dbNameToAddr(pwait->outn, (struct dbAddr *)pwait->outa);
pwait->dolv = dbNameToAddr(pwait->doln, (struct dbAddr *)pwait->dola);
pwait->clcv=postfix(pwait->calc,rpbuf,&error_number);
if(pwait->clcv){
recGblRecordError(S_db_badField,(void *)pwait,
@@ -284,36 +284,42 @@ static long init_record(pwait,pass)
callbackSetUser(pwait, &pcbst->ioProcCb);
pcbst->pwait = pwait;
pcbst->wd_id = wdCreate();
if((pcbst->monitorQ = rngCreate(sizeof(struct qStruct) * Q_SIZE)) == NULL) {
if((pcbst->monitorQ=rngCreate(sizeof(struct qStruct)*Q_SIZE)) == NULL) {
errMessage(0,"recWait can't create ring buffer");
exit(1);
}
/* Set up monitors on input channels if scan type is IO Event */
/* MON_ALWAYS if(pwait->scan == SCAN_IO_EVENT) { */
if(1) {
paddrValid = &pwait->inav;
piointInc = &pwait->inap;
for(i=0;i<ARG_MAX; i++, paddrValid++, piointInc++) {
/* store current value in private array */
pcbst->inpMonFlag[i] = *piointInc;
/* if valid PV AND input include flag is true ... */
if(!(*paddrValid) && (*piointInc)) {
if(recWaitDebug) printf("adding monitor on input %d\n", i);
status = recWaitCaAdd(&(((struct cbStruct *)pwait->cbst)->inpMonitor[i]));
if(status) errMessage(status,"recWaitCaAdd error");
}
}
}
if (status=initSiml(pwait)) return(status);
/* reset miscellaneous flags */
pcbst->outputWait = 0;
pcbst->procPending = 0;
pwait->init = TRUE;
/* Do initial lookup of PV Names using recDynLink lib */
*ppvn = &pwait->inan[0];
pPvStat = &pwait->inav;
/* check all dynLinks for non-NULL */
for(i=0;i<NUM_LINKS; i++, pPvStat++, *ppvn += PVN_SIZE) {
if(*ppvn[0] != NULL) {
*pPvStat = PV_NC;
if(i<OUT_INDEX) {
recDynLinkAddInput(&pcbst->caLinkStruct[i], *ppvn,
DBR_DOUBLE, rdlSCALAR, pvSearchCallback, inputChanged);
}
else {
recDynLinkAddOutput(&pcbst->caLinkStruct[i], *ppvn,
DBR_DOUBLE, rdlSCALAR, pvSearchCallback);
}
if(recWaitDebug > 5) printf("Search during init\n");
}
else {
*pPvStat = NO_PV;
}
}
pwait->init = TRUE;
return(0);
}
@@ -341,11 +347,14 @@ static long process(pwait)
recGblSetSevr(pwait,CALC_ALARM,INVALID_ALARM);
} else pwait->udf = FALSE;
}
else {
recGblSetSevr(pwait,READ_ALARM,INVALID_ALARM);
}
}
else { /* SIMULATION MODE */
nRequest = 1;
status = recGblGetLinkValue(&(pwait->siol),
(void *)pwait,DBR_DOUBLE,&(pwait->sval),&options,&nRequest);
status = recGblGetLinkValue(&(pwait->siol),
(void *)pwait,DBR_DOUBLE,&(pwait->sval),&options,&nRequest);
if (status==0){
pwait->val=pwait->sval;
pwait->udf=FALSE;
@@ -413,141 +422,59 @@ static long special(paddr,after)
struct cbStruct *pcbst = (struct cbStruct *)pwait->cbst;
int special_type = paddr->special;
char *ppvn[PVN_SIZE];
struct dbAddr **ppdbAddr; /* ptr to a ptr to dbAddr */
long *paddrValid;
unsigned short *pPvStat;
unsigned short *piointInc; /* include for IO_INT ? */
int i;
unsigned short oldStat;
int index;
long status;
long odbv =0;
short error_number;
char rpbuf[184];
if(recWaitDebug) printf("entering special %d \n",after);
if(!after) { /* this is called before ca changes the field */
/* MON_ALWAYS This case doesn't currently happen */
if((special_type == SPC_SCAN) && (pwait->scan == SCAN_IO_EVENT)) {
/* Leaving IO_EVENT, delete monitors */
paddrValid = &pwait->inav;
for(i=0;i<ARG_MAX; i++, paddrValid++) {
if(!(*paddrValid)) {
if(recWaitDebug) printf("deleting monitor\n");
status = recWaitCaDelete(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaDelete error");
}
}
return(0);
}
/* check if changing any Input PV names while monitored */
if((paddr->pfield >= (void *)pwait->inan) &&
(paddr->pfield <= (void *)pwait->inln)) {
/* About to change a PV, delete that particular monitor */
i = special_type - REC_WAIT_A; /* index of input */
paddrValid = &pwait->inav + i; /* pointer arithmetic */
piointInc = &pwait->inap + i; /* pointer arithmetic */
/* If PV name is valid and the INxP flag is true, ... */
if(!(*paddrValid) && (*piointInc)) {
if(recWaitDebug) printf("deleting monitor on input %d\n",i);
status = recWaitCaDelete(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaDelete error");
/* check if changing any dynamic link names */
/* This is where one would do a recDynLinkClear, but it is
not required prior to a new search */
return(0);
}
/* this is executed after ca changed the field */
if((special_type >= REC_WAIT_A) &&
(special_type < (REC_WAIT_A + NUM_LINKS))) {
index = special_type - REC_WAIT_A; /* index of input */
pPvStat = &pwait->inav + index; /* pointer arithmetic */
oldStat = *pPvStat;
*ppvn = &pwait->inan[0] + (index*PVN_SIZE);
if(*ppvn[0] != NULL) {
if(recWaitDebug > 5) printf("Search during special \n");
*pPvStat = PV_NC;
/* need to post_event before recDynLinkAddXxx because
SearchCallback could happen immediatley */
if(*pPvStat != oldStat) {
db_post_events(pwait,pPvStat,DBE_VALUE);
}
if(index<OUT_INDEX) {
recDynLinkAddInput(&pcbst->caLinkStruct[index], *ppvn,
DBR_DOUBLE, rdlSCALAR, pvSearchCallback, inputChanged);
}
else {
recDynLinkAddOutput(&pcbst->caLinkStruct[index], *ppvn,
DBR_DOUBLE, rdlSCALAR, pvSearchCallback);
}
}
else if(*pPvStat != NO_PV) {
/* PV is now NULL but didn't used to be */
*pPvStat = NO_PV; /* PV just cleared */
if(*pPvStat != oldStat) {
db_post_events(pwait,pPvStat,DBE_VALUE);
}
recDynLinkClear(&pcbst->caLinkStruct[index]);
}
return(0);
}
/* this is executed after ca changed the field */
switch(special_type) {
case(SPC_SCAN): /* Changed SCAN mechanism, set monitors on input links */
/* MON_ALWAYS This case currently doesn't happen */
if(pwait->scan == SCAN_IO_EVENT) {
paddrValid = &pwait->inav;
for(i=0;i<ARG_MAX; i++, paddrValid++) {
if(!(*paddrValid)) {
if(recWaitDebug) printf("adding monitor on input %d\n", i);
status = recWaitCaAdd(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaAdd error");
}
}
}
return(0);
break;
case(REC_WAIT_A): /* check if changing any input PV's or flags */
case(REC_WAIT_B):
case(REC_WAIT_C):
case(REC_WAIT_D):
case(REC_WAIT_E):
case(REC_WAIT_F):
case(REC_WAIT_G):
case(REC_WAIT_H):
case(REC_WAIT_I):
case(REC_WAIT_J):
case(REC_WAIT_K):
case(REC_WAIT_L):
i = special_type - REC_WAIT_A; /* index of input */
paddrValid = &pwait->inav + i; /* pointer arithmetic */
ppdbAddr = (struct dbAddr **)&pwait->inaa + i; /* pointer arithmetic */
*ppvn = &pwait->inan[0] + (i*PVN_SIZE);
piointInc = &pwait->inap + i; /* pointer arithmetic */
/* If the PV Name changing, do dbNameToAddr */
if(paddr->pfield==*ppvn) {
odbv = *paddrValid;
*paddrValid = dbNameToAddr(*ppvn, *ppdbAddr);
if (odbv != *paddrValid) {
db_post_events(pwait,paddrValid,DBE_VALUE);
}
/* MON_ALWAYS: Should only do if SCAN_IO_EVENT), but can't now */
/* If the INxP flag is set, add a monitor */
if(!(*paddrValid) && (*piointInc)) {
if(recWaitDebug) printf("adding monitor on input %d\n", i);
status = recWaitCaAdd(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaAdd error");
}
}
/* Must be the I/O INTR flag that changed. Compare to previous value */
else {
if(!(*paddrValid) && (*piointInc) && !(pcbst->inpMonFlag[i])) {
if(recWaitDebug) printf("adding monitor on input %d\n", i);
status = recWaitCaAdd(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaAdd error");
}
else if(!(*paddrValid) && !(*piointInc) && (pcbst->inpMonFlag[i])) {
if(recWaitDebug) printf("deleting monitor on input %d\n", i);
status = recWaitCaDelete(&pcbst->inpMonitor[i]);
if(status) errMessage(status,"recWaitCaDelete error");
}
pcbst->inpMonFlag[i] = *piointInc; /* keep track of current val */
}
return(0);
break;
case(SPC_MOD): /* check if changing any other SPC_MOD fields */
if(paddr->pfield==pwait->outn) { /* this is the output link */
odbv = pwait->outv;
pwait->outv = dbNameToAddr(pwait->outn,(struct dbAddr *)pwait->outa);
if (odbv != pwait->outv) {
db_post_events(pwait,&pwait->outv,DBE_VALUE);
}
}
else if(paddr->pfield==pwait->doln) { /* this is the DOL link */
odbv = pwait->dolv;
pwait->dolv = dbNameToAddr(pwait->doln,(struct dbAddr *)pwait->dola);
if (odbv != pwait->dolv) {
db_post_events(pwait,&pwait->dolv,DBE_VALUE);
}
}
else if(paddr->pfield==(void *)&pwait->prio) {
callbackSetPriority(pwait->prio, &((struct cbStruct *)pwait->cbst)->doOutCb);
callbackSetPriority(pwait->prio, &((struct cbStruct *)pwait->cbst)->ioProcCb);
}
return(0);
break;
case(SPC_CALC):
else if(special_type == SPC_CALC) {
pwait->clcv=postfix(pwait->calc,rpbuf,&error_number);
if(pwait->clcv){
recGblRecordError(S_db_badField,(void *)pwait,
@@ -560,8 +487,13 @@ static long special(paddr,after)
db_post_events(pwait,pwait->calc,DBE_VALUE);
db_post_events(pwait,&pwait->clcv,DBE_VALUE);
return(0);
break;
default:
}
else if(paddr->pfield==(void *)&pwait->prio) {
callbackSetPriority(pwait->prio, &pcbst->doOutCb);
callbackSetPriority(pwait->prio, &pcbst->ioProcCb);
return(0);
}
else {
recGblDbaddrError(S_db_badChoice,paddr,"wait: special");
return(S_db_badChoice);
return(0);
@@ -649,12 +581,14 @@ static void monitor(pwait)
db_post_events(pwait,&pwait->val,monitor_mask);
}
/* check all input fields for changes */
for(i=0, pnew=&pwait->a, pprev=&pwait->la; i<ARG_MAX; i++, pnew++, pprev++) {
if(*pnew != *pprev) {
db_post_events(pwait,pnew,monitor_mask|DBE_VALUE);
*pprev = *pnew;
}
}
for(i=0, pnew=&pwait->a, pprev=&pwait->la; i<ARG_MAX;
i++, pnew++, pprev++) {
if(*pnew != *pprev) {
db_post_events(pwait,pnew,monitor_mask|DBE_VALUE);
*pprev = *pnew;
db_post_events(pwait,pprev,monitor_mask|DBE_VALUE);
}
}
return;
}
@@ -703,37 +637,47 @@ struct waitRecord *pwait;
static int fetch_values(pwait)
struct waitRecord *pwait;
{
struct dbAddr **ppdba; /* a ptr to a ptr to dbAddr */
struct cbStruct *pcbst = (struct cbStruct *)pwait->cbst;
double *pvalue;
long *pvalid;
unsigned short *pPvStat;
unsigned short *piointInc; /* include for IO_INT ? */
long status=0,options=0,nRequest=1;
int i;
piointInc = &pwait->inap;
for(i=0, ppdba= (struct dbAddr **)&pwait->inaa, pvalue=&pwait->a, pvalid = &pwait->inav;
i<ARG_MAX; i++, ppdba++, pvalue++, pvalid++, piointInc++) {
for(i=0, pvalue=&pwait->a, pPvStat = &pwait->inav;
i<ARG_MAX; i++, pvalue++, pPvStat++, piointInc++) {
/* only fetch a value if the dbAddr is valid, otherwise, leave it alone */
/* if in SCAN_IO_EVENT, only fetch inputs if INxP != 1 (not monitored) */
if(!(*pvalid) && !((pwait->scan == SCAN_IO_EVENT) && (*piointInc))) {
status = dbGet(*ppdba, DBR_DOUBLE,
pvalue, &options, &nRequest, NULL);
/* if any input should be connected, but is not, return */
if(*pPvStat == PV_NC) {
status = ERROR;
}
/* only fetch a value if the connection is valid */
/* if not in SCAN_IO_EVENT, fetch all valid inputs */
/* if in SCAN_IO_EVENT, only fetch inputs if INxP == 0 */
/* The data from those with INxP=1 comes from the ring buffer */
else if((*pPvStat == PV_OK)&&
((pwait->scan != SCAN_IO_EVENT) ||
((pwait->scan == SCAN_IO_EVENT) && !*piointInc))) {
if(recWaitDebug > 5) printf("Fetching input %d \n",i);
status = recDynLinkGet(&pcbst->caLinkStruct[i], pvalue,
&nRequest, 0, 0, 0);
}
if (!RTN_SUCCESS(status)) return(status);
}
return(0);
}
/******************************************************************************
/***************************************************************************
*
* The following functions schedule and/or request the execution of the output
* PV and output event based on the Output Execution Delay (ODLY).
* If .odly > 0, a watchdog is scheduled; if 0, reqOutput() is called immediately.
* The following functions schedule and/or request the execution of the
* output PV and output event based on the Output Execution Delay (ODLY).
* If .odly > 0, a watchdog is scheduled; if 0, execOutput() is called
* immediately.
* NOTE: THE RECORD REMAINS "ACTIVE" WHILE WAITING ON THE WATCHDOG
*
******************************************************************************/
**************************************************************************/
static void schedOutput(pwait)
struct waitRecord *pwait;
{
@@ -746,26 +690,19 @@ int wdDelay;
/* Use the watch-dog as a delay mechanism */
pcbst->outputWait = 1;
wdDelay = pwait->odly * sysClkRateGet();
wdStart(pcbst->wd_id, wdDelay, (FUNCPTR)reqOutput, (int)(pwait));
wdStart(pcbst->wd_id, wdDelay, (FUNCPTR)execOutput, (int)(pwait->cbst));
} else {
reqOutput(pwait);
execOutput(pwait->cbst);
}
}
static void reqOutput(pwait)
struct waitRecord *pwait;
{
callbackRequest(pwait->cbst);
}
/******************************************************************************
/***************************************************************************
*
* This is the code that is executed by the callback task to do the record
* outputs. It is done with a separate task so one need not worry about
* This code calls recDynLinkPut to execute the output link. Since requests
* recDynLinkPut are done via another task, one need not worry about
* lock sets.
*
******************************************************************************/
***************************************************************************/
void execOutput(pcbst)
struct cbStruct *pcbst;
{
@@ -779,15 +716,15 @@ double oldDold;
if(pcbst->pwait->dopt) {
if(!pcbst->pwait->dolv) {
oldDold = pcbst->pwait->dold;
status = dbGet(pcbst->pwait->dola,DBR_DOUBLE,
&(pcbst->pwait->dold), &options, &nRequest, NULL);
status = recDynLinkGet(&pcbst->caLinkStruct[DOL_INDEX],
&(pcbst->pwait->dold), &nRequest, 0, 0, 0);
if(pcbst->pwait->dold != oldDold)
db_post_events(pcbst->pwait,&pcbst->pwait->dold,DBE_VALUE);
db_post_events(pcbst->pwait,&pcbst->pwait->dold,DBE_VALUE);
}
status = dbPutField(pcbst->pwait->outa,DBR_DOUBLE,
status = recDynLinkPut(&pcbst->caLinkStruct[OUT_INDEX],
&(pcbst->pwait->dold), 1);
} else {
status = dbPutField(pcbst->pwait->outa,DBR_DOUBLE,
status = recDynLinkPut(&pcbst->caLinkStruct[OUT_INDEX],
&(pcbst->pwait->val), 1);
}
}
@@ -811,42 +748,38 @@ double oldDold;
/* This routine is called by the recWaitCaTask whenver a monitored input
changes. The input index and new data is put on a work queue, and a callback
request is issued to the routine ioIntProcess
*/
static void inputChanged(struct recWaitCa *pcamonitor, char inputIndex, double monData)
/* This routine is called by the recDynLink task whenver a monitored input
* changes. If the particular input is flagged to cause record processing,
* The input index and new data are put on a work queue, and a callback
* request is issued to the routine ioIntProcess
*/
static void inputChanged(recDynLink *precDynLink)
{
struct waitRecord *pwait = ((recDynLinkPvt *)precDynLink->puserPvt)->pwait;
struct cbStruct *pcbst = (struct cbStruct *)pwait->cbst;
double monData;
unsigned long nRequest;
long status;
char index;
unsigned short *piointInc;
struct waitRecord *pwait = (struct waitRecord *)pcamonitor->userPvt;
struct cbStruct *pcbst = (struct cbStruct *)pwait->cbst;
/* the next line is here because the monitors are always active ... MON_ALWAYS */
if(pwait->scan != SCAN_IO_EVENT) return;
if(recWaitCacheMode) {
/* if record hasn't been processed or is DISABLED, don't set procPending yet */
if((pwait->stat == DISABLE_ALARM) || pwait->udf) {
if(recWaitDebug>=5) printf("queuing monitor (cached)\n");
callbackRequest(&pcbst->ioProcCb);
} else if(pcbst->procPending) {
/* if(recWaitDebug) printf("discarding monitor\n"); */
printf("discarding monitor\n");
return;
} else {
pcbst->procPending = 1;
if(recWaitDebug>=5) printf("queuing monitor (cached)\n");
callbackRequest(&pcbst->ioProcCb);
}
}
else { /* put input index and monitored data on processing queue */
if(recWaitDebug>=5) printf("queuing monitor on %d = %lf\n", inputIndex, monData);
if(rngBufPut(pcbst->monitorQ, (void *)&inputIndex, sizeof(char))
!= sizeof(char)) errMessage(0,"recWait rngBufPut error");
if(rngBufPut(pcbst->monitorQ, (void *)&monData, sizeof(double))
!= sizeof(double)) errMessage(0,"recWait rngBufPut error");
callbackRequest(&pcbst->ioProcCb);
}
index = (char)((recDynLinkPvt *)precDynLink->puserPvt)->linkIndex;
piointInc = &pwait->inap + index; /* pointer arithmetic */
if(*piointInc == 0) return; /* input cause processing ???*/
/* put input index and monitored data on processing queue */
recDynLinkGet(precDynLink, &monData, &nRequest, 0, 0, 0);
if(recWaitDebug>5)
printf("queuing monitor on %d = %lf\n",index,monData);
if(rngBufPut(pcbst->monitorQ, (void *)&index, sizeof(char))
!= sizeof(char)) errMessage(0,"recWait rngBufPut error");
if(rngBufPut(pcbst->monitorQ, (void *)&monData, sizeof(double))
!= sizeof(double)) errMessage(0,"recWait rngBufPut error");
callbackRequest(&pcbst->ioProcCb);
}
@@ -876,13 +809,15 @@ static void ioIntProcess(CALLBACK *pioProcCb)
if(rngBufGet(pcbst->monitorQ, (void *)&monData, sizeof(double))
!= sizeof(double)) errMessage(0, "recWait: rngBufGet error");
if(recWaitDebug>=5) printf("processing on %d = %lf (%lf)\n", inputIndex, monData,pwait->val);
if(recWaitDebug>=5)
printf("processing on %d = %lf (%lf)\n",
inputIndex, monData,pwait->val);
pInput += inputIndex; /* pointer arithmetic to choose appropriate input */
pInput += inputIndex; /* pointer arithmetic for appropriate input */
dbScanLock((struct dbCommon *)pwait);
*pInput = monData; /* put data in input data field */
*pInput = monData; /* put data in input data field */
/* Process the record, unless it's busy waiting to do the output link */
/* Process the record, unless busy waiting to do the output link */
if(pcbst->outputWait) {
pcbst->procPending = 1;
if(recWaitDebug) printf("record busy, setting procPending\n");
@@ -901,3 +836,32 @@ static void ioIntProcess(CALLBACK *pioProcCb)
}
LOCAL void pvSearchCallback(recDynLink *precDynLink)
{
recDynLinkPvt *puserPvt = (recDynLinkPvt *)precDynLink->puserPvt;
struct waitRecord *pwait = puserPvt->pwait;
unsigned short index = puserPvt->linkIndex;
unsigned short *pPvStat;
unsigned short oldValid;
pPvStat = &pwait->inav + index; /* pointer arithmetic */
puserPvt = (recDynLinkPvt *)precDynLink->puserPvt;
oldValid = *pPvStat;
if(recDynLinkConnectionStatus(precDynLink)) {
*pPvStat = PV_NC;
if(recWaitDebug) printf("Search Callback: No Connection\n");
}
else {
*pPvStat = PV_OK;
if(recWaitDebug) printf("Search Callback: Success\n");
}
if(*pPvStat != oldValid) {
db_post_events(pwait, pPvStat, DBE_VALUE);
}
}

View File

@@ -439,7 +439,7 @@ struct client *client
/*
* user name will not change if there isnt enough memory
*/
pMalloc = malloc(size);
pMalloc = casMalloc(size);
if(!pMalloc){
send_err(
mp,
@@ -498,7 +498,7 @@ struct client *client
/*
* user name will not change if there isnt enough memory
*/
pMalloc = malloc(size);
pMalloc = casMalloc(size);
if(!pMalloc){
send_err(
mp,
@@ -896,7 +896,7 @@ struct client *client
*/
if(!pciu->pPutNotify){
pciu->pPutNotify =
(RSRVPUTNOTIFY *) calloc(1, sizeof(*pciu->pPutNotify)+size);
(RSRVPUTNOTIFY *) casCalloc(1, sizeof(*pciu->pPutNotify)+size);
if(!pciu->pPutNotify){
putNotifyErrorReply(client, mp, ECA_ALLOCMEM);
return;
@@ -1037,7 +1037,7 @@ struct client *client
ellGet(&rsrv_free_eventq);
FASTUNLOCK(&rsrv_free_eventq_lck);
if (!pevext) {
pevext = (struct event_ext *) malloc(size);
pevext = (struct event_ext *) casMalloc(size);
if (!pevext) {
SEND_LOCK(client);
send_err(
@@ -1581,6 +1581,7 @@ struct client *client
unsigned sid;
unsigned long count;
ca_uint16_t type;
int spaceAvailOnFreeList;
/* Exit quickly if channel not on this node */
status = db_name_to_addr(
@@ -1601,9 +1602,12 @@ struct client *client
}
/*
* set true if max memory block drops below MAX_BLOCK_THRESHOLD
* stop further use of server if max block drops
* below MAX_BLOCK_THRESHOLD
*/
if(casDontAllowSearchReplies){
spaceAvailOnFreeList = ellCount(&rsrv_free_clientQ)>0
&& ellCount(&rsrv_free_addrq)>0;
if (casBelowMaxBlockThresh && !spaceAvailOnFreeList) {
SEND_LOCK(client);
send_err(mp,
ECA_ALLOCMEM,
@@ -1696,7 +1700,7 @@ unsigned cid
FASTUNLOCK(&rsrv_free_addrq_lck);
if (!pchannel) {
pchannel = (struct channel_in_use *)
malloc(sizeof(*pchannel));
casMalloc(sizeof(*pchannel));
if (!pchannel) {
return NULL;
}
@@ -1874,7 +1878,7 @@ char *pformat,
case IOC_READ_SYNC:
case IOC_SNAPSHOT:
default:
reply->m_cid = NULL;
reply->m_cid = ~0L;
break;
}
@@ -2111,3 +2115,32 @@ LOCAL void access_rights_reply(struct channel_in_use *pciu)
END_MSG(pclient);
SEND_UNLOCK(pclient);
}
/*
* casCalloc()
*
* (dont drop below some max block threshold)
*/
void *casCalloc(size_t count, size_t size)
{
if (casBelowMaxBlockThresh) {
return NULL;
}
return calloc(count, size);
}
/*
* casMalloc()
*
* (dont drop below some max block threshold)
*/
void *casMalloc(size_t size)
{
if (casBelowMaxBlockThresh) {
return NULL;
}
return malloc(size);
}

View File

@@ -388,7 +388,7 @@ struct client *create_udp_client(unsigned sock)
UNLOCK_CLIENTQ;
if(!client){
client = (struct client *)malloc(sizeof(struct client));
client = (struct client *)casMalloc(sizeof(struct client));
if(!client){
logMsg("CAS: no mem for new client\n",
NULL,
@@ -426,7 +426,7 @@ struct client *create_udp_client(unsigned sock)
/*
* user name initially unknown
*/
client->pUserName = malloc(1);
client->pUserName = casMalloc(1);
if(!client->pUserName){
semDelete(client->blockSem);
free(client);
@@ -437,7 +437,7 @@ struct client *create_udp_client(unsigned sock)
/*
* host name initially unknown
*/
client->pHostName = malloc(1);
client->pHostName = casMalloc(1);
if(!client->pHostName){
semDelete(client->blockSem);
free(client->pUserName);

View File

@@ -162,10 +162,10 @@ int rsrv_online_notify_task()
*/
maxBlock = memFindMax();
if(maxBlock<MAX_BLOCK_THRESHOLD){
casDontAllowSearchReplies = TRUE;
casBelowMaxBlockThresh = TRUE;
}
else{
casDontAllowSearchReplies = FALSE;
casBelowMaxBlockThresh = FALSE;
}
pNode = (caAddrNode *) beaconAddrList.node.next;

View File

@@ -192,7 +192,7 @@ GLBLTYPE BUCKET *pCaBucket;
* set true if max memory block drops below MAX_BLOCK_THRESHOLD
*/
#define MAX_BLOCK_THRESHOLD 100000
GLBLTYPE int casDontAllowSearchReplies;
GLBLTYPE int casBelowMaxBlockThresh;
#define SEND_LOCK(CLIENT)\
{\
@@ -248,6 +248,9 @@ struct client *pc
void write_notify_reply(void *pArg);
void *casMalloc(size_t size);
void *casCalloc(size_t count, size_t size);
/*
* !!KLUDGE!!
*

View File

@@ -1,10 +1,16 @@
#
# $Id$
# Makefile,v 1.2 1995/06/27 15:25:35 wright Exp
#
# Lowest Level Directroy Makefile
# by Janet Anderson
#
# $Log$
# Makefile,v
# Revision 1.2 1995/06/27 15:25:35 wright
# Brought over Andy's sequencer 1.9 files, compiled and created new seq and snc.
#
# Revision 1.1 1994/09/07 19:26:37 jba
# New file
#
#
EPICS=../../..

View File

@@ -11,11 +11,11 @@ YACC = $(EYACC)
USR_LDLIBS = -ll
YACCOPT = -d -v
SRCS.c = ../parse.c ../phase2.c ../gen_ss_code.c \
../gen_tables.c sncVersion.c snc.c
SRCS.c = ../snc_main.c ../parse.c ../phase2.c ../gen_ss_code.c \
../gen_tables.c sncVersion.c snc.c
OBJS = parse.o phase2.o gen_ss_code.o \
gen_tables.o sncVersion.o snc.o
OBJS = snc_main.o parse.o phase2.o gen_ss_code.o \
gen_tables.o sncVersion.o snc.o
PROD = snc
@@ -24,7 +24,7 @@ include $(EPICS)/config/RULES.Unix
#
# The generated lex file includes snc.h
#
snc_lex.c: snc.h
snc_lex.c: snc.h ../snc_lex.l
snc.o: snc_lex.c

View File

@@ -6,19 +6,23 @@ USR_CFLAGS =
SRCS.c = \
../seq_main.c ../seq_ca.c ../seq_qry.c ../seq_task.c \
../seq_mac.c ../seq_prog.c
../seq_mac.c ../seq_prog.c ../seq_if.c
LIBOBJS = \
OBJS = \
seq_main.o seq_ca.o seq_qry.o seq_task.o \
seq_mac.o seq_prog.o seqVersion.o
seq_mac.o seq_prog.o seq_if.o seqVersion.o
LIBNAME = seq
PROD = seq
include $(EPICS)/config/RULES.Vx
clean::
@$(RM) seqVersion.c
seq: $(OBJS)
$(RM) $@
$(LINK.c) $@ $(OBJS) $(LDLIBS)
seqVersion.c: ../Version
$(RM) seqVersion.c
sh ../makeSeqVersion ../Version > seqVersion.c

View File

@@ -1,2 +1,3 @@
1.8.3
1.9.0(3.12.1)

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# epics/release $Id$
# epics/release chmod.sh,v 1.1.1.1 1995/08/15 03:15:26 epicss Exp
# Author: Roger A. Cole (LANL)
# Date: 08-20-91
#

View File

@@ -2,19 +2,20 @@
GTA PROJECT AT division
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
gen_ss_code.c,v 1.2 1995/06/27 15:25:43 wright Exp
DESCRIPTION: gen_ss_code.c -- routines to generate state set code
ENVIRONMENT: UNIX
HISTORY:
19nov91,ajk Changed find_var() to findVar().
28apr92,ajk Implemented efClear() & efTestAndClear().
01mar94,ajk Changed table generation to the new structures defined
in seqCom.h.
***************************************************************************/
#include <stdio.h>
#include "parse.h"
#include "cadef.h"
#include <dbDefs.h>
#include <seqU.h>
#include <dbDefs.h>
#include <seqCom.h>
/*+************************************************************************
* NAME: gen_ss_code
@@ -29,6 +30,7 @@
*
* NOTES: All inputs are external globals.
*-*************************************************************************/
/*#define DEBUG 1*/
#define EVENT_STMT 1
#define ACTION_STMT 2
@@ -50,7 +52,7 @@ gen_ss_code()
printf("\f/* Code for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
/* Generate delay processing function */
/* Generate function to set up for delay processing */
gen_delay_func(sp, ssp);
/* Generate event processing function */
@@ -64,9 +66,64 @@ gen_ss_code()
/* Generate exit handler code */
gen_exit_handler();
}
/* Generate a function for each state that sets up delay processing:
* This function gets called prior to the event function to guarantee
* that the initial delay value specified in delay() calls are used.
* Each delay() call is assigned a unique id. The maximum number of
* delays is recorded in the state set structure.
*/
gen_delay_func(sp, ssp)
Expr *ssp;
Expr *sp;
{
Expr *tp;
int eval_delay();
printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
printf("static D_%s_%s(ssId, pVar)\n", ssp->value, sp->value);
printf("SS_ID\tssId;\n");
printf("struct UserVar\t*pVar;\n{\n");
/* For each transition: */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
print_line_num(tp->line_num, tp->src_file);
traverseExprTree(tp, E_FUNC, "delay", eval_delay, sp);
}
printf("}\n");
}
/* Evaluate the expression within a delay() function and generate
* a call to seq_delayInit(). Adds ssId, delay id parameters and cast to float.
* Example: seq_delayInit(ssId, 1, (float)(<some expression>));
*/
eval_delay(ep, sp)
Expr *ep;
Expr *sp;
{
Expr *epf;
int delay_id;
extern char *stype[];
#ifdef DEBUG
fprintf("stderr, "eval_delay: type=%s\n", stype[ep->type]);
#endif DEBUG
/* Generate 1-st part of function w/ 1-st 2 parameters */
delay_id = (int)ep->right; /* delay id was previously assigned */
printf("\tseq_delayInit(ssId, %d, (", delay_id);
/* Evaluate & generate the 3-rd parameter (an expression) */
eval_expr(EVENT_STMT, ep->left, sp, 0);
/* Complete the function call */
printf("));\n");
}
/* Generate action processing functions:
/* Generate action processing functions:
Each state has one action routine. It's name is derived from the
state set name and the state name.
*/
@@ -78,17 +135,20 @@ Expr *ssp; /* Parent state set */
Expr *ap;
int trans_num;
extern char *prog_name;
extern line_num;
/* Action function declaration */
printf("\n/* Action function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
/* action function declaration with ss_ptr as parameter */
printf("static void A_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value);
printf("SPROG\t*sprog;\n");
printf("SSCB\t*ss_ptr;\n");
printf("struct UserVar\t*var_ptr;\n{\n");
printf("static A_%s_%s(ssId, pVar, transNum)\n", ssp->value, sp->value);
printf("SS_ID\tssId;\n");
printf("struct UserVar\t*pVar;\n");
printf("short\ttransNum;\n{\n");
/* "switch" statment based on the transition number */
printf("\tswitch(ss_ptr->trans_num)\n\t{\n");
printf("\tswitch(transNum)\n\t{\n");
trans_num = 0;
line_num = 0;
/* For each transition ("when" statement) ... */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
@@ -97,7 +157,11 @@ Expr *ssp; /* Parent state set */
/* For each action statement insert action code */
for (ap = tp->right; ap != NULL; ap = ap->next)
{
print_line_num(ap->line_num, ap->src_file);
if (line_num != ap->line_num)
{
print_line_num(ap->line_num, ap->src_file);
line_num = ap->line_num;
}
/* Evaluate statements */
eval_expr(ACTION_STMT, ap, sp, 2);
}
@@ -122,18 +186,21 @@ Expr *ssp;
printf("\n/* Event function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
printf("static int E_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value);
printf("SPROG\t*sprog;\n");
printf("SSCB\t*ss_ptr;\n");
printf("struct UserVar\t*var_ptr;\n{\n");
printf("static E_%s_%s(ssId, pVar, pTransNum, pNextState)\n",
ssp->value, sp->value);
printf("SS_ID\tssId;\n");
printf("struct UserVar\t*pVar;\n");
printf("short\t*pTransNum, *pNextState;\n{\n");
trans_num = 0;
/* For each transition generate an "if" statement ... */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
print_line_num(tp->line_num, tp->src_file);
printf("\tif (");
eval_expr(EVENT_STMT, tp->left, sp, 0);
/* an event triggered, set next state */
if (tp->left == 0)
printf("TRUE");
else
eval_expr(EVENT_STMT, tp->left, sp, 0);
printf(")\n\t{\n");
/* index is the transition number (0, 1, ...) */
index = state_block_index_from_name(ssp, tp->value);
@@ -146,8 +213,8 @@ Expr *ssp;
printf("\t\t/* state %s does not exist */\n",
tp->value);
}
printf("\t\tss_ptr->next_state = %d;\n", index);
printf("\t\tss_ptr->trans_num = %d;\n", trans_num);
printf("\t\t*pNextState = %d;\n", index);
printf("\t\t*pTransNum = %d;\n", trans_num);
printf("\t\treturn TRUE;\n\t}\n");
trans_num++;
}
@@ -173,32 +240,6 @@ char *state_name;
}
return -1; /* State name non-existant */
}
/* Generate delay processing function for a state */
gen_delay_func(sp, ssp)
Expr *sp;
Expr *ssp;
{
Expr *tp;
int eval_delay();
printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
printf("static void D_%s_%s(sprog, ss_ptr, var_ptr)\n", ssp->value, sp->value);
printf("SPROG\t*sprog;\n");
printf("SSCB\t*ss_ptr;\n");
printf("struct UserVar\t*var_ptr;\n{\n");
/* For each transition ... */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
print_line_num(tp->line_num, tp->src_file);
traverseExprTree(tp, E_FUNC, "delay", eval_delay, sp);
}
printf("}\n");
return;
}
/* Evaluate an expression.
*/
eval_expr(stmt_type, ep, sp, level)
@@ -210,6 +251,8 @@ int level; /* indentation level */
Expr *epf;
int nparams;
extern int reent_opt;
extern int line_num;
if (ep == 0)
return;
@@ -218,17 +261,20 @@ int level; /* indentation level */
case E_CMPND:
indent(level);
printf("{\n");
line_num += 1;
for (epf = ep->left; epf != 0; epf = epf->next)
{
eval_expr(stmt_type, epf, sp, level+1);
}
indent(level);
printf("}\n");
line_num += 1;
break;
case E_STMT:
indent(level);
eval_expr(stmt_type, ep->left, sp, 0);
printf(";\n");
line_num += 1;
break;
case E_IF:
case E_WHILE:
@@ -239,6 +285,7 @@ int level; /* indentation level */
printf("while (");
eval_expr(stmt_type, ep->left, sp, 0);
printf(")\n");
line_num += 1;
epf = ep->right;
if (epf->type == E_CMPND)
eval_expr(stmt_type, ep->right, sp, level);
@@ -254,6 +301,7 @@ int level; /* indentation level */
printf("; ");
eval_expr(stmt_type, ep->right->left, sp, 0);
printf(")\n");
line_num += 1;
epf = ep->right->right;
if (epf->type == E_CMPND)
eval_expr(stmt_type, epf, sp, level);
@@ -263,6 +311,7 @@ int level; /* indentation level */
case E_ELSE:
indent(level);
printf("else\n");
line_num += 1;
epf = ep->left;
/* Is it "else if" ? */
if (epf->type == E_IF || epf->type == E_CMPND)
@@ -271,12 +320,15 @@ int level; /* indentation level */
eval_expr(stmt_type, ep->left, sp, level+1);
break;
case E_VAR:
#ifdef DEBUG
fprintf(stderr, "E_VAR: %s\n", ep->value);
#endif DEBUG
if(reent_opt)
{ /* Make variables point to allocated structure */
Var *vp;
vp = (Var *)ep->left;
if (vp->type != V_NONE && vp->type != V_EVFLAG)
printf("(var_ptr->%s)", ep->value);
printf("(pVar->%s)", ep->value);
else
printf("%s", ep->value);
}
@@ -292,13 +344,16 @@ int level; /* indentation level */
case E_BREAK:
indent(level);
printf("break;\n");
line_num += 1;
break;
case E_FUNC:
#ifdef DEBUG
fprintf(stderr, "E_FUNC: %s\n", ep->value);
#endif DEBUG
if (special_func(stmt_type, ep, sp))
break;
printf("%s(", ep->value);
for (epf = ep->left, nparams = 0; epf != 0;
epf = epf->next, nparams++)
for (epf = ep->left, nparams = 0; epf != 0; epf = epf->next, nparams++)
{
if (nparams > 0)
printf(" ,");
@@ -337,6 +392,7 @@ int level; /* indentation level */
break;
case E_TEXT:
printf("%s\n", ep->left);
line_num += 1;
break;
default:
if (stmt_type == EVENT_STMT)
@@ -355,16 +411,22 @@ int level;
}
/* func_name_to_code - convert function name to a code */
enum fcode { F_DELAY, F_EFSET, F_EFTEST, F_EFCLEAR, F_EFTESTANDCLEAR,
F_PVGET, F_PVPUT,
F_PVGET, F_PVPUT, F_PVTIMESTAMP, F_PVASSIGN,
F_PVMONITOR, F_PVSTOPMONITOR, F_PVCOUNT, F_PVINDEX,
F_PVSTATUS, F_PVSEVERITY, F_PVFLUSH, F_PVERROR, F_PVGETCOMPLETE,
F_PVCONNECTED, F_PVCHANNELCOUNT, F_PVCONNECTCOUNT, F_NONE };
F_PVASSIGNED, F_PVCONNECTED,
F_PVCHANNELCOUNT, F_PVCONNECTCOUNT, F_PVASSIGNCOUNT,
F_PVDISCONNECT, F_SEQLOG, F_MACVALUEGET, F_OPTGET,
F_NONE };
char *fcode_str[] = { "delay", "efSet", "efTest", "efClear", "efTestAndClear",
"pvGet", "pvPut",
"pvGet", "pvPut", "pvTimeStamp", "pvAssign",
"pvMonitor", "pvStopMonitor", "pvCount", "pvIndex",
"pvStatus", "pvSeverity", "pvFlush", "pvError", "pvGetComplete",
"pvConnected", "pvChannelCount", "pvConnectCount", NULL };
"pvAssigned", "pvConnected",
"pvChannelCount", "pvConnectCount", "pvAssignCount",
"pvDisconnect", "seqLog", "macValueGet", "optGet",
NULL };
enum fcode func_name_to_code(fname)
char *fname;
@@ -382,9 +444,11 @@ char *fname;
/* Process special function (returns TRUE if this is a special function)
Checks for one of the following special functions:
- event flag functions
- process variable functions
- event flag functions, e.g. pvSet()
- process variable functions, e.g. pvPut()
- delay()
- macVauleget()
- seqLog()
*/
special_func(stmt_type, ep, sp)
int stmt_type; /* ACTION_STMT or EVENT_STMT */
@@ -392,113 +456,206 @@ Expr *ep; /* ptr to function in the expression */
Expr *sp; /* current State struct */
{
char *fname; /* function name */
Expr *ep1; /* 1-st parameter */
Expr *ep1, *ep2, *ep3; /* parameters */
Chan *cp;
Var *vp;
enum fcode func_code;
int ndelay;
int delay_id;
fname = ep->value;
func_code = func_name_to_code(fname);
if (func_code == F_NONE)
return FALSE; /* not a special function */
ep1 = ep->left; /* ptr to 1-st parameters */
if ( (ep1 != 0) && (ep1->type == E_VAR) )
{
vp = (Var *)findVar(ep1->value);
cp = vp->chan;
}
else
{
vp = 0;
cp = 0;
}
#ifdef DEBUG
fprintf(stderr, "special_func: func_code=%d\n", func_code);
#endif DEBUG
switch (func_code)
{
case F_DELAY:
delay_id = (int)ep->right;
printf("seq_delay(ssId, %d)", delay_id);
return TRUE;
case F_EFSET:
case F_EFTEST:
case F_EFCLEAR:
case F_EFTESTANDCLEAR:
if (vp->type != V_EVFLAG)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Parameter to \"%s\" must be an event flag\n", fname);
}
else if (func_code == F_EFSET && stmt_type == EVENT_STMT)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"efSet() cannot be used as an event.\n");
}
else
{
printf("%s(%s)", fname, vp->name);
}
/* Event flag funtions */
gen_ef_func(stmt_type, ep, sp, fname);
return TRUE;
case F_PVPUT:
case F_PVGET:
case F_PVTIMESTAMP:
case F_PVGETCOMPLETE:
case F_PVSTATUS:
case F_PVSEVERITY:
case F_PVCONNECTED:
case F_PVASSIGNED:
case F_PVMONITOR:
case F_PVSTOPMONITOR:
case F_PVCOUNT:
case F_PVINDEX:
/* DB functions requiring a channel structure */
if (cp == 0)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Parameter to \"%s\" must be DB variable.\n", fname);
}
else
{
printf("%s(%d)", fname, cp->index);
}
case F_PVDISCONNECT:
case F_PVASSIGN:
/* DB functions requiring a channel id */
gen_pv_func(stmt_type, ep, sp, fname, func_code);
return TRUE;
case F_PVFLUSH:
case F_PVERROR:
case F_PVCHANNELCOUNT:
case F_PVCONNECTCOUNT:
/* DB functions not requiring a channel structure */
printf("%s()", fname);
case F_PVASSIGNCOUNT:
/* DB functions NOT requiring a channel structure */
printf("seq_%s(ssId)", fname);
return TRUE;
case F_DELAY:
/* Test for delay: "test_delay(delay_id)" */
printf("test_delay(%d)", (int)ep->right);
case F_SEQLOG:
case F_MACVALUEGET:
case F_OPTGET:
/* Any funtion that requires adding ssID as 1st parameter.
* Note: name is changed by prepending "seq_". */
printf("seq_%s(ssId", fname);
/* now fill in user-supplied paramters */
for (ep1 = ep->left; ep1 != 0; ep1 = ep1->next)
{
printf(", ");
eval_expr(stmt_type, ep1, sp, 0);
}
printf(") ");
return TRUE;
default:
return FALSE; /* not a special function */
/* Not a special function */
return FALSE;
}
}
/* Evaluate delay expression. */
eval_delay(ep, sp)
Expr *ep; /* ptr to expression */
Expr *sp; /* ptr to current State struct */
/* Generate code for all event flag functions */
gen_ef_func(stmt_type, ep, sp, fname, func_code)
int stmt_type; /* ACTION_STMT or EVENT_STMT */
Expr *ep; /* ptr to function in the expression */
Expr *sp; /* current State struct */
char *fname; /* function name */
enum fcode func_code;
{
Expr *epf;
int delay_id;
extern char *stype[];
Expr *ep1, *ep2, *ep3;
Var *vp;
Chan *cp;
ep1 = ep->left; /* ptr to 1-st parameters */
if ( (ep1 != 0) && (ep1->type == E_VAR) )
vp = (Var *)findVar(ep1->value);
else
vp = 0;
if (vp == 0 || vp->type != V_EVFLAG)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Parameter to \"%s\" must be an event flag\n", fname);
}
else if (func_code == F_EFSET && stmt_type == EVENT_STMT)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"efSet() cannot be used as an event.\n");
}
else
{
printf("seq_%s(ssId, %s)", fname, vp->name);
}
return;
}
/* Generate code for pv functions requiring a database variable.
* The channel id (index into channel array) is substituted for the variable
*/
gen_pv_func(stmt_type, ep, sp, fname)
int stmt_type; /* ACTION_STMT or EVENT_STMT */
Expr *ep; /* ptr to function in the expression */
Expr *sp; /* current State struct */
char *fname; /* function name */
{
Expr *ep1, *ep2, *ep3;
Var *vp;
Chan *cp;
int index;
ep1 = ep->left; /* ptr to 1-st parameter in the function */
if (ep1 == 0)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Function \"%s\" requires a parameter.\n", fname);
return;
}
vp = 0;
if (ep1->type == E_VAR)
{
vp = (Var *)findVar(ep1->value);
}
else if (ep1->type == E_SUBSCR)
{ /* Form should be: <db variable>[<expression>] */
ep2 = ep1->left; /* variable */
ep3 = ep1->right; /* subscript */
if ( ep2->type == E_VAR )
{
vp = (Var *)findVar(ep2->value);
}
}
if (vp == 0)
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Parameter to \"%s\" is not a defined variable.\n", fname);
cp=0;
}
else
{
#ifdef DEBUG
fprintf(stderr, "eval_delay: type=%s\n", stype[ep->type]);
#endif
fprintf(stderr, "gen_pv_func: var=%s\n", ep1->value);
#endif DEBUG
cp = vp->chan;
index = cp->index;
}
delay_id = (int)ep->right;
printf("\tstart_delay(%d, ", delay_id);
if ( (vp != 0) && (cp == 0) )
{
fprintf(stderr, "Line %d: ", ep->line_num);
fprintf(stderr,
"Parameter to \"%s\" must be DB variable.\n", fname);
index=-1;
}
/* Output each parameter */
eval_expr(EVENT_STMT, ep->left, sp, 0);
printf("seq_%s(ssId, %d", fname, index);
printf(");\n");
if (ep1->type == E_SUBSCR) /* subscripted variable? */
{ /* e.g. pvPut(xyz[i+2]); => seq_pvPut(ssId, 3 + (i+2)); */
printf(" + (");
/* evalute the subscript expression */
eval_expr(stmt_type, ep3, sp, 0);
printf(")");
}
/* Add any additional parameter(s) */
ep1 = ep1->next;
while (ep1 != 0)
{
printf(", ");
eval_expr(stmt_type, ep1, sp, 0);
ep1 = ep1->next;
}
/* Close the parameter list */
printf(") \n");
return;
}
/* Generate exit handler code */
gen_exit_handler()
@@ -507,9 +664,9 @@ gen_exit_handler()
Expr *ep;
printf("/* Exit handler */\n");
printf("static void exit_handler(sprog, var_ptr)\n");
printf("SPROG\t*sprog;\n");
printf("struct UserVar\t*var_ptr;\n{\n");
printf("static exit_handler(ssId, pVar)\n");
printf("int\tssId;\n");
printf("struct UserVar\t*pVar;\n{\n");
for (ep = exit_code_list; ep != 0; ep = ep->next)
{
eval_expr(EXIT_STMT, ep, 0, 1);

View File

@@ -3,18 +3,23 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
gen_tables.c,v 1.2 1995/06/27 15:25:45 wright Exp
DESCRIPTION: Generate tables for run-time sequencer.
See also: phase2.c & gen_ss_code.c
ENVIRONMENT: UNIX
HISTORY:
28apr92,ajk Implemented new event flag mode.
01mar94,ajk Implemented new interface to sequencer (see seqCom.h).
01mar94,ajk Implemented assignment of array elements to db channels.
17may94,ajk removed old event flag (-e) option.
***************************************************************************/
/*#define DEBUG 1*/
#include <stdio.h>
#include "parse.h"
#include <dbDefs.h>
#include <seqU.h>
#include <seqCom.h>
/*+************************************************************************
* NAME: gen_tables
@@ -30,8 +35,6 @@
* NOTES: All inputs are external globals.
*-*************************************************************************/
int nstates; /* total # states in all state sets */
gen_tables()
{
extern Expr *ss_list; /* state sets (from parse) */
@@ -45,11 +48,14 @@ gen_tables()
/* Generate State Blocks */
gen_state_blocks();
/* Generate State Set control blocks as an array */
gen_sscb_array();
/* Generate State Set Blocks */
gen_ss_array();
/* generate program parameter string */
gen_prog_params();
/* Generate state program table */
gen_state_prog_table();
gen_prog_table();
return;
}
@@ -58,254 +64,250 @@ gen_db_blocks()
{
extern Chan *chan_list;
Chan *cp;
int nchan;
int nchan, elem_num;
printf("\n/* Database Blocks */\n");
printf("static CHAN db_channels[NUM_CHANNELS] = {\n");
printf("static struct seqChan seqChan[NUM_CHANNELS] = {\n");
nchan = 0;
for (cp = chan_list; cp != NULL; cp = cp->next)
{
/* Only process db variables */
if (cp->db_name != NULL)
{
if (nchan > 0)
printf(",\n");
fill_db_block(cp, nchan);
#ifdef DEBUG
fprintf(stderr, "gen_db_blocks: index=%d, num_elem=%d\n",
cp->index, cp->num_elem);
#endif DEBUG
if (cp->num_elem == 0)
{ /* Variable assigned to single pv */
fill_db_block(cp, 0);
nchan++;
}
else
{ /* Variable assigned to multiple pv's */
for (elem_num = 0; elem_num < cp->num_elem; elem_num++)
{
fill_db_block(cp, elem_num);
nchan++;
}
}
}
printf("\n};\n");
printf("};\n");
return;
}
/* Fill in a db block with data (all elements for "CHAN" struct) */
fill_db_block(cp, index)
/* Fill in a db block with data (all elements for "seqChan" struct) */
fill_db_block(cp, elem_num)
Chan *cp;
int index;
int elem_num;
{
Var *vp;
char *get_type_string, *put_type_string, *postfix;
char *type_string, *suffix, elem_str[20], *db_name;
extern char *prog_name;
extern int reent_opt;
int size, ev_flag, count;
extern int reent_opt;
extern int num_events;
int size, count, ef_num, mon_flag;
char *db_type_str();
vp = cp->var;
/* Convert variable type to a DB request type */
switch (vp->type)
/* Figure out text needed to handle subscripts */
if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP)
sprintf(elem_str, "[%d]", elem_num);
else if (vp->class == VC_ARRAY2)
sprintf(elem_str, "[%d][0]", elem_num);
else
sprintf(elem_str, "");
if (vp->type == V_STRING)
suffix = "[0]";
else
suffix = "";
/* Pick up other db info */
if (cp->num_elem == 0)
{
case V_SHORT:
get_type_string = "DBR_STS_INT";
put_type_string = "DBR_INT";
size = sizeof(short);
break;
case V_INT:
case V_LONG:
/* Assume "long" & "int" are same size */
get_type_string = "DBR_STS_LONG";
put_type_string = "DBR_LONG";
size = sizeof(int);
break;
case V_CHAR:
get_type_string = "DBR_STS_CHAR";
put_type_string = "DBR_CHAR";
size = sizeof(char);
break;
case V_FLOAT:
get_type_string = "DBR_STS_FLOAT";
put_type_string = "DBR_FLOAT";
size = sizeof(float);
break;
case V_DOUBLE:
get_type_string = "DBR_STS_DOUBLE";
put_type_string = "DBR_DOUBLE";
size = sizeof(double);
break;
case V_STRING:
get_type_string = "DBR_STS_STRING";
put_type_string = "DBR_STRING";
size = MAX_STRING_SIZE;
break;
db_name = cp->db_name;
mon_flag = cp->mon_flag;
ef_num = cp->ef_num;
}
else
{
db_name = cp->db_name_list[elem_num];
mon_flag = cp->mon_flag_list[elem_num];
ef_num = cp->ef_num_list[elem_num];
}
/* fill in the CHAN structure */
printf("\t%d, ", index); /* index for this channel */
if (db_name == NULL)
db_name = ""; /* not assigned */
printf("\"%s\", ", cp->db_name);/* unexpanded db channel name */
/* Now, fill in the dbCom structure */
printf("(char *)0, "); /* ch'l name after macro expansion */
printf(" \"%s\", ", db_name);/* unexpanded db channel name */
/* Ptr or offset to user variable */
printf("(char *)");
if (vp->type == V_STRING || cp->count > 0)
postfix = "[0]";
else
postfix = "";
printf("(void *)");
if (reent_opt)
printf("OFFSET(struct UserVar, %s%s), ", vp->name, postfix);
printf("OFFSET(struct UserVar, %s%s%s), ", vp->name, elem_str, suffix);
else
printf("&%s%s, ", vp->name, postfix); /* variable ptr */
printf("&%s%s%s, ", vp->name, elem_str, suffix); /* variable ptr */
printf("(chid)0, "); /* reserve place for chid */
/* variable name with optional elem num */
printf("\"%s%s\", ", vp->name, elem_str);
printf("0, 0, 0, 0, "); /* connected, get_complete, status, severity */
/* variable type */
printf("\n \"%s\", ", db_type_str(vp->type) );
printf("%d,\n", size); /* element size (bytes) */
/* count for db requests */
printf("%d, ", cp->count);
printf("\t%s, ", get_type_string);/* DB request conversion type (get/mon) */
/* event number */
printf("%d, ", cp->index + elem_num + num_events + 1);
printf("%s, ", put_type_string);/* DB request conversion type (put) */
/* event flag number (or 0) */
printf("%d, ", ef_num);
count = cp->count;
if (count == 0)
count = 1;
printf("%d, ", count); /* count for db requests */
/* monitor flag */
printf("%d", mon_flag);
printf("%d, ", cp->mon_flag); /* monitor flag */
printf("0, "); /* monitored */
printf("%g, ", cp->delta); /* monitor delta */
printf("%g, ", cp->timeout); /* monitor timeout */
printf("0, "); /* event id supplied by CA */
printf("0, "); /* semaphore id for async. pvGet() */
printf("&%s", prog_name); /* ptr to state program structure */
printf(",\n\n");
return;
}
/* Convert variable type to db type as a string */
char *db_type_str(type)
int type;
{
switch (type)
{
case V_CHAR: return "char";
case V_SHORT: return "short";
case V_INT: return "int";
case V_LONG: return "long";
case V_FLOAT: return "float";
case V_DOUBLE: return "double";
case V_STRING: return "string";
default: return "";
}
}
/* Generate structure and data for state blocks (STATE) */
/* Generate structure and data for state blocks */
gen_state_blocks()
{
extern Expr *ss_list;
Expr *ssp;
Expr *sp;
int ns;
extern int nstates;
int nstates, n;
extern int num_events, num_channels;
int numEventWords;
bitMask *pEventMask;
printf("\n/* State Blocks:\n");
printf(" action_func, event_func, delay_func, event_flag_mask");
printf(", *delay, *name */\n");
nstates = 0;
/* Allocate an array for event mask bits */
numEventWords = (num_events + num_channels + NBITS - 1)/NBITS;
pEventMask = (bitMask *)calloc(numEventWords, sizeof (bitMask));
/* for all state sets ... */
for (ssp = ss_list; ssp != NULL; ssp = ssp->next)
{
printf("\nstatic STATE state_%s[] = {\n", ssp->value);
ns = 0;
/* Build event mask arrays for each state */
printf("\n/* Event masks for state set %s */\n", ssp->value);
for (sp = ssp->left; sp != NULL; sp = sp->next)
{
eval_state_event_mask(sp, pEventMask, numEventWords);
printf("\t/* Event mask for state %s: */\n", sp->value);
printf("static bitMask\tEM_%s_%s[] = {\n", ssp->value, sp->value);
for (n = 0; n < numEventWords; n++)
printf("\t0x%08x,\n", pEventMask[n]);
printf("};\n");
}
/* Build state block for each state in this state set */
printf("\n/* State Blocks */\n");
printf("\nstatic struct seqState state_%s[] = {\n", ssp->value);
nstates = 0;
for (sp = ssp->left; sp != NULL; sp = sp->next)
{
if (ns > 0)
printf(",\n\n");
ns++;
nstates++;
fill_state_block(sp, ssp->value);
}
printf("\n};\n");
}
free(pEventMask);
return;
}
/* Fill in data for a the state block */
/* Fill in data for a state block (see seqState in seqCom.h) */
fill_state_block(sp, ss_name)
Expr *sp;
char *ss_name;
{
bitMask events[NWRDS];
int n;
printf("\t/* State \"%s\"*/\n", sp->value);
printf("\tA_%s_%s,\t/* action_function */\n", ss_name, sp->value);
printf("\t/* state name */ \"%s\",\n", sp->value);
printf("\tE_%s_%s,\t/* event_function */\n", ss_name, sp->value);
printf("\t/* action function */ A_%s_%s,\n", ss_name, sp->value);
printf("\tD_%s_%s,\t/* delay_function */\n", ss_name, sp->value);
printf("\t/* event function */ E_%s_%s,\n", ss_name, sp->value);
eval_state_event_mask(sp, events);
printf("\t/* Event mask for this state: */\n");
for (n = 0; n < NWRDS; n++)
printf("\t0x%08x,\n", events[n]);
printf("\t/* delay function */ D_%s_%s,\n", ss_name, sp->value);
printf("\t\"%s\"\t/* *name */", sp->value);
printf("\t/* event mask array */ EM_%s_%s,\n\n", ss_name, sp->value);
return;
}
/* Generate the structure with data for a state program table (SPROG) */
gen_state_prog_table()
/* Generate the program parameter list */
gen_prog_params()
{
extern char *prog_name, *prog_param;
extern int async_opt, debug_opt, reent_opt, conn_opt, newef_opt;
extern int nstates;
extern Expr exit_code_list;
int i;
extern char *prog_param;
printf("\n/* Program parameter list */\n");
printf("static char prog_param[] = \"%s\";\n", prog_param);
}
/* Generate the structure with data for a state program table (SPROG) */
gen_prog_table()
{
extern int reent_opt;
extern char *prog_name;
extern Expr exit_code_list;
int i;
printf("\n/* State Program table (global) */\n");
printf("SPROG %s = {\n", prog_name);
printf("struct seqProgram %s = {\n", prog_name);
printf("\t%d,\t/* magic number */\n", MAGIC);
printf("\t/* magic number */ %d,\n", MAGIC); /* magic number */
printf("\t0,\t/* task id */\n");
printf("\t/* *name */ \"%s\",\n", prog_name);/* program name */
printf("\t0,\t/* dyn_ptr */\n");
printf("\t/* *pChannels */ seqChan,\n"); /* table of db channels */
printf("\t0,\t/* task_is_deleted */\n");
printf("\t/* numChans */ NUM_CHANNELS,\n"); /* number of db channels */
printf("\t1,\t/* relative task priority */\n");
printf("\t/* *pSS */ seqSS,\n"); /* array of SS blocks */
printf("\t0,\t/* caSemId */\n");
printf("\tdb_channels,\t/* *channels */\n");
printf("\tNUM_CHANNELS,\t/* nchan */\n");
printf("\t0,\t/* conn_count */\n");
printf("\tsscb,\t/* *sscb */\n");
printf("\tNUM_SS,\t/* nss */\n");
printf("\tNULL,\t/* ptr to states */\n");
printf("\t%d,\t/* number of states */\n", nstates);
printf("\tNULL,\t/* ptr to user area (not used) */\n");
printf("\t/* numSS */ NUM_SS,\n"); /* number of state sets */
if (reent_opt)
printf("\tsizeof(struct UserVar),\t/* user area size */\n");
printf("\t/* user variable size */ sizeof(struct UserVar),\n");
else
printf("\t0,\t/* user area size (not used) */\n");
printf("\t/* user variable size */ 0,\n");
printf("\tNULL,\t/* mac_ptr */\n");
printf("\t/* *pParams */ prog_param,\n"); /* program parameters */
printf("\tNULL,\t/* scr_ptr */\n");
printf("\t/* numEvents */ NUM_EVENTS,\n"); /* number event flags */
printf("\t0,\t/* scr_nleft */\n");
printf("\t/* encoded options */ ");
encode_options();
printf("\t\"%s\",\t/* *name */\n", prog_name);
printf("\tprog_param,\t/* *params */\n");
printf("\t");
for (i = 0; i < NWRDS; i++)
printf("0, ");
printf("\t/* Event flags (bit encoded) */\n");
printf("\t0x%x,\t/* encoded async, debug, conn, newef & reent options */\n",
encode_options() );
printf("\texit_handler,\t/* exit handler */\n");
printf("\t0, 0\t/* logSemId & logFd */\n");
printf("\t/* exit handler */ exit_handler,\n");
printf("};\n");
@@ -314,71 +316,55 @@ gen_state_prog_table()
encode_options()
{
int options;
extern int async_opt, debug_opt, reent_opt, conn_opt, newef_opt;
extern int async_opt, debug_opt, reent_opt,
newef_opt, conn_opt, vx_opt;
options = 0;
printf("(0");
if (async_opt)
options |= OPT_ASYNC;
printf(" | OPT_ASYNC");
if (conn_opt)
options |= OPT_CONN;
printf(" | OPT_CONN");
if (debug_opt)
options |= OPT_DEBUG;
if (reent_opt)
options |= OPT_REENT;
printf(" | OPT_DEBUG");
if (newef_opt)
options |= OPT_NEWEF;
return options;
printf(" | OPT_NEWEF");
if (reent_opt)
printf(" | OPT_REENT");
if (vx_opt)
printf(" | OPT_VXWORKS");
printf("),\n");
return;
}
/* Generate an array of state set control blocks (SSCB),
one entry for each state set */
gen_sscb_array()
/* Generate an array of state set blocks, one entry for each state set */
gen_ss_array()
{
extern Expr *ss_list;
Expr *ssp;
int nss, nstates, n;
bitMask events[NWRDS];
printf("\n/* State Set Control Blocks */\n");
printf("static SSCB sscb[NUM_SS] = {\n");
printf("\n/* State Set Blocks */\n");
printf("static struct seqSS seqSS[NUM_SS] = {\n");
nss = 0;
for (ssp = ss_list; ssp != NULL; ssp = ssp->next)
{
if (nss > 0)
printf(",\n\n");
printf("\n\n");
nss++;
printf("\t/* State set \"%s\"*/\n", ssp->value);
printf("\t0, 1,\t/* task_id, task_prioity */\n");
printf("\t/* ss name */ \"%s\",\n", ssp->value);
printf("\t0, 0,\t/* caSemId, getSemId */\n");
printf("\t/* ptr to state block */ state_%s%,\n", ssp->value);
nstates = exprCount(ssp->left);
printf("\t%d, state_%s,\t/* num_states, *states */\n", nstates,
ssp->value);
printf("\t/* number of states */ %d,\n", nstates, ssp->value);
printf("\t0, 0, 0,");
printf("\t/* current_state, next_state, prev_state */\n");
printf("\t/* error state */ %d,\n", find_error_state(ssp));
printf("\t%d,\t/* error_state */\n", find_error_state(ssp));
printf("\t0, FALSE,\t/* trans_number, action_complete */\n");
printf("\t0,\t/* pMask - ptr to current event mask */\n");
printf("\t0,\t/* number of delays in use */\n");
printf("\t/* array of delay values: */\n\t");
for (n = 0; n < MAX_NDELAY; n++)
printf("0,");
printf("\n");
printf("\t0,\t/* time (ticks) when state was entered */\n");
printf("\t\"%s\"\t\t/* ss name */", ssp->value);
}
printf("\n};\n");
printf("};\n");
return;
}
@@ -397,42 +383,146 @@ Expr *ssp;
}
/* Evaluate composite event mask for a single state */
eval_state_event_mask(sp, events)
eval_state_event_mask(sp, pEventWords, numEventWords)
Expr *sp;
bitMask events[NWRDS];
bitMask *pEventWords;
int numEventWords;
{
int n;
int eval_tr_event_mask();
int eval_event_mask(), eval_event_mask_subscr();
Expr *tp;
/* Clear all bits in mask */
for (n = 0; n < NWRDS; n++)
events[n] = 0;
/* Set appropriate bits based on transition expressions.
* Here we look at the when() statement for references to event flags
* and database variables. Database variables might have a subscript,
* which could be a constant (set a single event bit) or an expression
* (set a group of bits for the possible range of the evaluated expression)
*/
for (n = 0; n < numEventWords; n++)
pEventWords[n] = 0;
/* Set appropriate bits based on transition expressions */
for (tp = sp->left; tp != 0; tp = tp->next)
traverseExprTree(tp->left, E_VAR, 0,
eval_tr_event_mask, events);
{
/* look for simple variables, e.g. "when(x > 0)" */
traverseExprTree(tp->left, E_VAR, 0, eval_event_mask, pEventWords);
/* look for subscripted variables, e.g. "when(x[i] > 0)" */
traverseExprTree(tp->left, E_SUBSCR, 0, eval_event_mask_subscr, pEventWords);
}
#ifdef DEBUG
fprintf(stderr, "Event mask for state %s is", sp->value);
for (n = 0; n < numEventWords; n++)
fprintf(stderr, " 0x%x", pEventWords[n]);
fprintf(stderr, "\n");
#endif DEBUG
}
/* Evaluate the event mask for a given transition. */
eval_tr_event_mask(ep, events)
/* Evaluate the event mask for a given transition (when() statement).
* Called from traverseExprTree() when ep->type==E_VAR.
*/
eval_event_mask(ep, pEventWords)
Expr *ep;
bitMask events[NWRDS];
bitMask *pEventWords;
{
Chan *cp;
Var *vp;
extern int num_events;
vp = (Var *)ep->left;
if (vp == 0)
return; /* this shouldn't happen */
/* event flag? */
if (vp->type == V_EVFLAG)
{
#ifdef DEBUG
fprintf(stderr, "eval_tr_event_mask: %s, ef_num=%d\n",
vp->name, vp->ef_num);
fprintf(stderr, " eval_event_mask: %s, ef_num=%d\n",
vp->name, vp->ef_num);
#endif
if (vp->ef_num != 0)
bitSet(events, vp->ef_num);
bitSet(pEventWords, vp->ef_num);
return;
}
/* database channel? */
cp = vp->chan;
if (cp != NULL && cp->num_elem == 0)
{
#ifdef DEBUG
fprintf(stderr, " eval_event_mask: %s, db event bit=%d\n",
vp->name, cp->index + 1);
#endif
bitSet(pEventWords, cp->index + num_events + 1);
}
return;
}
/* Evaluate the event mask for a given transition (when() statement)
* for subscripted database variables.
* Called from traverseExprTree() when ep->type==E_SUBSCR.
*/
eval_event_mask_subscr(ep, pEventWords)
Expr *ep;
bitMask *pEventWords;
{
extern int num_events;
Chan *cp;
Var *vp;
Expr *ep1, *ep2;
int subscr, n;
ep1 = ep->left;
if (ep1 == 0 || ep1->type != E_VAR)
return;
vp = (Var *)ep1->left;
if (vp == 0)
return; /* this shouldn't happen */
cp = vp->chan;
if (cp == NULL)
return;
/* Only do this if the array is assigned to multiple pv's */
if (cp->num_elem == 0)
{
#ifdef DEBUG
fprintf(stderr, " eval_event_mask_subscr: %s, db event bit=%d\n",
vp->name, cp->index);
#endif
bitSet(pEventWords, cp->index + num_events + 1);
return;
}
/* Is this subscript a constant? */
ep2 = ep->right;
if (ep2 == 0)
return;
if (ep2->type == E_CONST)
{
subscr = atoi(ep2->value);
if (subscr < 0 || subscr >= cp->num_elem)
return;
#ifdef DEBUG
fprintf(stderr, " eval_event_mask_subscr: %s, db event bit=%d\n",
vp->name, cp->index + subscr + 1);
#endif
bitSet(pEventWords, cp->index + subscr + num_events + 1);
return;
}
/* subscript is an expression -- set all event bits for this variable */
#ifdef DEBUG
fprintf(stderr, " eval_event_mask_subscr: %s, db event bits=%d..%d\n",
vp->name, cp->index + 1, cp->index + vp->length1);
#endif
for (n = 0; n < vp->length1; n++)
{
bitSet(pEventWords, cp->index + n + num_events + 1);
}
return;
}
/* Count the number of linked expressions */

View File

@@ -4,7 +4,7 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
< parse.c,v 1.3 1995/10/19 16:30:16 wright Exp
DESCRIPTION: Parsing support routines for state notation compiler.
The 'yacc' parser calls these routines to build the tables
and linked lists, which are then passed on to the phase 2 routines.
@@ -15,6 +15,10 @@
20nov91,ajk Removed snc_init() - no longer did anything useful.
20nov91,ajk Added option_stmt() routine.
28apr92,ajk Implemented new event flag mode.
29opc93,ajk Implemented assignment of pv's to array elements.
29oct93,ajk Implemented variable class (VC_SIMPLE, VC_ARRAY, & VC_POINTER).
29oct93,ajk Added 'v' (vxWorks include) option.
17may94,ajk Removed old event flag (-e) option.
***************************************************************************/
/*====================== Includes, globals, & defines ====================*/
@@ -22,12 +26,11 @@
#include <stdio.h>
#include "parse.h" /* defines linked list structures */
#include <math.h>
#include "db_access.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif /* TRUE */
#endif TRUE
int debug_print_opt = 0; /* Debug level (set by source file) */
@@ -65,8 +68,6 @@ Expr *global_c_list; /* global C code following state program */
program_name(pname, pparam)
char *pname, *pparam;
{
extern char *prog_name, *prog_param;
prog_name = pname;
prog_param = pparam;
#ifdef DEBUG
@@ -76,29 +77,40 @@ char *pname, *pparam;
}
/* Parsing a declaration statement */
decl_stmt(type, name, s_length, value)
decl_stmt(type, class, name, s_length1, s_length2, value)
int type; /* variable type (e.g. V_FLOAT) */
int class; /* variable class (e.g. VC_ARRAY) */
char *name; /* ptr to variable name */
char *s_length; /* array lth (NULL=single element) */
char *s_length1; /* array lth (1st dim, arrays only) */
char *s_length2; /* array lth (2nd dim, [n]x[m] arrays only) */
char *value; /* initial value or NULL */
{
Var *vp;
int length;
int length1, length2;
extern int line_num;
if (s_length == 0)
length = 0;
else if (type == V_STRING)
length = 0;
else
{
length = atoi(s_length);
if (length < 0)
length = 0;
}
#ifdef DEBUG
fprintf(stderr, "variable decl: type=%d, name=%s, length=%d\n",
type, name, length);
fprintf(stderr,
"variable decl: type=%d, class=%d, name=%s, ", type, class, name);
#endif
length1 = length2 = 1;
if (s_length1 != NULL)
{
length1 = atoi(s_length1);
if (length1 <= 0)
length1 = 1;
}
if (s_length2 != NULL)
{
length2 = atoi(s_length2);
if (length2 <= 0)
length2 = 1;
}
#ifdef DEBUG
fprintf(stderr, "length1=%d, length2=%d\n", length1, length2);
#endif
/* See if variable already declared */
vp = (Var *)findVar(name);
@@ -112,9 +124,12 @@ char *value; /* initial value or NULL */
vp = allocVar();
addVar(vp); /* add to var list */
vp->name = name;
vp->class = class;
vp->type = type;
vp->length = length;
vp->length1 = length1;
vp->length2 = length2;
vp->value = value; /* initial value or NULL */
vp->chan = NULL;
return;
}
@@ -123,8 +138,8 @@ option_stmt(option, value)
char *option; /* "a", "r", ... */
int value; /* TRUE means +, FALSE means - */
{
extern int async_opt, conn_opt, debug_opt,
line_opt, reent_opt, warn_opt, newef_opt;
extern int async_opt, conn_opt, debug_opt, line_opt,
reent_opt, warn_opt, vx_opt, newef_opt;
switch(*option)
{
@@ -137,6 +152,10 @@ int value; /* TRUE means +, FALSE means - */
case 'd':
debug_opt = value;
break;
case 'e':
newef_opt = value;
break;
case 'l':
line_opt = value;
break;
@@ -145,28 +164,30 @@ int value; /* TRUE means +, FALSE means - */
break;
case 'w':
warn_opt = value;
case 'e':
newef_opt = value;
break;
case 'v':
vx_opt = value;
break;
}
return;
}
/* "Assign" statement: assign a variable to a DB channel.
elem_num is ignored in this version) */
assign_stmt(name, db_name)
/* "Assign" statement: Assign a variable to a DB channel.
* Format: assign <variable> to <string;
* Note: Variable may be subscripted.
*/
assign_single(name, db_name)
char *name; /* ptr to variable name */
char *db_name; /* ptr to db name */
{
Chan *cp;
Var *vp;
int subNum;
extern int line_num;
#ifdef DEBUG
fprintf(stderr, "assign_stmt: name=%s, db_name=%s\n", name, db_name);
#endif /* DEBUG */
fprintf(stderr, "assign %s to \"%s\";\n", name, db_name);
#endif DEBUG
/* Find the variable */
vp = (Var *)findVar(name);
if (vp == 0)
@@ -176,29 +197,240 @@ char *db_name; /* ptr to db name */
return;
}
/* Build structure for this channel */
cp = allocChan();
addChan(cp); /* add to Chan list */
cp->var = vp; /* make connection to variable */
vp->chan = cp; /* reverse ptr */
cp->db_name = db_name; /* DB name */
cp->count = vp->length; /* default count is variable length */
cp = vp->chan;
if (cp != NULL)
{
fprintf(stderr, "assign: %s already assigned, line %d\n",
name, line_num);
return;
}
/* Build structure for this channel */
cp = (Chan *)build_db_struct(vp);
cp->db_name = db_name; /* DB name */
/* The entire variable is assigned */
cp->count = vp->length1 * vp->length2;
cp->mon_flag = FALSE; /* assume no monitor */
cp->ef_var = NULL; /* assume no sync event flag */
return;
}
/* Parsing a "monitor" statement */
monitor_stmt(name, delta)
char *name; /* variable name (should be assigned) */
char *delta; /* monitor delta */
/* "Assign" statement: assign an array element to a DB channel.
* Format: assign <variable>[<subscr>] to <string>; */
assign_subscr(name, subscript, db_name)
char *name; /* ptr to variable name */
char *subscript; /* subscript value or NULL */
char *db_name; /* ptr to db name */
{
Chan *cp;
Chan *cp;
Var *vp;
int subNum;
extern int line_num;
#ifdef DEBUG
fprintf(stderr, "assign %s[%s] to \"%s\";\n", name, subscript, db_name);
#endif DEBUG
/* Find the variable */
vp = (Var *)findVar(name);
if (vp == 0)
{
fprintf(stderr, "assign: variable %s not declared, line %d\n",
name, line_num);
return;
}
if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
{
fprintf(stderr, "assign: variable %s not an array, line %d\n",
name, line_num);
return;
}
cp = vp->chan;
if (cp == NULL)
{
/* Build structure for this channel */
cp = (Chan *)build_db_struct(vp);
}
else if (cp->db_name != NULL)
{
fprintf(stderr, "assign: array %s already assigned, line %d\n",
name, line_num);
return;
}
subNum = atoi(subscript);
if (subNum < 0 || subNum >= vp->length1)
{
fprintf(stderr,
"assign: subscript %s[%d] is out of range, line %d\n",
name, subNum, line_num);
return;
}
if (cp->db_name_list == NULL)
alloc_db_lists(cp, vp->length1); /* allocate lists */
else if (cp->db_name_list[subNum] != NULL)
{
fprintf(stderr, "assign: %s[%d] already assigned, line %d\n",
name, subNum, line_num);
return;
}
cp->db_name_list[subNum] = db_name;
cp->count = vp->length2; /* could be a 2-dimensioned array */
return;
}
/* Assign statement: assign an array to multiple DB channels.
* Format: assign <variable> to { <string>, <string>, ... };
* Assignments for double dimensioned arrays:
* <var>[0][0] assigned to 1st db name,
* <var>[1][0] assigned to 2nd db name, etc.
* If db name list contains fewer names than the array dimension,
* the remaining elements receive NULL assignments.
*/
assign_list(name, db_name_list)
char *name; /* ptr to variable name */
Expr *db_name_list; /* ptr to db name list */
{
Chan *cp;
Var *vp;
int elem_num;
extern int line_num;
#ifdef DEBUG
fprintf(stderr, "assign %s to {", name);
#endif DEBUG
/* Find the variable */
vp = (Var *)findVar(name);
if (vp == 0)
{
fprintf(stderr, "assign: variable %s not declared, line %d\n",
name, line_num);
return;
}
if (vp->class != VC_ARRAY1 && vp->class != VC_ARRAY2)
{
fprintf(stderr, "assign: variable %s is not an array, line %d\n",
name, line_num);
return;
}
cp = vp->chan;
if (cp != NULL)
{
fprintf(stderr, "assign: variable %s already assigned, line %d\n",
name, line_num);
return;
}
/* Build a db structure for this variable */
cp = (Chan *)build_db_struct(vp);
/* Allocate lists */
alloc_db_lists(cp, vp->length1); /* allocate lists */
/* fill in the array of pv names */
for (elem_num = 0; elem_num < vp->length1; elem_num++)
{
if (db_name_list == NULL)
break; /* end of list */
#ifdef DEBUG
fprintf(stderr, "\"%s\", ", db_name_list->value);
#endif DEBUG
cp->db_name_list[elem_num] = db_name_list->value; /* DB name */
cp->count = vp->length2;
db_name_list = db_name_list->next;
}
#ifdef DEBUG
fprintf(stderr, "};\n");
#endif DEBUG
return;
}
/* Build a db structure for this variable */
build_db_struct(vp)
Var *vp;
{
Chan *cp;
cp = allocChan();
addChan(cp); /* add to Chan list */
/* make connections between Var & Chan structures */
cp->var = vp;
vp->chan = cp;
/* Initialize the structure */
cp->db_name_list = 0;
cp->mon_flag_list = 0;
cp->ef_var_list = 0;
cp->ef_num_list = 0;
cp->num_elem = 0;
cp->mon_flag = 0;
cp->ef_var = 0;
cp->ef_num = 0;
return (int)cp;
}
/* Allocate lists for assigning multiple pv's to a variable */
alloc_db_lists(cp, length)
Chan *cp;
int length;
{
/* allocate an array of pv names */
cp->db_name_list = (char **)calloc(sizeof(char **), length);
/* allocate an array for monitor flags */
cp->mon_flag_list = (int *)calloc(sizeof(int **), length);
/* allocate an array for event flag var ptrs */
cp->ef_var_list = (Var **)calloc(sizeof(Var **), length);
/* allocate an array for event flag numbers */
cp->ef_num_list = (int *)calloc(sizeof(int **), length);
cp->num_elem = length;
}
/* Parsing a "monitor" statement.
* Format:
* monitor <var>; - monitor a single variable or all elements in an array.
* monitor <var>[<m>]; - monitor m-th element of an array.
*/
monitor_stmt(name, subscript)
char *name; /* variable name (should be assigned) */
char *subscript; /* element number or NULL */
{
Var *vp;
Chan *cp;
int subNum;
extern int line_num;
#ifdef DEBUG
fprintf(stderr, "monitor_stmt: name=%s[%s]\n", name, subscript);
#endif DEBUG
/* Find the variable */
vp = (Var *)findVar(name);
if (vp == 0)
{
fprintf(stderr, "assign: variable %s not declared, line %d\n",
name, line_num);
return;
}
/* Find a channel assigned to this variable */
cp = (Chan *)findChan(name);
cp = vp->chan;
if (cp == 0)
{
fprintf(stderr, "monitor: variable %s not assigned, line %d\n",
@@ -206,22 +438,67 @@ char *delta; /* monitor delta */
return;
}
/* Enter monitor parameters */
cp->mon_flag = TRUE;
cp->delta = atof(delta);
if (subscript == NULL)
{
if (cp->num_elem == 0)
{ /* monitor one channel for this variable */
cp->mon_flag = TRUE;
return;
}
/* else monitor all channels in db list */
for (subNum = 0; subNum < cp->num_elem; subNum++)
{ /* 1 pv per element of the array */
cp->mon_flag_list[subNum] = TRUE;
}
return;
}
/* subscript != NULL */
subNum = atoi(subscript);
if (subNum < 0 || subNum >= cp->num_elem)
{
fprintf(stderr, "monitor: subscript of %s out of range, line %d\n",
name, line_num);
return;
}
if (cp->num_elem == 0 || cp->db_name_list[subNum] == NULL)
{
fprintf(stderr, "monitor: %s[%d] not assigned, line %d\n",
name, subNum, line_num);
return;
}
cp->mon_flag_list[subNum] = TRUE;
return;
}
/* Parsing "sync" statement */
sync_stmt(name, ef_name)
char *name;
char *ef_name;
sync_stmt(name, subscript, ef_name)
char *name;
char *subscript;
char *ef_name;
{
Chan *cp;
Var *vp;
extern int line_num;
int subNum;
cp = (Chan *)findChan(name);
#ifdef DEBUG
fprintf(stderr, "sync_stmt: name=%s, subNum=%s, ef_name=%s\n",
name, subscript, ef_name);
#endif DEBUG
vp = (Var *)findVar(name);
if (vp == 0)
{
fprintf(stderr, "sync: variable %s not declared, line %d\n",
name, line_num);
return;
}
cp = vp->chan;
if (cp == 0)
{
fprintf(stderr, "sync: variable %s not assigned, line %d\n",
@@ -238,36 +515,56 @@ char *ef_name;
return;
}
/* Insert pointers between Var & Chan structures */
cp->ef_var = vp;
vp->chan = cp;
if (subscript == NULL)
{ /* no subscript */
if (cp->db_name != NULL)
{ /* 1 pv assigned to this variable */
cp->ef_var = vp;
return;
}
/* 1 pv per element in the array */
for (subNum = 0; subNum < cp->num_elem; subNum++)
{
cp->ef_var_list[subNum] = vp;
}
return;
}
/* subscript != NULL */
subNum = atoi(subscript);
if (subNum < 0 || subNum >= cp->num_elem)
{
fprintf(stderr,
"sync: subscript %s[%d] out of range, line %d\n",
name, subNum, line_num);
return;
}
cp->ef_var_list[subNum] = vp; /* sync to a specific element of the array */
return;
}
/* Definition C code */
defn_c_stmt(c_str)
char *c_str; /* ptr to C code string */
defn_c_stmt(c_list)
Expr *c_list; /* ptr to C code */
{
Expr *ep;
#ifdef DEBUG
fprintf(stderr, "defn_c_stmt\n");
#endif
ep = expression(E_TEXT, "", c_str, 0);
if (defn_c_list == 0)
defn_c_list = ep;
defn_c_list = c_list;
else
link_expr(defn_c_list, ep);
link_expr(defn_c_list, c_list);
return;
}
/* Global C code (follows state program) */
global_c_stmt(c_str)
char *c_str; /* ptr to C code */
global_c_stmt(c_list)
Expr *c_list; /* ptr to C code */
{
global_c_list = expression(E_TEXT, "", c_str, 0);
global_c_list = c_list;
return;
}
@@ -292,22 +589,13 @@ char *name;
{
Var *vp;
#ifdef DEBUG
fprintf(stderr, "findVar, name=%s: ", name);
#endif
for (vp = var_list; vp != NULL; vp = vp->next)
{
if (strcmp(vp->name, name) == 0)
{
#ifdef DEBUG
fprintf(stderr, "found\n");
#endif
return vp;
}
}
#ifdef DEBUG
fprintf(stderr, "not found\n");
#endif
return 0;
}
@@ -322,35 +610,6 @@ Chan *cp;
chan_tail = cp;
cp->next = NULL;
}
/* Find a channel with a given associated variable name */
Chan *findChan(name)
char *name; /* variable name */
{
Chan *cp;
Var *vp;
#ifdef DEBUG
fprintf(stderr, "findChan, var name=%s: ", name);
#endif
for (cp = chan_list; cp != NULL; cp = cp->next)
{
vp = cp->var;
if (vp == 0)
continue;
if (strcmp(vp->name, name) == 0)
{
#ifdef DEBUG
fprintf(stderr, "found chan name=%s\n", cp->db_name);
#endif
return cp;
}
}
#ifdef DEBUG
fprintf(stderr, "not found\n");
#endif
return 0;
}
/* Set debug print opt */
set_debug_print(opt)
@@ -366,7 +625,7 @@ Expr *prog_list;
ss_list = prog_list;
#ifdef DEBUG
fprintf(stderr, "----Phase2---\n");
#endif /* DEBUG */
#endif DEBUG
phase2(ss_list);
exit(0);
@@ -442,7 +701,7 @@ Expr *ep2; /* beginning 2-nd (append it to 1-st) */
break;
}
fprintf(stderr, ")\n");
#endif /* DEBUG */
#endif DEBUG
return ep1;
}
@@ -452,7 +711,7 @@ char *line;
char *fname;
{
extern int line_num;
extern char *src_file;
extern char *src_file;
line_num = atoi(line);
src_file = fname;
@@ -462,4 +721,6 @@ char *fname;
char *stype[] = {
"E_EMPTY", "E_CONST", "E_VAR", "E_FUNC", "E_STRING", "E_UNOP", "E_BINOP",
"E_ASGNOP", "E_PAREN", "E_SUBSCR", "E_TEXT", "E_STMT", "E_CMPND",
"E_IF", "E_ELSE", "E_WHILE", "E_SS", "E_STATE", "E_WHEN" };
"E_IF", "E_ELSE", "E_WHILE", "E_SS", "E_STATE", "E_WHEN",
"E_FOR", "E_X", "E_PRE", "E_POST", "E_BREAK", "E_COMMA",
"E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?", "E_?" };

View File

@@ -1,13 +1,17 @@
/**************************************************************************
GTA PROJECT AT division
Copyright, 1989, The Regents of the University of California.
Copyright, 1989-93, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
parse.h,v 1.2 1995/06/27 15:25:50 wright Exp
DESCRIPTION: Structures for parsing the state notation language.
ENVIRONMENT: UNIX
HISTORY:
18nov91,ajk Replaced lstLib stuff with in-line links.
28oct93,ajk Added support for assigning array elements to pv's.
28oct93,ajk Added support for pointer declarations (see VC_*)
5nov93,ajk Changed structures var & db_chan to handle array assignments.
5nov93,ajk changed malloc() to calloc() 3 places.
***************************************************************************/
/* Data for these blocks are generated by the parsing routines for each
** state set. The tables are then used to generate the run-time C code
@@ -34,41 +38,47 @@ struct var /* Variable or function definition */
char *name; /* variable name */
char *value; /* initial value or NULL */
int type; /* var type */
int length; /* array lth (0 if not an array) */
int ef_num; /* event flag bit number */
struct db_chan *chan; /* ptr to db channel struct or NULL */
int class; /* simple, array, or pointer */
int length1; /* 1st dim. array lth (default=1) */
int length2; /* 2nd dim. array lth (default=1) */
int ef_num; /* bit number if this is an event flag */
struct db_chan *chan; /* ptr to channel struct if assigned */
};
typedef struct var Var;
struct db_chan /* DB channel info */
struct db_chan /* DB channel assignment info */
{
struct db_chan *next; /* link to next item in list */
char *db_name; /* database name */
int index; /* channel array index */
char *db_name; /* database name (assign all to 1 pv) */
char **db_name_list; /* list of db names (assign each to a pv) */
int num_elem; /* number of elements assigned in db_name_list */
Var *var; /* ptr to variable definition */
Var *ef_var; /* ptr to event flag variable for sync */
int count; /* count for db access */
int mon_flag; /* TRUE if channel is "monitored" */
float delta; /* monitor dead-band */
float timeout; /* monitor timeout */
int *mon_flag_list; /* ptr to list of monitor flags */
Var *ef_var; /* ptr to event flag variable for sync */
Var **ef_var_list; /* ptr to list of event flag variables */
int ef_num; /* event flag number */
int *ef_num_list; /* list of event flag numbers */
int index; /* index in database channel array (seqChan) */
};
typedef struct db_chan Chan;
/* Note: Only one of db_name or db_name_list can have a non-zero value */
Expr *expression(), *link_expr();
Var *findVar();
Chan *findChan();
/* Linked list allocation definitions */
#define allocExpr() (Expr *)malloc(sizeof(Expr));
#define allocVar() (Var *)malloc(sizeof(Var));
#define allocChan() (Chan *)malloc(sizeof(Chan));
#define allocExpr() (Expr *)calloc(1, sizeof(Expr));
#define allocVar() (Var *)calloc(1, sizeof(Var));
#define allocChan() (Chan *)calloc(1, sizeof(Chan));
/* Variable types */
#define V_NONE 0 /* not defined */
#define V_CHAR 1 /* char */
#define V_SHORT 2 /* short */
#define V_INT 3 /* int (but converted to long) */
#define V_INT 3 /* int */
#define V_LONG 4 /* long */
#define V_FLOAT 5 /* float */
#define V_DOUBLE 6 /* double */
@@ -77,9 +87,16 @@ Chan *findChan();
#define V_FUNC 9 /* function (not a variable) */
#define V_UCHAR 11 /* unsigned char */
#define V_USHORT 12 /* unsigned short */
#define V_UINT 13 /* unsigned int (converted to unsigned long) */
#define V_UINT 13 /* unsigned int */
#define V_ULONG 14 /* unsigned long */
/* Variable classes */
#define VC_SIMPLE 0 /* simple (un-dimentioned) variable */
#define VC_ARRAY1 1 /* single dim. array */
#define VC_ARRAY2 2 /* multiple dim. array */
#define VC_POINTER 3 /* pointer */
#define VC_ARRAYP 4 /* array of pointers */
/* Expression types */
#define E_EMPTY 0 /* empty expression */
#define E_CONST 1 /* numeric constant */

View File

@@ -3,23 +3,29 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
phase2.c,v 1.2 1995/06/27 15:25:52 wright Exp
DESCRIPTION: Phase 2 code generation routines for SNC.
Produces code and tables in C output file.
See also: gen_ss_code.c
See also: gen_ss_code.c and gen_tables.c
ENVIRONMENT: UNIX
HISTORY:
19nov91,ajk Replaced lstLib calls with built-in linked list.
19nov91,ajk Removed extraneous "static" from "UserVar" declaration.
01mar94,ajk Implemented new interface to sequencer (seqCom.h).
01mar94,ajk Implemented assignment of array elements to db channels.
01mar94,ajk Changed algorithm for assigning event bits.
***************************************************************************/
/*#define DEBUG 1*/
#include <stdio.h>
#include "parse.h"
#include <dbDefs.h>
#include <seqU.h>
#include <seqCom.h>
int num_channels = 0; /* number of db channels */
int num_events = 0; /* number of event flags */
int num_ss = 0; /* number of state sets */
int max_delays = 0; /* maximum number of delays per state */
int num_errors = 0; /* number of errors detected in phase 2 processing */
/*+************************************************************************
@@ -31,7 +37,7 @@ int num_errors = 0; /* number of errors detected in phase 2 processing */
*
* RETURNS: n/a
*
* FUNCTION: Generate C code from tables.
* FUNCTION: Generate C code from parsing lists.
*
* NOTES: All inputs are external globals.
*-*************************************************************************/
@@ -51,6 +57,12 @@ phase2()
/* reconcile all state names, including next state in transitions */
reconcile_states();
/* Assign bits for event flags */
assign_ef_bits();
/* Assign delay id's */
assign_delay_ids();
/* Generate preamble code */
gen_preamble();
@@ -60,12 +72,6 @@ phase2()
/* Generate definition C code */
gen_defn_c_code();
/* Assign bits for event flags */
assign_ef_bits();
/* Assign delay id's */
assign_delay_ids();
/* Generate code for each state set */
gen_ss_code();
@@ -87,11 +93,16 @@ gen_preamble()
printf("/* Program \"%s\" */\n", prog_name);
/* Include files */
printf("#include \"seq.h\"\n");
printf("#define ANSI\n"); /* Expands ANSI prototypes in seqCom.h */
printf("#include \"seqCom.h\"\n");
/* Local definitions */
printf("\n#define NUM_SS %d\n", num_ss);
printf("#define NUM_CHANNELS %d\n", num_channels);
printf("#define NUM_EVENTS %d\n", num_events);
/* The following definition should be consistant with db_access.h */
printf("#define MAX_STRING_SIZE 40\n");
/* #define's for compiler options */
gen_opt_defn(async_opt, "ASYNC_OPT");
@@ -101,12 +112,13 @@ gen_preamble()
printf("\n");
/* Forward references of tables: */
printf("\nextern SPROG %s;\n", prog_name);
printf("extern CHAN db_channels[];\n");
printf("\nextern struct seqProgram %s;\n", prog_name);
printf("extern struct seqChan seqChan[];\n");
return;
}
/* Generate defines for compiler options */
gen_opt_defn(opt, defn_name)
int opt;
char *defn_name;
@@ -118,8 +130,9 @@ char *defn_name;
}
/* Reconcile all variables in an expression,
and tie each to the appropriate VAR struct */
int printTree = FALSE;
* and tie each to the appropriate VAR structure.
*/
int printTree = FALSE; /* For debugging only */
reconcile_variables()
{
@@ -131,7 +144,7 @@ reconcile_variables()
{
#ifdef DEBUG
fprintf(stderr, "reconcile_variables: ss=%s\n", ssp->value);
#endif /* DEBUG */
#endif DEBUG
traverseExprTree(ssp, E_VAR, 0, connect_variable, 0);
}
@@ -151,6 +164,11 @@ Expr *ep;
extern char *stype[];
extern int warn_opt;
if (ep->type != E_VAR)
return;
#ifdef DEBUG
fprintf(stderr, "connect_variable: \"%s\", line %d\n", ep->value, ep->line_num);
#endif
vp = (Var *)findVar(ep->value);
if (vp == 0)
{ /* variable not declared; add it to the variable list */
@@ -162,39 +180,39 @@ Expr *ep;
addVar(vp);
vp->name = ep->value;
vp->type = V_NONE; /* undeclared type */
vp->length = 0;
vp->length1 = 1;
vp->length2 = 1;
vp->value = 0;
}
ep->left = (Expr *)vp; /* make connection */
#ifdef DEBUG
fprintf(stderr, "connect_variable: %s\n", ep->value);
#endif
return;
}
/* Reconcile state names */
reconcile_states()
{
extern Expr *ss_list;
extern int num_errors;
extern Expr *ss_list;
Expr *ssp, *sp, *sp1, tr;
for (ssp = ss_list; ssp != 0; ssp = ssp->next)
{
for (sp = ssp->left; sp != 0; sp = sp->next)
for (sp = ssp->left; sp != 0; sp = sp->next)
{
/* Check for duplicate state names in this state set */
for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next)
{
/* Check for duplicate state names in this state set */
for (sp1 = sp->next; sp1 != 0; sp1 = sp1->next)
if (strcmp(sp->value, sp1->value) == 0)
{
if (strcmp(sp->value, sp1->value) == 0)
{
fprintf(stderr,
"State \"%s\" is duplicated in state set \"%s\"\n",
sp->value, ssp->value);
num_errors++;
}
}
}
fprintf(stderr,
"State \"%s\" is duplicated in state set \"%s\"\n",
sp->value, ssp->value);
num_errors++;
}
}
}
}
}
@@ -231,47 +249,60 @@ gen_var_decl()
{
switch (vp->type)
{
case V_CHAR:
case V_CHAR:
vstr = "char";
break;
case V_INT:
case V_LONG:
case V_INT:
vstr = "int";
break;
case V_LONG:
vstr = "long";
break;
case V_SHORT:
case V_SHORT:
vstr = "short";
break;
case V_FLOAT:
case V_FLOAT:
vstr = "float";
break;
case V_DOUBLE:
case V_DOUBLE:
vstr = "double";
break;
case V_STRING:
case V_STRING:
vstr = "char";
break;
case V_EVFLAG:
case V_NONE:
case V_EVFLAG:
case V_NONE:
vstr = NULL;
break;
default:
default:
vstr = "int";
break;
}
if (vstr == NULL)
continue;
if (vstr != NULL)
{
if (reent_opt)
printf("\t");
else
printf("static ");
printf("%s\t%s", vstr, vp->name);
if (vp->length > 0)
printf("[%d]", vp->length);
else if (vp->type == V_STRING)
printf("[MAX_STRING_SIZE]");
printf(";\n");
}
if (reent_opt)
printf("\t");
else
printf("static ");
printf("%s\t", vstr);
if (vp->class == VC_POINTER || vp->class == VC_ARRAYP)
printf("*");
printf("%s", vp->name);
if (vp->class == VC_ARRAY1 || vp->class == VC_ARRAYP)
printf("[%d]", vp->length1);
else if (vp->class == VC_ARRAY2)
printf("[%d][%d]", vp->length1, vp->length2);
if (vp->type == V_STRING)
printf("[MAX_STRING_SIZE]");
printf(";\n");
}
if (reent_opt)
printf("};\n");
@@ -306,16 +337,17 @@ gen_global_c_code()
if (ep != NULL)
{
printf("\f\t/* Global C code */\n");
print_line_num(ep->line_num, ep->src_file);
for (; ep != NULL; ep = ep->next)
{
print_line_num(ep->line_num, ep->src_file);
printf("%s\n", ep->left);
}
}
return;
}
/* Returns number of db channels defined & inserts index into each channel struct */
/* Sets cp->index for each variable, & returns number of db channels defined.
*/
db_chan_count()
{
extern Chan *chan_list;
@@ -325,57 +357,68 @@ db_chan_count()
nchan = 0;
for (cp = chan_list; cp != NULL; cp = cp->next)
{
if (cp->db_name != NULL)
{
cp->index = nchan;
nchan++;
#ifdef DEBUG
fprintf(stderr, "db_name=%s, index=%d\n",
cp->db_name, cp->index);
#endif
}
cp->index = nchan;
if (cp->num_elem == 0)
nchan += 1;
else
nchan += cp->num_elem; /* array with multiple channels */
}
return nchan;
}
/* Assign bits to event flags and database variables */
/* Assign event bits to event flags and associate db channels with
* event flags.
*/
assign_ef_bits()
{
extern Var *var_list;
Var *vp;
Chan *cp;
int ef_num;
extern int num_channels;
extern Var *var_list;
extern Chan *chan_list;
Var *vp;
Chan *cp;
extern int num_events;
int n;
ef_num = num_channels + 1; /* start with 1-st avail mask bit */
/* Assign event flag numbers (starting at 1) */
printf("\n/* Event flags */\n");
#ifdef DEBUG
fprintf(stderr, "\nAssign values to event flags\n");
#endif
num_events = 0;
for (vp = var_list; vp != NULL; vp = vp->next)
{
cp = vp->chan;
/* First see if this is an event flag */
if (vp->type == V_EVFLAG)
{
if (cp != 0)
vp->ef_num = cp->index + 1; /* sync'ed */
else
vp->ef_num = ef_num++;
printf("#define %s\t%d\n", vp->name, vp->ef_num);
num_events++;
vp->ef_num = num_events;
printf("#define %s\t%d\n", vp->name, num_events);
}
else
{
if (cp != 0)
vp->ef_num = cp->index + 1;
}
#ifdef DEBUG
fprintf(stderr, "%s: ef_num=%d\n", vp->name, vp->ef_num);
#endif
}
/* Associate event flags with DB channels */
for (cp = chan_list; cp != NULL; cp = cp->next)
{
if (cp->num_elem == 0)
{
if (cp->ef_var != NULL)
{
vp = cp->ef_var;
cp->ef_num = vp->ef_num;
}
}
else /* cp->num_elem != 0 */
{
for (n = 0; n < cp->num_elem; n++)
{
vp = cp->ef_var_list[n];
if (vp != NULL)
{
cp->ef_num_list[n] = vp->ef_num;
}
}
}
}
return;
}
@@ -387,6 +430,9 @@ assign_delay_ids()
int delay_id;
int assign_next_delay_id();
#ifdef DEBUG
fprintf(stderr, "assign_delay_ids:\n");
#endif DEBUG
for (ssp = ss_list; ssp != 0; ssp = ssp->next)
{
for (sp = ssp->left; sp != 0; sp = sp->next)
@@ -398,6 +444,10 @@ assign_delay_ids()
traverseExprTree(tp->left, E_FUNC, "delay",
assign_next_delay_id, &delay_id);
}
/* Keep track of number of delay id's requied */
if (delay_id > max_delays)
max_delays = delay_id;
}
}
}
@@ -409,9 +459,10 @@ int *delay_id;
ep->right = (Expr *)*delay_id;
*delay_id += 1;
}
/* Traverse the expression tree, and call the supplied
* function on matched conditions */
/* Traverse the expression tree, and call the supplied
* function whenever type = ep->type AND value matches ep->value.
* The condition value = 0 matches all.
* The function is called with the current ep and a supplied argument (argp) */
traverseExprTree(ep, type, value, funcp, argp)
Expr *ep; /* ptr to start of expression */
int type; /* to search for */
@@ -430,8 +481,7 @@ void *argp; /* ptr to argument to pass on to function */
stype[ep->type], ep->value);
/* Call the function? */
if ((ep->type == type) &&
(value == 0 || strcmp(ep->value, value) == 0) )
if ((ep->type == type) && (value == 0 || strcmp(ep->value, value) == 0) )
{
funcp(ep, argp);
}
@@ -439,7 +489,6 @@ void *argp; /* ptr to argument to pass on to function */
/* Continue traversing the expression tree */
switch(ep->type)
{
case E_EMPTY:
case E_VAR:
case E_CONST:
case E_STRING:

View File

@@ -1,4 +1,6 @@
/* $Id$
/*
seq_ca.c,v 1.2 1995/06/27 15:25:54 wright Exp
* DESCRIPTION: Channel access interface for sequencer.
*
* Author: Andy Kozubal
@@ -6,7 +8,7 @@
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* Copyright 1991-1994, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
@@ -37,16 +39,23 @@
* all state programs. Added seq_disconnect() and ca_import_cancel().
DB name resolution was moved to seq_main.c.
* 19feb93,ajk Added patched version of VxWorks 5.02b taskVarDelete().
* 01mar94,ajk Moved "seq_pv*()" functions to seq_if.c.
* 28mar94,ajk Restructured event& callback handlers to call proc_db_events().
* 29mar94,ajk Removed getPtrToValue(). Offset is now in db_channel structure.
* 08apr94,ajk Added support for time stamp.
*/
#define ANSI
#include "seq.h"
#include <string.h>
LOCAL VOID *getPtrToValue(union db_access_val *, chtype);
LOCAL VOID proc_db_events(union db_access_val *, CHAN *, int);
/*#define DEBUG*/
#ifdef DEBUG
#undef LOCAL
#define LOCAL
#endif DEBUG
/*
* seq_connect() - Connect to all database channels through channel access.
*/
@@ -58,21 +67,22 @@ SPROG *pSP;
extern VOID seq_conn_handler();
extern int seqInitialTaskId;
pSP->conn_count = 0;
/*
* For each channel: substitute macros, connect to db,
* & isssue monitor (if monitor request flaf is TRUE).
* For each channel: connect to db & isssue monitor (if monFlag is TRUE).
*/
pDB = pSP->channels;
for (i = 0; i < pSP->nchan; i++)
for (i = 0, pDB = pSP->pChan; i < pSP->numChans; i++, pDB++)
{
if (pDB->dbName == NULL || pDB->dbName[0] == 0)
continue; /* skip records without pv names */
pDB->assigned = TRUE;
pSP->assignCount += 1; /* keep track of number of *assigned* channels */
#ifdef DEBUG
printf("connect to \"%s\"\n", pDB->db_name);
#endif /* DEBUG */
logMsg("seq_connect: connect %s to %s\n",
pDB->pVarName, pDB->dbName);
#endif DEBUG
/* Connect to it */
status = ca_build_and_connect(
pDB->db_name, /* DB channel name */
pDB->dbName, /* DB channel name */
TYPENOTCONN, /* Don't get initial value */
0, /* get count (n/a) */
&(pDB->chid), /* ptr to chid */
@@ -91,16 +101,19 @@ SPROG *pSP;
/*
* Issue monitor request
*/
if (pDB->mon_flag)
if (pDB->monFlag)
{
seq_pvMonitor(pSP, 0, pDB);
seq_pvMonitor((SS_ID)pSP->pSS, i);
}
pDB++;
}
ca_flush_io();
return 0;
}
/*
#define GET_COMPLETE 0
#define MON_COMPLETE 1
/*
* seq_event_handler() - Channel access events (monitors) come here.
* args points to CA event handler argument structure. args.usr contains
* a pointer to the channel structure (CHAN *).
@@ -108,33 +121,75 @@ SPROG *pSP;
VOID seq_event_handler(args)
struct event_handler_args args;
{
SPROG *pSP;
CHAN *pDB;
struct dbr_sts_char *dbr_sts_ptr;
void *pVal;
int i, nbytes;
/* User arg is ptr to db channel structure */
pDB = (CHAN *)args.usr;
/* Copy value returned into user variable */
pVal = getPtrToValue((union db_access_val *)args.dbr, pDB->get_type);
nbytes = pDB->size * pDB->count;
memcpy(pDB->var, pVal, nbytes);
/* Copy status & severity */
dbr_sts_ptr = (struct dbr_sts_char *)args.dbr;
pDB->status = dbr_sts_ptr->status;
pDB->severity = dbr_sts_ptr->severity;
/* Process event handling in each state set */
pSP = pDB->sprog; /* State program that owns this db entry */
/* Wake up each state set that is waiting for event processing */
seq_efSet(pSP, 0, pDB->index + 1);
proc_db_events((union db_access_val *)args.dbr, (CHAN *)args.usr, MON_COMPLETE);
return;
}
/*
* seq_callback_handler() - Sequencer callback handler.
* Called when a "get" completes.
* args.usr points to the db structure (CHAN *) for tis channel.
*/
VOID seq_callback_handler(args)
struct event_handler_args args;
{
/* Process event handling in each state set */
proc_db_events((union db_access_val *)args.dbr, (CHAN *)args.usr, GET_COMPLETE);
return;
}
/* Common code for event and callback handling */
LOCAL VOID proc_db_events(pAccess, pDB, complete_type)
union db_access_val *pAccess;
CHAN *pDB;
int complete_type;
{
SPROG *pSP;
void *pVal;
int i;
#ifdef DEBUG
logMsg("proc_db_events: var=%s, pv=%s\n", pDB->VarName, pDB->dbName);
#endif DEBUG
/* Copy value returned into user variable */
pVal = (void *)pAccess + pDB->dbOffset; /* ptr to data in CA structure */
bcopy(pVal, pDB->pVar, pDB->size * pDB->dbCount);
/* Copy status & severity */
pDB->status = pAccess->tchrval.status;
pDB->severity = pAccess->tchrval.severity;
/* Copy time stamp */
pDB->timeStamp = pAccess->tchrval.stamp;
/* Get ptr to the state program that owns this db entry */
pSP = pDB->sprog;
/* Wake up each state set that uses this channel in an event */
seqWakeup(pSP, pDB->eventNum);
/* If there's an event flag associated with this channel, set it */
if (pDB-> efId > 0)
seq_efSet((SS_ID)pSP->pSS, pDB->efId);
/* Special processing for completed pvGet() */
if (complete_type == GET_COMPLETE)
{
pDB->getComplete = TRUE;
/* If syncronous pvGet then notify pending state set */
if (pDB->getSemId != NULL)
semGive(pDB->getSemId);
}
return;
}
/* Disconnect all database channels */
seq_disconnect(pSP)
SPROG *pSP;
@@ -143,43 +198,54 @@ SPROG *pSP;
STATUS status;
int i;
extern int seqAuxTaskId;
SPROG *pMySP; /* NULL if this task is not a sequencer task */
/* Did we already disconnect? */
if (pSP->conn_count < 0)
if (pSP->connCount < 0)
return 0;
/* Import Channel Access context from the auxillary seq. task */
ca_import(seqAuxTaskId);
pDB = pSP->channels;
for (i = 0; i < pSP->nchan; i++)
pMySP = seqFindProg(taskIdSelf() );
if (pMySP == NULL)
{
ca_import(seqAuxTaskId); /* not a sequencer task */
}
pDB = pSP->pChan;
for (i = 0; i < pSP->numChans; i++, pDB++)
{
if (!pDB->assigned)
continue;
#ifdef DEBUG
printf("disconnect \"%s\"\n", pDB->db_name);
#endif /* DEBUG */
logMsg("seq_disconnect: disconnect %s from %s\n",
pDB->pVarName, pDB->dbName);
taskDelay(30);
#endif DEBUG
/* Disconnect this channel */
status = ca_clear_channel(pDB->chid);
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_clear_chan");
ca_task_exit();
return -1;
/* SEVCHK(status, "ca_clear_chan"); */
/* ca_task_exit(); */
/* return -1; */
}
/* Clear monitor & connect indicators */
pDB->monitored = FALSE;
pDB->connected = FALSE;
pDB++;
}
pSP->conn_count = -1; /* flag to indicate all disconnected */
pSP->connCount = -1; /* flag to indicate all disconnected */
ca_flush_io();
/* Cancel CA import */
ca_import_cancel(taskIdSelf());
/* Cancel CA context if it was imported above */
if (pMySP == NULL)
{
logMsg("seq_disconnect: cancel import CA context\n");
ca_import_cancel(taskIdSelf());
}
return 0;
}
@@ -204,309 +270,55 @@ struct connection_handler_args args;
if (ca_field_type(args.chid) == TYPENOTCONN)
{
pDB->connected = FALSE;
pSP->conn_count--;
pSP->connCount--;
pDB->monitored = FALSE;
#ifdef DEBUG
seq_log(pSP, "Channel \"%s\" disconnected\n", pDB->db_name);
#endif /* DEBUG */
logMsg("%s disconnected from %s\n", pDB->VarName, pDB->dbName);
#endif DEBUG
}
else
else /* PV connected */
{
pDB->connected = TRUE;
pSP->conn_count++;
pSP->connCount++;
if (pDB->monFlag)
pDB->monitored = TRUE;
#ifdef DEBUG
seq_log(pSP, "Channel \"%s\" connected\n", pDB->db_name);
#endif /* DEBUG */
if (pDB->count > ca_element_count(args.chid))
{
pDB->count = ca_element_count(args.chid);
#ifdef DEBUG
seq_log(pSP, "\"%s\": reset count to %d\n",
pDB->db_name, pDB->count);
#endif /* DEBUG */
}
logMsg("%s connected to %s\n", pDB->VarName, pDB->dbName);
#endif DEBUG
pDB->dbCount = ca_element_count(args.chid);
if (pDB->dbCount > pDB->count)
pDB->dbCount = pDB->count;
}
/* Wake up each state set that is waiting for event processing */
seq_efSet(pSP, 0, 0);
seqWakeup(pSP, 0);
return;
}
/*
* seq_efSet() - Set an event flag, then wake up each state
* set that might be waiting on that event flag.
* seqWakeup() -- wake up each state set that is waiting on this event
* based on the current event mask. EventNum = 0 means wake all state sets.
*/
VOID seq_efSet(pSP, dummy, ev_flag)
VOID seqWakeup(pSP, eventNum)
SPROG *pSP;
int dummy;
int ev_flag; /* event flag */
int eventNum;
{
SSCB *pSS;
int nss;
SSCB *pSS;
/* Set this bit (apply resource lock) */
semTake(pSP->caSemId, WAIT_FOREVER);
bitSet(pSP->events, ev_flag);
/* Check flag against mask for all state sets: */
for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++)
/* Check event number against mask for all state sets: */
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
{
/* Test for possible event trig based on bit mask for this state */
if ( (ev_flag == 0) || bitTest(pSS->pMask, ev_flag) )
/* If event bit in mask is set, wake that state set */
if ( (eventNum == 0) || bitTest(pSS->pMask, eventNum) )
{
semGive(pSS->syncSemId); /* wake up the ss task */
}
}
/* Unlock resource */
semGive(pSP->caSemId);
}
/*
* seq_efTest() - Test event flag against outstanding events.
*/
int seq_efTest(pSP, pSS, ev_flag)
SPROG *pSP;
SSCB *pSS;
int ev_flag; /* event flag */
{
return bitTest(pSP->events, ev_flag);
}
/*
* seq_efClear() - Test event flag against outstanding events, then clear it.
*/
int seq_efClear(pSP, pSS, ev_flag)
SPROG *pSP;
SSCB *pSS;
int ev_flag; /* event flag */
{
int isSet;
isSet = bitTest(pSP->events, ev_flag);
bitClear(pSP->events, ev_flag);
return isSet;
}
/*
* seq_pvGet() - Get DB value (uses channel access).
*/
seq_pvGet(pSP, pSS, pDB)
SPROG *pSP; /* ptr to state program */
SSCB *pSS; /* ptr to current state set */
CHAN *pDB; /* ptr to channel struct */
{
int status, sem_status;
extern VOID seq_callback_handler();
/* Check for channel connected */
if (!pDB->connected)
return ECA_DISCONN;
/* Flag this pvGet() as not completed */
pDB->get_complete = FALSE;
/* If synchronous pvGet then clear the pvGet pend semaphore */
if ( !(pSP->options & OPT_ASYNC) )
{
pDB->getSemId = pSS->getSemId;
semTake(pSS->getSemId, NO_WAIT);
}
/* Perform the CA get operation with a callback routine specified */
status = ca_array_get_callback(
pDB->get_type, /* db request type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_callback_handler, /* callback handler */
pDB); /* user arg */
if ( (pSP->options & OPT_ASYNC) || (status != ECA_NORMAL) )
return status;
/* Synchronous pvGet() */
ca_flush_io();
/* Wait for completion (10s timeout) */
sem_status = semTake(pSS->getSemId, 600);
if (sem_status == ERROR)
status = ECA_TIMEOUT;
return status;
}
/*
* seq_callback_handler() - Sequencer callback handler.
* Called when a "get" completes.
* args.usr points to the db structure (CHAN *) for tis channel.
*/
VOID seq_callback_handler(args)
struct event_handler_args args;
{
SPROG *pSP;
CHAN *pDB;
struct dbr_sts_char *dbr_sts_ptr;
int i, nbytes;
void *pVal;
/* User arg is ptr to db channel structure */
pDB = (CHAN *)args.usr;
/* Copy value returned into user variable */
pVal = getPtrToValue((union db_access_val *)args.dbr, pDB->get_type);
nbytes = pDB->size * pDB->count;
memcpy(pDB->var, pVal, nbytes);
/* Copy status & severity */
dbr_sts_ptr = (struct dbr_sts_char *)args.dbr;
pDB->status = dbr_sts_ptr->status;
pDB->severity = dbr_sts_ptr->severity;
/* Set get complete flag */
pDB->get_complete = TRUE;
/* Wake up each state set that is waiting for event processing) */
pSP = pDB->sprog; /* State program that owns this db entry */
seq_efSet(pSP, 0, pDB->index + 1);
/* If syncronous pvGet then notify pending state set */
if ( !(pSP->options & OPT_ASYNC) )
semGive(pDB->getSemId);
return;
}
/* Flush outstanding CA requests */
VOID seq_pvFlush()
{
ca_flush_io();
}
/*
* seq_pvPut() - Put DB value (uses channel access).
*/
seq_pvPut(pSP, pSS, pDB)
SPROG *pSP; /* ptr to state program */
SSCB *pSS; /* ptr to current state set */
CHAN *pDB; /* ptr to channel struct */
{
int status;
if (!pDB->connected)
return ECA_DISCONN;
status = ca_array_put(pDB->put_type, pDB->count,
pDB->chid, pDB->var);
if (status != ECA_NORMAL)
{
#ifdef DEBUG
seq_log(pSP, "pvPut on \"%s\" failed (%d)\n",
pDB->db_name, status);
seq_log(pSP, " put_type=%d\n", pDB->put_type);
seq_log(pSP, " size=%d, count=%d\n", pDB->size, pDB->count);
#endif /* DEBUG */
}
return status;
}
/*
* seq_pvMonitor() - Initiate a monitor on a channel.
*/
seq_pvMonitor(pSP, pSS, pDB)
SPROG *pSP; /* ptr to state program */
SSCB *pSS; /* ptr to current state set */
CHAN *pDB; /* ptr to channel struct */
{
int status;
extern VOID seq_event_handler();
#ifdef DEBUG
printf("monitor \"%s\"\n", pDB->db_name);
#endif /* DEBUG */
if (pDB->monitored)
return;
status = ca_add_array_event(
pDB->get_type, /* requested type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_event_handler, /* function to call */
pDB, /* user arg (db struct) */
pDB->delta, /* pos. delta value */
pDB->delta, /* neg. delta value */
pDB->timeout, /* timeout */
&pDB->evid); /* where to put event id */
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_add_array_event");
ca_task_exit(); /* this is serious */
return;
}
ca_flush_io();
pDB->monitored = TRUE;
return;
}
/*
* seq_pvStopMonitor() - Cancel a monitor
*/
seq_pvStopMonitor(pSP, pSS, pDB)
SPROG *pSP; /* ptr to state program */
SSCB *pSS; /* ptr to current state set */
CHAN *pDB; /* ptr to channel struct */
{
int status;
if (!pDB->monitored)
return -1;
status = ca_clear_event(pDB->evid);
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_clear_event");
return status;
}
pDB->monitored = FALSE;
return status;
}
/*
* getPtr() - Given ptr to value structure & type, return ptr to value.
*/
LOCAL VOID *getPtrToValue(pBuf, dbrType)
union db_access_val *pBuf;
chtype dbrType;
{
switch (dbrType) {
case DBR_STRING: return (void *)pBuf->strval;
case DBR_STS_STRING: return (void *)pBuf->sstrval.value;
case DBR_SHORT: return (void *)&pBuf->shrtval;
case DBR_STS_SHORT: return (void *)&pBuf->sshrtval.value;
case DBR_FLOAT: return (void *)&pBuf->fltval;
case DBR_STS_FLOAT: return (void *)&pBuf->sfltval.value;
case DBR_ENUM: return (void *)&pBuf->enmval;
case DBR_STS_ENUM: return (void *)&pBuf->senmval.value;
case DBR_CHAR: return (void *)&pBuf->charval;
case DBR_STS_CHAR: return (void *)&pBuf->schrval.value;
case DBR_LONG: return (void *)&pBuf->longval;
case DBR_STS_LONG: return (void *)&pBuf->slngval.value;
case DBR_DOUBLE: return (void *)&pBuf->doubleval;
case DBR_STS_DOUBLE: return (void *)&pBuf->sdblval.value;
default: return NULL;
}
}
#include "memLib.h"
#include "taskVarLib.h"
#include "taskLib.h"
@@ -524,7 +336,7 @@ chtype dbrType;
* SEE ALSO: taskVarAdd(2), taskVarGet(2), taskVarSet(2)
*/
LOCAL STATUS taskVarDelete (tid, pVar)
LOCAL STATUS LtaskVarDelete (tid, pVar)
int tid; /* task id whose task variable is to be retrieved */
int *pVar; /* pointer to task variable to be removed from task */
@@ -571,7 +383,7 @@ int tid;
extern int ca_static;
int status;
status = taskVarDelete(tid, &ca_static);
status = LtaskVarDelete(tid, &ca_static);
if (status != OK)
{
logMsg("Seq: taskVarDelete failed for tid = 0x%x\n", tid);

616
src/sequencer/seq_if.c Normal file
View File

@@ -0,0 +1,616 @@
/*
seq_if.c,v 1.3 1995/10/10 01:56:49 wright Exp
* DESCRIPTION: Interface functions from state program to run-time sequencer.
* Note: To prevent global name conflicts "seq_" is added by the SNC, e.g.
* pvPut() becomes seq_pvPut().
*
* Author: Andy Kozubal
* Date: 1 March, 1994
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991-1994, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
* Modification Log:
* -----------------
*/
#define ANSI
#include "seq.h"
/* See seqCom.h for function prototypes (ANSI standard) */
/*#define DEBUG*/
/* The following "pv" functions are included here:
seq_pvGet()
seq_pvGetComplete()
seq_pvPut()
seq_pvFlush()
seq_pvConnect()
seq_pvMonitor()
seq_pvStopMonitor()
seq_pvStatus()
seq_pvSeverity()
seq_pvConnected()
seq_pvAssigned()
seq_pvChannelCount()
seq_pvAssignCount()
seq_pvConnectCount()
seq_pvCount()
seq_pvIndex()
seq_pvTimeStamp()
*/
/* Flush outstanding CA requests */
void seq_pvFlush()
{
ca_flush_io();
}
/*
* seq_pvGet() - Get DB value (uses channel access).
*/
seq_pvGet(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
SSCB *pSS;
CHAN *pDB; /* ptr to channel struct */
int status, sem_status;
extern VOID seq_callback_handler();
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
pDB = pSP->pChan + pvId;
/* Check for channel connected */
if (!pDB->connected)
return ECA_DISCONN;
/* Flag this pvGet() as not completed */
pDB->getComplete = FALSE;
/* If synchronous pvGet then clear the pvGet pend semaphore */
if ( !(pSP->options & OPT_ASYNC) )
{
pDB->getSemId = pSS->getSemId;
semTake(pSS->getSemId, NO_WAIT);
}
/* Perform the CA get operation with a callback routine specified */
status = ca_array_get_callback(
pDB->getType, /* db request type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_callback_handler, /* callback handler */
pDB); /* user arg */
if ( (pSP->options & OPT_ASYNC) || (status != ECA_NORMAL) )
return status;
/* Synchronous pvGet() */
ca_flush_io();
/* Wait for completion (10s timeout) */
sem_status = semTake(pSS->getSemId, 600);
if (sem_status == ERROR)
status = ECA_TIMEOUT;
return status;
}
/*
* seq_pvGetComplete() - returns TRUE if the last get completed.
*/
seq_pvGetComplete(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan;
return pDB->getComplete;
}
/*
* seq_pvPut() - Put DB value.
*/
seq_pvPut(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
logMsg("seq_pvPut: pv name=%s, pVar=0x%x\n", pDB->dbName, pDB->pVar);
#endif DEBUG
if (!pDB->connected)
return ECA_DISCONN;
status = ca_array_put(pDB->putType, pDB->count,
pDB->chid, pDB->pVar);
#ifdef DEBUG
logMsg("seq_pvPut: status=%d\n", status);
if (status != ECA_NORMAL)
{
seq_log(pSP, "pvPut on \"%s\" failed (%d)\n",
pDB->dbName, status);
seq_log(pSP, " putType=%d\n", pDB->putType);
seq_log(pSP, " size=%d, count=%d\n", pDB->size, pDB->count);
}
#endif DEBUG
return status;
}
/*
* seq_pvAssign() - Assign/Connect to a channel.
* Assign to a zero-lth string ("") disconnects/de-assignes.
*/
seq_pvAssign(ssId, pvId, pvName)
SS_ID ssId;
int pvId;
char *pvName;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status, nchar;
extern VOID seq_conn_handler();
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
printf("Assign %s to \"%s\"\n", pDB->pVarName, pvName);
#endif DEBUG
if (pDB->assigned)
{ /* Disconnect this channel */
status = ca_clear_channel(pDB->chid);
if (status != ECA_NORMAL)
return status;
free(pDB->dbName);
pDB->assigned = FALSE;
pSP->assignCount -= 1;
}
if (pDB->connected)
{
pDB->connected = FALSE;
pSP->connCount -= 1;
}
pDB->monitored = FALSE;
nchar = strlen(pvName);
pDB->dbName = (char *)calloc(1, nchar + 1);
strcpy(pDB->dbName, pvName);
/* Connect */
if (nchar > 0)
{
pDB->assigned = TRUE;
pSP->assignCount += 1;
status = ca_build_and_connect(
pDB->dbName, /* DB channel name */
TYPENOTCONN, /* Don't get initial value */
0, /* get count (n/a) */
&(pDB->chid), /* ptr to chid */
0, /* ptr to value (n/a) */
seq_conn_handler, /* connection handler routine */
pDB); /* user ptr is CHAN structure */
if (status != ECA_NORMAL)
{
return status;
}
if (pDB->monFlag)
{
status = seq_pvMonitor(ssId, pvId);
if (status != ECA_NORMAL)
return status;
}
}
ca_flush_io();
return ECA_NORMAL;
}
/*
* seq_pvMonitor() - Initiate a monitor on a channel.
*/
seq_pvMonitor(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
extern VOID seq_event_handler();
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
printf("monitor \"%s\"\n", pDB->dbName);
#endif DEBUG
if (pDB->monitored || !pDB->assigned)
return ECA_NORMAL;
status = ca_add_array_event(
pDB->getType, /* requested type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_event_handler, /* function to call */
pDB, /* user arg (db struct) */
0.0, /* pos. delta value */
0.0, /* neg. delta value */
0.0, /* timeout */
&pDB->evid); /* where to put event id */
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_add_array_event");
ca_task_exit(); /* this is serious */
return status;
}
ca_flush_io();
pDB->monitored = TRUE;
return ECA_NORMAL;
}
/*
* seq_pvStopMonitor() - Cancel a monitor
*/
seq_pvStopMonitor(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
if (!pDB->monitored)
return -1;
status = ca_clear_event(pDB->evid);
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_clear_event");
return status;
}
pDB->monitored = FALSE;
return status;
}
/*
* seq_pvChannelCount() - returns total number of database channels.
*/
seq_pvChannelCount(ssId)
SS_ID ssId;
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->numChans;
}
/*
* seq_pvConnectCount() - returns number of database channels connected.
*/
seq_pvConnectCount(ssId)
SS_ID ssId;
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->connCount;
}
/*
* seq_pvAssignCount() - returns number of database channels assigned.
*/
seq_pvAssignCount(ssId)
SS_ID ssId;
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->assignCount;
}
/*
* seq_pvConnected() - returns TRUE if database channel is connected.
*/
seq_pvConnected(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB;
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->connected;
}
/*
* seq_pvAssigned() - returns TRUE if database channel is assigned.
*/
seq_pvAssigned(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB;
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->assigned;
}
/*
* seq_pvCount() - returns number elements in an array, which is the lesser of
* (1) the array size and (2) the element count returned by channel access.
*/
seq_pvCount(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->dbCount;
}
/*
* seq_pvStatus() - returns channel alarm status.
*/
seq_pvStatus(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->status;
}
/*
* seq_pvSeverity() - returns channel alarm severity.
*/
seq_pvSeverity(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->severity;
}
/*
* seq_pvIndex() - returns index of database variable.
*/
int seq_pvIndex(ssId, pvId)
SS_ID ssId;
int pvId;
{
return pvId; /* index is same as pvId */
}
/*
* seq_pvTimeStamp() - returns channel time stamp.
*/
TS_STAMP seq_pvTimeStamp(ssId, pvId)
SS_ID ssId;
int pvId;
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->timeStamp;
}
/*
* seq_efSet() - Set an event flag, then wake up each state
* set that might be waiting on that event flag.
*/
VOID seq_efSet(ssId, ev_flag)
SS_ID ssId;
int ev_flag; /* event flag */
{
SPROG *pSP;
SSCB *pSS;
int nss;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
#ifdef DEBUG
logMsg("seq_efSet: pSP=0x%x, pSS=0x%x, ev_flag=0x%x\n", pSP, pSS, ev_flag);
taskDelay(10);
#endif DEBUG
/* Set this bit (apply resource lock) */
semTake(pSP->caSemId, WAIT_FOREVER);
bitSet(pSP->pEvents, ev_flag);
/* Wake up state sets that are waiting for this event flag */
seqWakeup(pSP, ev_flag);
/* Unlock resource */
semGive(pSP->caSemId);
}
/*
* seq_efTest() - Test event flag against outstanding events.
*/
int seq_efTest(ssId, ev_flag)
SS_ID ssId;
int ev_flag; /* event flag */
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
#ifdef DEBUG
logMsg("seq_efTest: ev_flag=%d, event=0x%x, isSet=%d\n",
ev_flag, pSP->pEvents[0], isSet);
#endif DEBUG
return isSet;
}
/*
* seq_efClear() - Test event flag against outstanding events, then clear it.
*/
int seq_efClear(ssId, ev_flag)
SS_ID ssId;
int ev_flag; /* event flag */
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
bitClear(pSP->pEvents, ev_flag);
return isSet;
}
/*
* seq_efTestAndClear() - Test event flag against outstanding events, then clear it.
*/
int seq_efTestAndClear(ssId, ev_flag)
SS_ID ssId;
int ev_flag; /* event flag */
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
bitClear(pSP->pEvents, ev_flag);
return isSet;
}
/*
* seq_delay() - test for delay() time-out expired */
int seq_delay(ssId, delayId)
SS_ID ssId;
int delayId;
{
SSCB *pSS;
ULONG timeElapsed;
pSS = (SSCB *)ssId;
/* Calc. elapsed time since state was entered */
timeElapsed = tickGet() - pSS->timeEntered;
/* Check for delay timeout */
if (timeElapsed >= pSS->delay[delayId])
{
pSS->delayExpired[delayId] = TRUE; /* mark as expired */
return TRUE;
}
return FALSE;
}
/*
* seq_delayInit() - initialize delay time on entering a state.
*/
VOID seq_delayInit(ssId, delayId, delay)
SS_ID ssId;
int delayId;
float delay; /* delay in seconds */
{
SSCB *pSS;
int ndelay;
pSS = (SSCB *)ssId;
/* Convert delay time to tics & save */
pSS->delay[delayId] = delay * 60.0;
ndelay = delayId + 1;
if (ndelay > pSS->numDelays)
pSS->numDelays = ndelay;
}
/*
* seq_optGet: return the value of an option.
* FALSE means "-" and TRUE means "+".
*/
BOOL seq_optGet(ssId, opt)
SS_ID ssId;
char *opt; /* one of the snc options as a strign (e.g. "a") */
{
SPROG *pSP;
pSP = ((SSCB *)ssId)->sprog;
switch (opt[0])
{
case 'a': return ( (pSP->options & OPT_ASYNC) != 0);
case 'c': return ( (pSP->options & OPT_CONN) != 0);
case 'd': return ( (pSP->options & OPT_DEBUG) != 0);
case 'e': return ( (pSP->options & OPT_NEWEF) != 0);
case 'r': return ( (pSP->options & OPT_REENT) != 0);
case 'v': return ( (pSP->options & OPT_VXWORKS) != 0);
default: return FALSE;
}
}

View File

@@ -3,7 +3,9 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
seq_mac.c,v 1.2 1995/06/27 15:25:56 wright Exp
DESCRIPTION: Macro routines for Sequencer.
The macro table contains name & value pairs. These are both pointers
to strings.
@@ -11,77 +13,72 @@
ENVIRONMENT: VxWorks
HISTORY:
01mar94,ajk Added seq_macValueGet() as state program interface routine.
***************************************************************************/
#define ANSI
#include "seq.h"
#include <string.h>
LOCAL int macNameLth(char *);
LOCAL int seqMacParseName(char *);
LOCAL int seqMacParseValue(char *);
LOCAL char *skipBlanks(char *);
LOCAL MACRO *seqMacTblGet(char *, MACRO *);
LOCAL MACRO *seqMacTblGet(MACRO *, char *);
/*#define DEBUG*/
/*
*seqMacTblInit - initialize macro the table.
*/
seqMacTblInit(pMac)
MACRO *pMac;
{
int i;
for (i = 0 ; i < MAX_MACROS; i++, pMac++)
{
pMac->name = NULL;
pMac->value = NULL;
}
}
/*
*seqMacEval - substitute macro value into a string containing:
* ....{mac_name}....
*/
seqMacEval(pInStr, pOutStr, maxChar, macTbl)
VOID seqMacEval(pInStr, pOutStr, maxChar, pMac)
char *pInStr;
char *pOutStr;
int maxChar;
MACRO *macTbl;
MACRO *pMac;
{
char *pMacVal, *pTmp;
char name[50], *pValue, *pTmp;
int nameLth, valLth;
#ifdef DEBUG
printf("seqMacEval: InStr=%s\n", pInStr);
logMsg("seqMacEval: InStr=%s\n", pInStr);
taskDelay(30);
#endif
pTmp = pOutStr;
while (*pInStr != 0 && maxChar > 0)
{
if (*pInStr == '{')
{ /* Macro substitution */
{ /* Do macro substitution */
pInStr++; /* points to macro name */
nameLth = macNameLth(pInStr);
/* Copy the macro name */
nameLth = 0;
while (*pInStr != '}' && *pInStr != 0)
{
name[nameLth] = *pInStr++;
if (nameLth < (sizeof(name) - 1))
nameLth++;
}
name[nameLth] = 0;
if (*pInStr != 0)
pInStr++;
#ifdef DEBUG
printf("Name=%s[%d]\n", pInStr, nameLth);
logMsg("Macro name=%s\n", name);
taskDelay(30);
#endif
/* Find macro value from macro name */
pMacVal = seqMacValGet(pInStr, nameLth, macTbl);
if (pMacVal != NULL)
pValue = seqMacValGet(pMac, name);
if (pValue != NULL)
{ /* Substitute macro value */
valLth = strlen(pMacVal);
valLth = strlen(pValue);
if (valLth > maxChar)
valLth = maxChar;
#ifdef DEBUG
printf("Val=%s[%d]\n", pMacVal, valLth);
logMsg("Value=%s\n", pValue);
#endif
strncpy(pOutStr, pMacVal, valLth);
strncpy(pOutStr, pValue, valLth);
maxChar -= valLth;
pOutStr += valLth;
}
pInStr += nameLth;
if (*pInStr != 0)
pInStr++; /* skip '}' */
}
else
@@ -89,52 +86,58 @@ MACRO *macTbl;
*pOutStr++ = *pInStr++;
maxChar--;
}
*pOutStr = 0;
#ifdef DEBUG
printf("OutStr=%s\n", pTmp);
#endif
}
*pOutStr = 0;
#ifdef DEBUG
logMsg("OutStr=%s\n", pTmp);
taskDelay(30);
#endif
}
/*
* seqMacValGet - given macro name, return pointer to its value.
* seq_macValueGet - given macro name, return pointer to its value.
*/
char *seqMacValGet(macName, macNameLth, macTbl)
char *macName;
int macNameLth;
MACRO *macTbl;
char *seq_macValueGet(ssId, pName)
SS_ID ssId;
char *pName;
{
int i;
SPROG *pSP;
MACRO *pMac;
for (i = 0 ; i < MAX_MACROS; i++, macTbl++)
pSP = ((SSCB *)ssId)->sprog;
pMac = pSP->pMacros;
return seqMacValGet(pMac, pName);
}
/*
* seqMacValGet - internal routine to convert macro name to macro value.
*/
char *seqMacValGet(pMac, pName)
MACRO *pMac;
char *pName;
{
int i;
#ifdef DEBUG
logMsg("seqMacValGet: name=%s", pName);
#endif DEBUG
for (i = 0 ; i < MAX_MACROS; i++, pMac++)
{
if ((macTbl->name != NULL) &&
(strlen(macTbl->name) == macNameLth))
if (pMac->pName != NULL)
{
if (strncmp(macName, macTbl->name, macNameLth) == 0)
if (strcmp(pName, pMac->pName) == 0)
{
return macTbl->value;
#ifdef DEBUG
logMsg(", value=%s\n", pMac->pValue);
#endif DEBUG
return pMac->pValue;
}
}
}
#ifdef DEBUG
logMsg(", no value\n");
#endif DEBUG
return NULL;
}
/*
* macNameLth() - Return number of characters in a macro name */
LOCAL int macNameLth(pstr)
char *pstr;
{
int nchar;
nchar = 0;
while ( (*pstr != 0) && (*pstr != '}') )
{
pstr++;
nchar++;
}
return nchar;
}
/*
* seqMacParse - parse the macro definition string and build
* the macro table (name/value pairs). Returns number of macros parsed.
@@ -147,11 +150,11 @@ SPROG *pSP;
{
int nMac, nChar;
char *skipBlanks();
MACRO *macTbl; /* macro table */
MACRO *pMac; /* macro table */
MACRO *pMacTbl; /* macro tbl entry */
char *name, *value;
char *pName, *pValue;
macTbl = pSP->mac_ptr;
pMac = pSP->pMacros;
for ( ;; )
{
/* Skip blanks */
@@ -162,23 +165,24 @@ SPROG *pSP;
nChar = seqMacParseName(pMacStr);
if (nChar == 0)
break; /* finished or error */
name = seqAlloc(pSP, nChar+1);
if (name == NULL)
pName = (char *)calloc(nChar+1, 1);
if (pName == NULL)
break;
memcpy(name, pMacStr, nChar);
name[nChar] = 0;
bcopy(pMacStr, pName, nChar);
pName[nChar] = 0;
#ifdef DEBUG
printf("name=%s, nChar=%d\n", name, nChar);
logMsg("name=%s, nChar=%d\n", pName, nChar);
taskDelay(30);
#endif
pMacStr += nChar;
/* Find a slot in the table */
pMacTbl = seqMacTblGet(name, macTbl);
pMacTbl = seqMacTblGet(pMac, pName);
if (pMacTbl == NULL)
break; /* table is full */
if (pMacTbl->name == NULL)
if (pMacTbl->pName == NULL)
{ /* Empty slot, insert macro name */
pMacTbl->name = name;
pMacTbl->pName = pName;
}
/* Skip over blanks and equal sign or comma */
@@ -196,20 +200,26 @@ SPROG *pSP;
nChar = seqMacParseValue(pMacStr);
if (nChar == 0)
break;
value = seqAlloc(pSP, nChar+1);
if (value == NULL)
/* Remove previous value if it exists */
pValue = pMacTbl->pValue;
if (pValue != NULL)
free(pValue);
/* Copy value string into newly allocated space */
pValue = (char *)calloc(nChar+1, 1);
if (pValue == NULL)
break;
memcpy(value, pMacStr, nChar);
value[nChar] = 0;
pMacStr += nChar;
pMacTbl->pValue = pValue;
bcopy(pMacStr, pValue, nChar);
pValue[nChar] = 0;
#ifdef DEBUG
printf("value=%s, nChar=%d\n", value, nChar);
logMsg("value=%s, nChar=%d\n", pValue, nChar);
taskDelay(30);
#endif
/* Insert or replace macro value */
pMacTbl->value = value;
/* Skip blanks and comma */
/* Skip past last value and over blanks and comma */
pMacStr += nChar;
pMacStr = skipBlanks(pMacStr);
if (*pMacStr++ != ',')
break;
@@ -245,7 +255,8 @@ char *pStr;
/*
* seqMacParseValue() - Parse a macro value from the input string.
*/LOCAL int seqMacParseValue(pStr)
*/
LOCAL int seqMacParseValue(pStr)
char *pStr;
{
int nChar;
@@ -260,6 +271,7 @@ char *pStr;
return nChar;
}
/* skipBlanks() - skip blank characters */
LOCAL char *skipBlanks(pChar)
char *pChar;
{
@@ -272,21 +284,22 @@ char *pChar;
* seqMacTblGet - find a match for the specified name, otherwise
* return an empty slot in macro table.
*/
LOCAL MACRO *seqMacTblGet(name, macTbl)
char *name; /* macro name */
MACRO *macTbl;
LOCAL MACRO *seqMacTblGet(pMac, pName)
MACRO *pMac;
char *pName; /* macro name */
{
int i;
MACRO *pMacTbl;
#ifdef DEBUG
printf("seqMacTblGet: name=%s\n", name);
logMsg("seqMacTblGet: name=%s\n", pName);
taskDelay(30);
#endif
for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++)
for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++)
{
if (pMacTbl->name != NULL)
if (pMacTbl->pName != NULL)
{
if (strcmp(name, pMacTbl->name) == 0)
if (strcmp(pName, pMacTbl->pName) == 0)
{
return pMacTbl;
}
@@ -294,9 +307,9 @@ MACRO *macTbl;
}
/* Not found, find an empty slot */
for (i = 0, pMacTbl = macTbl; i < MAX_MACROS; i++, pMacTbl++)
for (i = 0, pMacTbl = pMac; i < MAX_MACROS; i++, pMacTbl++)
{
if (pMacTbl->name == NULL)
if (pMacTbl->pName == NULL)
{
return pMacTbl;
}

View File

@@ -1,9 +1,11 @@
/**************************************************************************
GTA PROJECT AT division
Copyright, 1990, 91, 92, 93, The Regents of the University of California.
Los Alamos National Laboratory
Copyright, 1990-1994, The Regents of the University of California
and the University of Chicago.
Los Alamos National Laboratory
seq_main.c,v 1.2 1995/06/27 15:25:58 wright Exp
$Id$
DESCRIPTION: Seq() initiates a sequence as a group of cooperating
tasks. An optional string parameter specifies the values for
macros. The channel access context and task are shared by all state
@@ -30,25 +32,41 @@
29apr92,ajk Now alocates private program structures, even when reentry option
is not specified. This avoids problems with seqAddTask().
29apr92,ajk Implemented mutual exclusion lock in seq_log().
16feb93,ajk Converted to single task for channel access, all state programs.
16feb93,ajk Converted to single channel access task for all state programs.
16feb93,ajk Removed VxWorks pre-v5 stuff.
17feb93,ajk Evaluation of channel names moved here from seq_ca.c.
19feb93,ajk Fixed time stamp format for seq_log().
16jun93,ajk Fixed taskSpawn() to have 15 args per vx5.1.
20jul93,ajk Replaced obsolete delete() with remove() per vx5.1 release notes.
20jul93,ajk Removed #define ANSI
15mar94,ajk Implemented i/f to snc through structures in seqCom.h.
15mar94,ajk Allowed assignment of array elements to db.
15mar94,ajk Rearranged code that builds program structures.
02may94,ajk Performed initialization when sequencer is evoked, even w/o
parameters.
***************************************************************************/
/*#define DEBUG 1*/
#include "seqCom.h"
#include "seq.h"
#ifdef DEBUG
#undef LOCAL
#define LOCAL
#endif DEBUG
/* ANSI functional prototypes for local routines */
LOCAL SPROG *alloc_task_area(SPROG *);
LOCAL VOID copy_sprog(SPROG *, SPROG *);
LOCAL VOID init_sprog(SPROG *);
LOCAL VOID init_sscb(SPROG *);
LOCAL SPROG *seqInitTables(struct seqProgram *);
LOCAL SPROG *alloc_task_area(struct seqProgram *);
LOCAL VOID init_sprog(struct seqProgram *, SPROG *);
LOCAL VOID init_sscb(struct seqProgram *, SPROG *);
LOCAL VOID init_chan(struct seqProgram *, SPROG *);
LOCAL VOID init_mac(SPROG *);
LOCAL VOID seq_logInit(SPROG *);
LOCAL VOID seqChanNameEval(SPROG *);
LOCAL int countStates(struct seqProgram *);
LOCAL int roundUp(int);
LOCAL VOID selectDBtype(char *, short *, short *, short *, short *);
#define SCRATCH_SIZE (MAX_MACROS*(MAX_STRING_SIZE+1)*12)
/* Globals */
@@ -68,41 +86,22 @@ int seqAuxTaskId = 0;
* Creates the initial state program task and returns its task id.
* Most initialization is performed here.
*/
int seq(pSP_orig, macro_def, stack_size)
SPROG *pSP_orig; /* ptr to original state program table */
char *macro_def; /* optional macro def'n string */
int stack_size; /* optional stack size (bytes) */
int seq(pSeqProg, macro_def, stack_size)
struct seqProgram *pSeqProg; /* state program info generated by snc */
char *macro_def; /* optional macro def'n string */
int stack_size; /* optional stack size (bytes) */
{
int tid;
extern sequencer(); /* Sequencer task entry point */
extern sprog_delete(); /* Task delete routine */
extern char *seqVersion;
SPROG *pSP, *alloc_task_area();
char *pname, *pvalue, *ptask_name;
SPROG *pSP;
char *pValue, *ptask_name;
extern seqAuxTask();
/* Print version & date of sequencer */
printf("%s\n", seqVersion);
/* Exit if no parameters specified */
if (pSP_orig == 0)
{
return 0;
}
/* Check for correct state program format */
if (pSP_orig->magic != MAGIC)
{ /* Oops */
logMsg("Illegal magic number in state program.\n");
logMsg(" - Possible mismatch between SNC & SEQ versions\n");
logMsg(" - Re-compile your program?\n");
return -1;
}
#ifdef DEBUG
print_sp_info(pSP_orig);
#endif /* DEBUG */
/* Spawn the sequencer auxillary task */
if (seqAuxTaskId == 0)
{
@@ -110,6 +109,9 @@ int stack_size; /* optional stack size (bytes) */
0,0,0,0,0,0,0,0,0,0);
while (seqAuxTaskId == 0)
taskDelay(5); /* wait for task to init. ch'l access */
#ifdef DEBUG
logMsg("task seqAux spawned, tid=0x%x\n", seqAuxTaskId);
#endif DEBUG
}
/* Specify a routine to run at task delete */
@@ -119,23 +121,26 @@ int stack_size; /* optional stack size (bytes) */
seqDeleteHookAdded = TRUE;
}
/* Allocate a contiguous space for all dynamic structures */
pSP = alloc_task_area(pSP_orig);
/* Exit if no parameters specified */
if (pSeqProg == 0)
{
return 0;
}
/* Make a private copy of original structures (but change pointers!) */
copy_sprog(pSP_orig, pSP);
/* Check for correct state program format */
if (pSeqProg->magic != MAGIC)
{ /* Oops */
logMsg("Illegal magic number in state program.\n");
logMsg(" - Possible mismatch between SNC & SEQ versions\n");
logMsg(" - Re-compile your program?\n");
return -1;
}
/* Initialize state program block */
init_sprog(pSP);
/* Initialize state set control blocks */
init_sscb(pSP);
/* Initialize the macro definition table */
seqMacTblInit(pSP->mac_ptr); /* Init macro table */
/* Initialize the sequencer tables */
pSP = seqInitTables(pSeqProg);
/* Parse the macro definitions from the "program" statement */
seqMacParse(pSP->params, pSP);
seqMacParse(pSeqProg->pParams, pSP);
/* Parse the macro definitions from the command line */
seqMacParse(macro_def, pSP);
@@ -149,183 +154,99 @@ int stack_size; /* optional stack size (bytes) */
/* Specify stack size */
if (stack_size == 0)
stack_size = SPAWN_STACK_SIZE;
pname = "stack";
pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr);
if (pvalue != NULL && strlen(pvalue) > 0)
pValue = seqMacValGet(pSP->pMacros, "stack");
if (pValue != NULL && strlen(pValue) > 0)
{
sscanf(pvalue, "%d", &stack_size);
sscanf(pValue, "%d", &stack_size);
}
if (stack_size < SPAWN_STACK_SIZE/2)
stack_size = SPAWN_STACK_SIZE/2;
/* Specify task name */
pname = "name";
pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr);
if (pvalue != NULL && strlen(pvalue) > 0)
ptask_name = pvalue;
pValue = seqMacValGet(pSP->pMacros, "name");
if (pValue != NULL && strlen(pValue) > 0)
ptask_name = pValue;
else
ptask_name = pSP->name;
ptask_name = pSP->pProgName;
/* Spawn the initial sequencer task */
#ifdef DEBUG
logMsg("Spawing task %s, stack_size=%d\n", ptask_name, stack_size);
#endif
tid = taskSpawn(ptask_name, SPAWN_PRIORITY, SPAWN_OPTIONS,
stack_size, sequencer, (int)pSP, stack_size, (int)ptask_name, 0,0,0,0,0,0,0);
seq_log(pSP, "Spawning state program \"%s\", task name = \"%s\"\n",
pSP->name, ptask_name);
pSP->pProgName, ptask_name);
seq_log(pSP, " Task id = %d = 0x%x\n", tid, tid);
/* Return task id to calling program */
return tid;
}
/*
* ALLOC_TASK_AREA
* Allocate a single block for all dynamic structures
* The pointer to the allocated area is saved for task delete hook routine.
*/
LOCAL SPROG *alloc_task_area(pSP_orig)
SPROG *pSP_orig; /* original state program structure */
/* seqInitTables - initialize sequencer tables */
LOCAL SPROG *seqInitTables(pSeqProg)
struct seqProgram *pSeqProg;
{
int size, nss, nstates, nchannels, user_size,
prog_size, ss_size, state_size, chan_size, mac_size, scr_size;
SPROG *pSP_new; /* ptr to new state program struct */
char *dyn_ptr, *dyn_ptr_start; /* ptr to allocated area */
SPROG *pSP;
nss = pSP_orig->nss;
nstates = pSP_orig->nstates;
nchannels = pSP_orig->nchan;
pSP = (SPROG *)calloc(1, sizeof (SPROG));
/* Calc. # of bytes to allocate for all structures */
prog_size = sizeof(SPROG);
ss_size = nss*sizeof(SSCB);
state_size = nstates*sizeof(STATE);
chan_size = nchannels*sizeof(CHAN);
user_size = pSP_orig->user_size;
mac_size = MAX_MACROS*sizeof(MACRO);
scr_size = SCRATCH_SIZE;
/* Initialize state program block */
init_sprog(pSeqProg, pSP);
/* Total # bytes to allocate */
size = prog_size + ss_size + state_size +
chan_size + user_size + mac_size + scr_size;
/* Initialize state set control blocks */
init_sscb(pSeqProg, pSP);
/* Alloc the dynamic task area */
dyn_ptr = dyn_ptr_start = (char *)calloc(size, 1);
/* Initialize database channel blocks */
init_chan(pSeqProg, pSP);
/* Initialize the macro table */
init_mac(pSP);
return pSP;
}
/* Count the total number of states in a state program */
LOCAL int countStates(pSeqProg)
struct seqProgram *pSeqProg;
{
struct seqSS *pSeqSS;
int nstates, nss;
nstates = 0;
for (nss = 0, pSeqSS = pSeqProg->pSS; nss < pSeqProg->numSS; nss++, pSeqSS++)
nstates += pSeqSS->numStates;
}
/*
* Copy data from seqCom.h structures into this task's dynamic structures as defined
* in seq.h.
*/
LOCAL VOID init_sprog(pSeqProg, pSP)
struct seqProgram *pSeqProg;
SPROG *pSP;
{
SSCB *pSS;
STATE *pState;
CHAN *pDB;
char *pVar;
int i, nWords;
/* Copy information for state program */
pSP->numSS = pSeqProg->numSS;
pSP->numChans = pSeqProg->numChans;
pSP->numEvents = pSeqProg->numEvents;
pSP->options = pSeqProg->options;
pSP->pProgName = pSeqProg->pProgName;
pSP->exitFunc = pSeqProg->exitFunc;
pSP->varSize = pSeqProg->varSize;
#ifdef DEBUG
printf("Allocate task area:\n");
printf(" nss=%d, nstates=%d, nchannels=%d\n", nss, nstates, nchannels);
printf(" prog_size=%d, ss_size=%d, state_size=%d\n",
prog_size, ss_size, state_size);
printf(" user_size=%d, mac_size=%d, scr_size=%d\n",
user_size, mac_size, scr_size);
printf(" size=%d=0x%x\n", size, size);
printf(" dyn_ptr=%d=0x%x\n", dyn_ptr, dyn_ptr);
#endif /* DEBUG */
logMsg("init_sprog: num SS=%d, num Chans=%d, num Events=%d, Prog Name=%s, var Size=%d\n",
pSP->numSS, pSP->numChans, pSP->numEvents, pSP->pProgName, pSP->varSize);
#endif DEBUG
/* Set ptrs in the PROG structure */
pSP_new = (SPROG *)dyn_ptr;
/* Copy the SPROG struct contents */
*pSP_new = *pSP_orig;
/* Allocate space for copies of the original structures */
dyn_ptr += prog_size;
pSP_new->sscb = (SSCB *)dyn_ptr;
dyn_ptr += ss_size;
pSP_new->states = (STATE *)dyn_ptr;
dyn_ptr += state_size;
pSP_new->channels = (CHAN *)dyn_ptr;
dyn_ptr += chan_size;
if (user_size != 0)
{
pSP_new->user_area = (char *)dyn_ptr;
dyn_ptr += user_size;
}
else
pSP_new->user_area = NULL;
/* Create additional dynamic structures for macros and scratch area */
pSP_new->mac_ptr = (MACRO *)dyn_ptr;
dyn_ptr += mac_size;
pSP_new->scr_ptr = (char *)dyn_ptr;
pSP_new->scr_nleft = scr_size;
/* Save ptr to start of allocated area so we can free it at task delete */
pSP_new->dyn_ptr = dyn_ptr_start;
return pSP_new;
}
/*
* Copy the SSCB, STATE, and CHAN structures into this task's dynamic structures.
* Note: we have to change some pointers in the SPROG struct, user variables,
* and all SSCB structs.
*/
LOCAL VOID copy_sprog(pSP_orig, pSP)
SPROG *pSP_orig; /* original ptr to program struct */
SPROG *pSP; /* new ptr */
{
SSCB *pSS, *pSS_orig;
STATE *pST, *pST_orig;
CHAN *pDB, *pDB_orig;
int nss, nstates, nchan;
char *var_ptr;
/* Ptr to 1-st SSCB in original SPROG */
pSS_orig = pSP_orig->sscb;
/* Ptr to 1-st SSCB in new SPROG */
pSS = pSP->sscb;
/* Copy structures for each state set */
for (nss = 0, pST = pSP->states; nss < pSP->nss; nss++)
{
*pSS = *pSS_orig; /* copy SSCB */
pSS->states = pST; /* new ptr to 1-st STATE */
pST_orig = pSS_orig->states;
for (nstates = 0; nstates < pSS->num_states; nstates++)
{
*pST = *pST_orig; /* copy STATE struct */
pST++;
pST_orig++;
}
pSS++;
pSS_orig++;
}
/* Copy database channel structures */
pDB = pSP->channels;
pDB_orig = pSP_orig->channels;
var_ptr = pSP->user_area;
for (nchan = 0; nchan < pSP->nchan; nchan++)
{
*pDB = *pDB_orig;
/* Reset ptr to SPROG structure */
pDB->sprog = pSP;
/* +r: Convert offset to address of the user variable.
* -r: var_ptr is an absolute address.
*/
if (pSP->options & OPT_REENT)
pDB->var += (int)var_ptr;
pDB++;
pDB_orig++;
}
/* Note: user area is not copied; it should be all zeros */
return;
}
/*
* Initialize the state program block
*/
LOCAL VOID init_sprog(pSP)
SPROG *pSP;
{
int i;
/* Semaphore for resource locking on CA events */
/* Create a semaphore for resource locking on CA events */
pSP->caSemId = semBCreate(SEM_Q_FIFO, SEM_FULL);
if (pSP->caSemId == NULL)
{
@@ -334,26 +255,54 @@ SPROG *pSP;
}
pSP->task_is_deleted = FALSE;
pSP->connCount = 0;
pSP->assignCount = 0;
pSP->logFd = 0;
/* Clear all event flags */
for (i = 0; i < NWRDS; i++)
pSP->events[i] = 0;
/* Allocate an array for event flag bits */
nWords = (pSP->numEvents + NBITS - 1) / NBITS;
if (nWords == 0)
nWords = 1;
pSP->pEvents = (bitMask *)calloc(nWords, sizeof(bitMask));
for (i = 0; i < nWords; i++)
pSP->pEvents[i] = 0;
return;
}
/*
* Initialize the state set control blocks
*/
LOCAL VOID init_sscb(pSP)
SPROG *pSP;
LOCAL VOID init_sscb(pSeqProg, pSP)
struct seqProgram *pSeqProg;
SPROG *pSP;
{
SSCB *pSS;
int nss, i;
SSCB *pSS;
STATE *pState;
int nss, i, nstates;
struct seqSS *pSeqSS;
struct seqState *pSeqState;
for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++)
/* Allocate space for the SSCB structures */
pSP->pSS = pSS = (SSCB *)calloc(pSeqProg->numSS, sizeof(SSCB));
/* Copy information for each state set and state */
pSeqSS = pSeqProg->pSS;
for (nss = 0; nss < pSeqProg->numSS; nss++, pSS++, pSeqSS++)
{
pSS->task_id = 0;
/* Fill in SSCB */
pSS->pSSName = pSeqSS->pSSName;
pSS->numStates = pSeqSS->numStates;
pSS->errorState = pSeqSS->errorState;
pSS->currentState = 0; /* initial state */
pSS->nextState = 0;
pSS->prevState = 0;
pSS->taskId = 0;
pSS->sprog = pSP;
#ifdef DEBUG
logMsg("init_sscb: SS Name=%s, num States=%d, pSS=0x%x\n",
pSS->pSSName, pSS->numStates, pSS);
#endif DEBUG
/* Create a binary semaphore for synchronizing events in a SS */
pSS->syncSemId = semBCreate(SEM_Q_FIFO, SEM_FULL);
if (pSS->syncSemId == NULL)
@@ -375,12 +324,100 @@ SPROG *pSP;
}
pSS->current_state = 0; /* initial state */
pSS->next_state = 0;
pSS->action_complete = TRUE;
/* Allocate & fill in state blocks */
pSS->pStates = pState = (STATE *)calloc(pSS->numStates, sizeof(STATE));
pSeqState = pSeqSS->pStates;
for (nstates = 0; nstates < pSeqSS->numStates;
nstates++, pState++, pSeqState++)
{
pState->pStateName = pSeqState->pStateName;
pState->actionFunc = pSeqState->actionFunc;
pState->eventFunc = pSeqState->eventFunc;
pState->delayFunc = pSeqState->delayFunc;
pState->pEventMask = pSeqState->pEventMask;
#ifdef DEBUG
logMsg("init_sscb: State Name=%s, Event Mask=0x%x\n",
pState->pStateName, *pState->pEventMask);
#endif DEBUG
}
}
#ifdef DEBUG
logMsg("init_sscb: numSS=%d\n", pSP->numSS);
#endif DEBUG
return;
}
/*
* init_chan--Build the database channel structures.
* Note: Actual PV name is not filled in here. */
LOCAL VOID init_chan(pSeqProg, pSP)
struct seqProgram *pSeqProg;
SPROG *pSP;
{
int nchan;
CHAN *pDB;
struct seqChan *pSeqChan;
/* Allocate space for the CHAN structures */
pSP->pChan = (CHAN *)calloc(pSP->numChans, sizeof(CHAN));
pDB = pSP->pChan;
pSeqChan = pSeqProg->pChan;
for (nchan = 0; nchan < pSP->numChans; nchan++, pDB++, pSeqChan++)
{
#ifdef DEBUG
logMsg("init_chan: pDB=0x%x\n", pDB);
#endif DEBUG
pDB->sprog = pSP;
pDB->dbAsName = pSeqChan->dbAsName;
pDB->pVarName = pSeqChan->pVarName;
pDB->pVarType = pSeqChan->pVarType;
pDB->pVar = pSeqChan->pVar; /* this is an offset for +r option */
pDB->count = pSeqChan->count;
pDB->efId = pSeqChan->efId;
pDB->monFlag = pSeqChan->monFlag;
pDB->eventNum = pSeqChan->eventNum;
pDB->assigned = 0;
/* Fill in get/put database types, element size, & access offset */
selectDBtype(pSeqChan->pVarType, &pDB->getType,
&pDB->putType, &pDB->size, &pDB->dbOffset);
/* Reentrant option: Convert offset to address of the user variable. */
if (pSP->options & OPT_REENT)
pDB->pVar += (int)pSP->pVar;
#ifdef DEBUG
logMsg(" Assigned Name=%s, VarName=%s, VarType=%s, count=%d\n",
pDB->dbAsName, pDB->pVarName, pDB->pVarType, pDB->count);
logMsg(" size=%d, dbOffset=%d\n", pDB->size, pDB->dbOffset);
logMsg(" efId=%d, monFlag=%d, eventNum=%d\n",
pDB->efId, pDB->monFlag, pDB->eventNum);
#endif DEBUG
}
}
/*
* init_mac - initialize the macro table.
*/
LOCAL VOID init_mac(pSP)
SPROG *pSP;
{
int i;
MACRO *pMac;
pSP->pMacros = pMac = (MACRO *)calloc(MAX_MACROS, sizeof (MACRO));
#ifdef DEBUG
logMsg("init_mac: pMac=0x%x\n", pMac);
#endif
for (i = 0 ; i < MAX_MACROS; i++, pMac++)
{
pMac->pName = NULL;
pMac->pValue = NULL;
}
}
/*
* Evaluate channel names by macro substitution.
*/
@@ -391,36 +428,77 @@ SPROG *pSP;
CHAN *pDB;
int i;
pDB = pSP->channels;
for (i = 0; i < pSP->nchan; i++, pDB++)
pDB = pSP->pChan;
for (i = 0; i < pSP->numChans; i++, pDB++)
{
pDB->db_name = seqAlloc(pSP, MACRO_STR_LEN);
seqMacEval(pDB->db_uname, pDB->db_name, MACRO_STR_LEN, pSP->mac_ptr);
pDB->dbName = calloc(1, MACRO_STR_LEN);
seqMacEval(pDB->dbAsName, pDB->dbName, MACRO_STR_LEN, pSP->pMacros);
#ifdef DEBUG
logMsg("seqChanNameEval: \"%s\" evaluated to \"%s\"\n",
pDB->dbAsName, pDB->dbName);
#endif DEBUG
}
}
/*
* seqAlloc: Allocate memory from the program scratch area.
* Always round up to even no. bytes.
/*
* selectDBtype -- returns types for DB put/getm element size, and db access
* offset based on user variable type.
* Mapping is determined by the following typeMap[] array.
* DBR_TIME_* types for gets/monitors returns status and time stamp.
* Note that type "int" is mapped into DBR_LONG, because DBR_INT is actually
* 16 bits as defined in the database. This could cause future problems
* if the cpu architecture or compiler doesn't make this same assumption!
*/
char *seqAlloc(pSP, nChar)
SPROG *pSP;
int nChar;
{
char *pStr;
LOCAL struct typeMap {
char *pTypeStr;
short putType;
short getType;
short size;
short offset;
} typeMap[] = {
"char", DBR_CHAR, DBR_TIME_CHAR,
sizeof (char), OFFSET(struct dbr_time_char, value),
pStr = pSP->scr_ptr;
/* round to even no. bytes */
if ((nChar & 1) != 0)
nChar++;
if (pSP->scr_nleft >= nChar)
"short", DBR_SHORT, DBR_TIME_SHORT,
sizeof (short), OFFSET(struct dbr_time_short, value),
"int", DBR_LONG, DBR_TIME_LONG,
sizeof (long), OFFSET(struct dbr_time_long, value),
"long", DBR_LONG, DBR_TIME_LONG,
sizeof (long), OFFSET(struct dbr_time_long, value),
"float", DBR_FLOAT, DBR_TIME_FLOAT,
sizeof (float), OFFSET(struct dbr_time_float, value),
"double", DBR_DOUBLE, DBR_TIME_DOUBLE,
sizeof (double), OFFSET(struct dbr_time_double, value),
"string", DBR_STRING, DBR_TIME_STRING,
MAX_STRING_SIZE, OFFSET(struct dbr_time_string, value[0]),
0, 0, 0, 0, 0
};
LOCAL VOID selectDBtype(pUserType, pGetType, pPutType, pSize, pOffset)
char *pUserType;
short *pGetType, *pPutType, *pSize, *pOffset;
{
struct typeMap *pMap;
for (pMap = &typeMap[0]; *pMap->pTypeStr != 0; pMap++)
{
pSP->scr_ptr += nChar;
pSP->scr_nleft -= nChar;
return pStr;
if (strcmp(pUserType, pMap->pTypeStr) == 0)
{
*pGetType = pMap->getType;
*pPutType = pMap->putType;
*pSize = pMap->size;
*pOffset = pMap->offset;
return;
}
}
else
return NULL;
*pGetType = *pPutType = *pSize = *pOffset = 0; /* this shouldn't happen */
return;
}
/*
* seq_logInit() - Initialize logging.
@@ -429,7 +507,7 @@ int nChar;
LOCAL VOID seq_logInit(pSP)
SPROG *pSP;
{
char *pname, *pvalue;
char *pValue;
int fd;
/* Create a logging resource locking semaphore */
@@ -442,26 +520,25 @@ SPROG *pSP;
pSP->logFd = ioGlobalStdGet(1); /* default fd is std out */
/* Check for logfile spec. */
pname = "logfile";
pvalue = seqMacValGet(pname, strlen(pname), pSP->mac_ptr);
if (pvalue != NULL && strlen(pvalue) > 0)
pValue = seqMacValGet(pSP->pMacros, "logfile");
if (pValue != NULL && strlen(pValue) > 0)
{ /* Create & open a new log file for write only */
remove(pvalue); /* remove the file if it exists */
fd = open(pvalue, O_CREAT | O_WRONLY, 0664);
remove(pValue); /* remove the file if it exists */
fd = open(pValue, O_CREAT | O_WRONLY, 0664);
if (fd != ERROR)
pSP->logFd = fd;
printf("logfile=%s, fd=%d\n", pvalue, fd);
printf("logfile=%s, fd=%d\n", pValue, fd);
}
}
/*
* seq_log
* Log a message to the console or a file with time of day and task id.
* The format looks like "mytask 12/13/91 10:07:43: <user's message>".
* Log a message to the console or a file with task name, date, & time of day.
* The format looks like "mytask 12/13/93 10:07:43: Hello world!".
*/
#include "tsDefs.h"
#define LOG_BFR_SIZE 200
VOID seq_log(pSP, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
STATUS seq_log(pSP, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
SPROG *pSP;
char *fmt; /* format string */
int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
@@ -481,7 +558,7 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
/* Convert to text format: "mm/dd/yy hh:mm:ss.nano-sec" */
tsStampToText(&timeStamp, TS_TEXT_MMDDYY, pBfr);
/* We're going to truncate the ".nano-sec" part */
/* Truncate the ".nano-sec" part */
if (pBfr[2] == '/') /* valid t-s? */
pBfr += 17;
@@ -498,11 +575,13 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
fd = pSP->logFd;
count = pBfr - logBfr + 1;
status = write(fd, logBfr, count);
semGive(pSP->logSemId);
if (status != count)
{
logMsg("Log file error, fd=%d, error no.=%d\n", fd, errnoGet());
printErrno(errnoGet());
return;
return ERROR;
}
/* If this is an NSF file flush the buffer */
@@ -510,41 +589,19 @@ int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
{
ioctl(fd, FIOSYNC, 0);
}
semGive(pSP->logSemId);
return;
}
/*
* seqLog() - State program interface to seq_log().
* Does not require ptr to state program block.
*/
STATUS seqLog(fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8)
char *fmt; /* format string */
int arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
{
SPROG *pSP, *seqFindProg();
pSP = seqFindProg(taskIdSelf());
if (pSP == NULL)
return ERROR;
seq_log(pSP, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8);
return OK;
}
/*
* seq_optGet: return the value of an option.
* FALSE means "-" and TRUE means "+".
* seq_seqLog() - State program interface to seq_log().
* Does not require ptr to state program block.
*/
BOOL seq_optGet(pSP, opt)
SPROG *pSP;
char *opt; /* one of the snc options as a strign (e.g. "a") */
STATUS seq_seqLog(ssId, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8)
SS_ID ssId;
char *fmt; /* format string */
int arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8; /* arguments */
{
switch (opt[0])
{
case 'a': return ( (pSP->options & OPT_ASYNC) != 0);
case 'c': return ( (pSP->options & OPT_CONN) != 0);
case 'd': return ( (pSP->options & OPT_DEBUG) != 0);
case 'r': return ( (pSP->options & OPT_REENT) != 0);
case 'e': return ( (pSP->options & OPT_NEWEF) != 0);
default: return FALSE;
}
SPROG *pSP;
pSP = ((SSCB *)ssId)->sprog;
return seq_log(pSP, fmt, arg1,arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}

View File

@@ -2,8 +2,9 @@
GTA PROJECT AT division
Copyright, 1991, The Regents of the University of California.
Los Alamos National Laboratory
seq_prog.c,v 1.2 1995/06/27 15:26:00 wright Exp
$Id$
DESCRIPTION: Seq_prog.c: state program list management functions.
All active state programs are inserted into the list when created
and removed from the list when deleted.
@@ -15,37 +16,38 @@
29apr92,ajk Added mutual exclusion locks
17Jul92,rcz Changed semBCreate call for V5 vxWorks, maybe should be semMCreate ???
***************************************************************************/
#define DEBUG
/*#define DEBUG*/
#define ANSI
#include "seq.h"
#include "lstLib.h"
LOCAL SEM_ID seqProgListSemId;
LOCAL int seqProgListInited = FALSE;
LOCAL ELLLIST seqProgList;
LOCAL LIST seqProgList;
LOCAL VOID seqProgListInit();
typedef struct prog_node
{
ELLNODE node;
NODE node;
SPROG *pSP;
} PROG_NODE;
#define seqListFirst(pList) (PROG_NODE *)ellFirst((ELLLIST *)pList)
#define seqListFirst(pList) (PROG_NODE *)lstFirst((LIST *)pList)
#define seqListNext(pNode) (PROG_NODE *)ellNext((ELLNODE *)pNode)
#define seqListNext(pNode) (PROG_NODE *)lstNext((NODE *)pNode)
/*
* seqFindProg() - find a program in the state program list from task id.
*/
SPROG *seqFindProg(task_id)
int task_id;
SPROG *seqFindProg(taskId)
int taskId;
{
PROG_NODE *pNode;
SPROG *pSP;
SSCB *pSS;
int n;
if (!seqProgListInited || task_id == 0)
if (!seqProgListInited || taskId == 0)
return NULL;
semTake(seqProgListSemId, WAIT_FOREVER);
@@ -54,15 +56,15 @@ int task_id;
pNode = seqListNext(pNode) )
{
pSP = pNode->pSP;
if (pSP->task_id == task_id)
if (pSP->taskId == taskId)
{
semGive(seqProgListSemId);
return pSP;
}
pSS = pSP->sscb;
for (n = 0; n < pSP->nss; n++, pSS++)
pSS = pSP->pSS;
for (n = 0; n < pSP->numSS; n++, pSS++)
{
if (pSS->task_id == task_id)
if (pSS->taskId == taskId)
{
semGive(seqProgListSemId);
return pSP;
@@ -122,7 +124,7 @@ SPROG *pSP;
{
semGive(seqProgListSemId);
#ifdef DEBUG
printf("Task %d already in list\n", pSP->task_id);
printf("Task %d already in list\n", pSP->taskId);
#endif
return ERROR; /* already in list */
}
@@ -137,10 +139,10 @@ SPROG *pSP;
}
pNode->pSP = pSP;
ellAdd((ELLLIST *)&seqProgList, (ELLNODE *)pNode);
lstAdd((LIST *)&seqProgList, (NODE *)pNode);
semGive(seqProgListSemId);
#ifdef DEBUG
printf("Added task %d to list.\n", pSP->task_id);
printf("Added task %d to list.\n", pSP->taskId);
#endif
return OK;
@@ -164,11 +166,11 @@ SPROG *pSP;
{
if (pNode->pSP == pSP)
{
ellDelete((ELLLIST *)&seqProgList, (ELLNODE *)pNode);
lstDelete((LIST *)&seqProgList, (NODE *)pNode);
semGive(seqProgListSemId);
#ifdef DEBUG
printf("Deleted task %d from list.\n", pSP->task_id);
printf("Deleted task %d from list.\n", pSP->taskId);
#endif
return OK;
}
@@ -184,7 +186,7 @@ SPROG *pSP;
LOCAL VOID seqProgListInit()
{
/* Init linked list */
ellInit(&seqProgList);
lstInit(&seqProgList);
/* Create a semaphore for mutual exclusion */
seqProgListSemId = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);

View File

@@ -1,9 +1,9 @@
/**************************************************************************
GTA PROJECT AT division
Copyright, 1990, The Regents of the University of California.
Copyright, 1990-1994, The Regents of the University of California.
Los Alamos National Laboratory
seq_qry.c,v 1.2 1995/06/27 15:26:02 wright Exp
$Id$
DESCRIPTION: Task querry & debug routines for run-time sequencer:
seqShow - prints state set info.
seqChanShow - printf channel (pv) info.
@@ -21,17 +21,17 @@
29apr92,ajk Modified to interpret encoded options.
21may92,ajk Modified format for listing programs & tasks.
21feb93,ajk Some minor code cleanup.
01mar94,ajk Major changes to print more meaningful information.
***************************************************************************/
/* #define DEBUG 1 */
/*#define DEBUG 1*/
#include "seq.h"
int seqShow(int);
int seqChanShow(int);
LOCAL VOID wait_rtn();
LOCAL VOID printValue(void *, int, int, int);
LOCAL VOID printType(int);
int seqChanShow(int, char *);
LOCAL int wait_rtn();
LOCAL VOID printValue(char *, int, int);
LOCAL SPROG *seqQryFind(int);
LOCAL seqShowAll();
@@ -53,32 +53,27 @@ int tid;
/* convert (possible) name to task id */
if (tid != 0)
{
tid = taskIdFigure(tid);
if (tid == ERROR)
return 0;
}
pSP = seqQryFind(tid);
if (pSP == NULL)
return 0;
/* Print info about state program */
printf("State Program: \"%s\"\n", pSP->name);
printf(" Memory layout:\n");
printf("\tpSP=%d=0x%x\n", pSP, pSP);
printf("\tdyn_ptr=%d=0x%x\n", pSP->dyn_ptr, pSP->dyn_ptr);
printf("\tsscb=%d=0x%x\n", pSP->sscb, pSP->sscb);
printf("\tstates=%d=0x%x\n", pSP->states, pSP->states);
printf("\tuser_area=%d=0x%x\n", pSP->user_area, pSP->user_area);
printf("\tuser_size=%d=0x%x\n", pSP->user_size, pSP->user_size);
printf("\tmac_ptr=%d=0x%x\n", pSP->mac_ptr, pSP->mac_ptr);
printf("\tscr_ptr=%d=0x%x\n", pSP->scr_ptr, pSP->scr_ptr);
printf("\tscr_nleft=%d=0x%x\n\n", pSP->scr_nleft, pSP->scr_nleft);
printf(" initial task id=%d=0x%x\n", pSP->task_id, pSP->task_id);
printf(" task priority=%d\n", pSP->task_priority);
printf(" number of state sets=%d\n", pSP->nss);
printf(" number of channels=%d\n", pSP->nchan);
printf(" number of channels connected=%d\n", pSP->conn_count);
printf(" options: async=%d, debug=%d, reent=%d, conn=%d, newef=%d\n",
printf("State Program: \"%s\"\n", pSP->pProgName);
printf(" initial task id=%d=0x%x\n", pSP->taskId, pSP->taskId);
printf(" task priority=%d\n", pSP->taskPriority);
printf(" number of state sets=%d\n", pSP->numSS);
printf(" number of channels=%d\n", pSP->numChans);
printf(" number of channels assigned=%d\n", pSP->assignCount);
printf(" number of channels connected=%d\n", pSP->connCount);
printf(" options: async=%d, debug=%d, newef=%d, reent=%d, conn=%d\n",
((pSP->options & OPT_ASYNC) != 0), ((pSP->options & OPT_DEBUG) != 0),
((pSP->options & OPT_REENT) != 0), ((pSP->options & OPT_CONN) != 0),
((pSP->options & OPT_NEWEF) != 0) );
((pSP->options & OPT_NEWEF) != 0), ((pSP->options & OPT_REENT) != 0),
((pSP->options & OPT_CONN) != 0) );
printf(" log file fd=%d\n", pSP->logFd);
status = ioctl(pSP->logFd, FIOGETNAME, (int)file_name);
if (status != ERROR)
@@ -87,88 +82,129 @@ int tid;
printf("\n");
/* Print state set info */
for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++)
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
{
wait_rtn();
printf(" State Set: \"%s\"\n", pSS->pSSName);
printf(" State Set: \"%s\"\n", pSS->name);
printf(" task name=%s; ", taskName(pSS->taskId));
printf(" task name=%s; ", taskName(pSS->task_id));
printf(" task id=%d=0x%x\n", pSS->taskId, pSS->taskId);
printf(" id=%d=0x%x\n", pSS->task_id, pSS->task_id);
pST = pSS->pStates;
printf(" First state = \"%s\"\n", pST->pStateName);
pST = pSS->states;
printf(" First state = \"%s\"\n", pSS->states->name);
pST = pSS->pStates + pSS->currentState;
printf(" Current state = \"%s\"\n", pST->pStateName);
pST = pSS->states + pSS->current_state;
printf(" Current state = \"%s\"\n", pST->name);
pST = pSS->pStates + pSS->prevState;
printf(" Previous state = \"%s\"\n", pST->pStateName);
pST = pSS->states + pSS->prev_state;
printf(" Previous state = \"%s\"\n", pST->name);
time = pSS->time/60.0;
printf("\tTime state was entered = %.1f seconds)\n", time);
time = (tickGet() - pSS->time)/60.0;
time = (tickGet() - pSS->timeEntered)/60.0;
printf("\tElapsed time since state was entered = %.1f seconds)\n",
time);
printf("\tNumber delays queued=%d\n", pSS->ndelay);
for (n = 0; n < pSS->ndelay; n++)
#ifdef DEBUG
printf(" Queued time delays:\n");
for (n = 0; n < pSS->numDelays; n++)
{
time = pSS->timeout[n]/60.0;
printf("\t\ttimeout[%d] = %.1f seconds\n", n, time);
printf("\tdelay[%2d]=%d", n, pSS->delay[n]);
if (pSS->delayExpired[n])
printf(" - expired");
printf("\n");
}
#endif DEBUG
printf("\n");
}
return 0;
}
/*
* seqChanQry() - Querry the sequencer for channel information.
* seqChanShow() - Show channel information for a state program.
*/
int seqChanShow(tid)
int tid;
int seqChanShow(tid, pStr)
int tid; /* task id or name */
char *pStr; /* optional pattern matching string */
{
SPROG *pSP;
CHAN *pDB;
int nch;
int nch, n;
float time;
char tsBfr[50], connQual;
int match, showAll;
/* convert (possible) name to task id */
if (tid != 0)
{
tid = taskIdFigure(tid);
if (tid == ERROR)
return 0;
}
pSP = seqQryFind(tid);
if (tid == NULL)
return 0;
pDB = pSP->channels;
printf("State Program: \"%s\"\n", pSP->name);
printf("Number of channels=%d\n", pSP->nchan);
printf("State Program: \"%s\"\n", pSP->pProgName);
printf("Number of channels=%d\n", pSP->numChans);
for (nch = 0; nch < pSP->nchan; nch++, pDB++)
if (pStr != NULL)
{
printf("\nChannel name: \"%s\"\n", pDB->db_name);
printf(" Unexpanded name: \"%s\"\n", pDB->db_uname);
printf(" Variable=%d=0x%x\n", pDB->var, pDB->var);
printf(" Size=%d bytes\n", pDB->size);
printf(" Count=%d\n", pDB->count);
printType(pDB->put_type);
printValue((void *)pDB->var, pDB->size, pDB->count,
pDB->put_type);
printf(" DB get request type=%d\n", pDB->get_type);
printf(" DB put request type=%d\n", pDB->put_type);
printf(" monitor flag=%d\n", pDB->mon_flag);
connQual = pStr[0];
/* Check for channel connect qualifier */
if ((connQual == '+') || (connQual == '-'))
{
pStr += 1;
}
}
else
connQual = 0;
pDB = pSP->pChan;
for (nch = 0; nch < pSP->numChans; )
{
if (pStr != NULL)
{
/* Check for channel connect qualifier */
if (connQual == '+')
showAll = pDB->connected; /* TRUE if connected */
else if (connQual == '-')
showAll = !pDB->connected; /* TRUE if NOT connected */
else
showAll = TRUE; /* Always TRUE */
/* Check for pattern match if specified */
match = (pStr[0] == 0) || (strstr(pDB->dbName, pStr) != NULL);
if (!(match && showAll))
{
pDB += 1;
nch += 1;
continue; /* skip this channel */
}
}
printf("\n#%d of %d:\n", nch+1, pSP->numChans);
printf("Channel name: \"%s\"\n", pDB->dbName);
printf(" Unexpanded (assigned) name: \"%s\"\n", pDB->dbAsName);
printf(" Variable name: \"%s\"\n", pDB->pVarName);
printf(" address = %d = 0x%x\n", pDB->pVar, pDB->pVar);
printf(" type = %s\n", pDB->pVarType);
printf(" count = %d\n", pDB->count);
printValue(pDB->pVar, pDB->putType, pDB->count);
printf(" Monitor flag=%d\n", pDB->monFlag);
if (pDB->monitored)
printf(" Monitored\n");
printf(" Monitored\n");
else
printf(" Not monitored\n");
printf(" Not monitored\n");
if (pDB->assigned)
printf(" Assigned\n");
else
printf(" Not assigned\n");
if(pDB->connected)
printf(" Connected\n");
else
printf(" Not connected\n");
if(pDB->get_complete)
if(pDB->getComplete)
printf(" Last get completed\n");
else
printf(" Get not completed or no get issued\n");
@@ -176,118 +212,117 @@ int tid;
printf(" Status=%d\n", pDB->status);
printf(" Severity=%d\n", pDB->severity);
printf(" Delta=%g\n", pDB->delta);
printf(" Timeout=%g\n", pDB->timeout);
wait_rtn();
/* Print time stamp in text format: "mm/dd/yy hh:mm:ss.nano-sec" */
tsStampToText(&pDB->timeStamp, TS_TEXT_MMDDYY, tsBfr);
if (tsBfr[2] == '/') /* valid t-s? */
printf(" Time stamp = %s\n", tsBfr);
n = wait_rtn();
if (n == 0)
return 0;
nch += n;
if (nch < 0)
nch = 0;
pDB = pSP->pChan + nch;
}
return 0;
}
/* Read from console until a RETURN is detected */
LOCAL VOID wait_rtn()
LOCAL int wait_rtn()
{
char bfr;
printf("Hit RETURN to continue\n");
do {
read(STD_IN, &bfr, 1);
} while (bfr != '\n');
char bfr[10];
int i, n;
printf("Next? (+/- skip count)\n");
for (i = 0; i < 10; i++)
{
read(STD_IN, &bfr[i], 1);
if (bfr[i] == '\n')
break;
}
bfr[i] = 0;
if (bfr[0] == 'q')
return 0; /* quit */
n = atoi(bfr);
if (n == 0)
n = 1;
return n;
}
/* Special union to simplify printing values */
struct dbr_union {
union {
char c;
short s;
long l;
float f;
double d;
} u;
};
/* Print the current internal value of a database channel */
LOCAL VOID printValue(pvar, size, count, type)
void *pvar;
int size, count, type;
LOCAL VOID printValue(pVal, type, count)
char *pVal;
int count, type;
{
struct dbr_union *pv = pvar;
int i;
char *c;
short *s;
long *l;
float *f;
double *d;
if (count > 5)
count = 5;
printf(" Value =");
while (count-- > 0)
{
switch (type)
{
case DBR_STRING:
printf(" %s", pv->u.c);
break;
case DBR_CHAR:
printf(" %d", pv->u.c);
break;
case DBR_SHORT:
printf(" %d", pv->u.s);
break;
case DBR_LONG:
printf(" %d", pv->u.l);
break;
case DBR_FLOAT:
printf(" %g", pv->u.f);
break;
case DBR_DOUBLE:
printf(" %lg", pv->u.d);
break;
}
pv = (struct dbr_union *)((char *)pv + size);
}
printf("\n");
}
/* Print the data type of a channel */
LOCAL VOID printType(type)
int type;
{
char *type_str;
switch (type)
for (i = 0; i < count; i++)
{
switch (type)
{
case DBR_STRING:
type_str = "string";
c = (char *)pVal;
for (i = 0; i < count; i++, c += MAX_STRING_SIZE)
{
printf(" %s", c);
}
break;
case DBR_CHAR:
type_str = "char";
case DBR_CHAR:
c = (char *)pVal;
for (i = 0; i < count; i++, c++)
{
printf(" %d", *c);
}
break;
case DBR_SHORT:
type_str = "short";
s = (short *)pVal;
for (i = 0; i < count; i++, s++)
{
printf(" %d", *s);
}
break;
case DBR_LONG:
type_str = "long";
l = (long *)pVal;
for (i = 0; i < count; i++, l++)
{
printf(" %d", *l);
}
break;
case DBR_FLOAT:
type_str = "float";
f = (float *)pVal;
for (i = 0; i < count; i++, f++)
{
printf(" %g", *f);
}
break;
case DBR_DOUBLE:
type_str = "double";
break;
default:
type_str = "?";
d = (double *)pVal;
for (i = 0; i < count; i++, d++)
{
printf(" %g", *d);
}
break;
}
}
printf(" Type = %s\n", type_str);
printf("\n");
}
/* Find a state program associated with a given task id */
@@ -311,13 +346,6 @@ int tid;
return NULL;
}
/* Check for correct magic number */
if (pSP->magic != MAGIC)
{
printf("Sorry, wrong magic number\n");
return NULL;
}
return pSP;
}
@@ -334,15 +362,15 @@ SPROG *pSP;
if (seqProgCount++ == 0)
printf("Program Name Task ID Task Name SS Name\n\n");
progName = pSP->name;
for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++)
progName = pSP->pProgName;
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
{
if (pSS->task_id == 0)
if (pSS->taskId == 0)
ptaskName = "(no task)";
else
ptaskName = taskName(pSS->task_id);
ptaskName = taskName(pSS->taskId);
printf("%-16s %-10d %-16s %-16s\n",
progName, pSS->task_id, ptaskName, pSS->name );
progName, pSS->taskId, ptaskName, pSS->pSSName );
progName = "";
}
printf("\n");

View File

@@ -1,10 +1,11 @@
/**************************************************************************
GTA PROJECT AT division
Copyright, 1990, 1991, 1992
The Regents of the University of California
Copyright, 1990-1994
The Regents of the University of California and
the University of Chicago.
Los Alamos National Laboratory
seq_task.c,v 1.3 1995/10/19 16:30:18 wright Exp
$Id$
DESCRIPTION: Seq_tasks.c: Task creation and control for sequencer
state sets.
@@ -20,14 +21,21 @@
Some minor changes in the way semaphores are deleted.
18feb92,ajk Changed to allow sharing of single CA task by all state programs.
Added seqAuxTask() and removed ca_pend_event() from ss_entry().
9aug93,ajk Added calls to taskwdInsert() & taskwdRemove().
09aug93,ajk Added calls to taskwdInsert() & taskwdRemove().
24nov93,ajk Added support for assigning array elements to db channels.
24nov93,ajk Changed implementation of event bits to support unlimited channels
20may94,ajk Changed sprog_delete() to spawn a separate cleanup task.
19oct95,ajk/rmw Fixed bug which kept events from being cleared in old eventflag mode
***************************************************************************/
/*#define DEBUG*/
#define ANSI
#include "seqCom.h"
#include "seq.h"
#include <taskwd.h>
/* Function declarations */
LOCAL VOID ss_task_init(SPROG *, SSCB *);
LOCAL VOID seq_clearDelay(SSCB *);
LOCAL long seq_getTimeout(SSCB *);
#define TASK_NAME_SIZE 10
@@ -37,10 +45,10 @@ LOCAL long seq_getTimeout(SSCB *);
/*
* sequencer() - Sequencer main task entry point.
* */
sequencer(pSP, stack_size, ptask_name)
sequencer(pSP, stack_size, pTaskName)
SPROG *pSP; /* ptr to original (global) state program table */
int stack_size; /* stack size */
char *ptask_name; /* Parent task name */
char *pTaskName; /* Parent task name */
{
SSCB *pSS;
STATE *pST;
@@ -49,9 +57,9 @@ char *ptask_name; /* Parent task name */
extern VOID ss_entry();
extern int seqAuxTaskId;
pSP->task_id = taskIdSelf(); /* my task id */
pSS = pSP->sscb;
pSS->task_id = pSP->task_id;
pSP->taskId = taskIdSelf(); /* my task id */
pSS = pSP->pSS;
pSS->taskId = pSP->taskId;
/* Add the program to the state program list */
seqAddProg(pSP);
@@ -63,19 +71,19 @@ char *ptask_name; /* Parent task name */
seq_connect(pSP);
/* Additional state set task names are derived from the first ss */
if (strlen(ptask_name) > TASK_NAME_SIZE)
ptask_name[TASK_NAME_SIZE] = 0;
if (strlen(pTaskName) > TASK_NAME_SIZE)
pTaskName[TASK_NAME_SIZE] = 0;
/* Create each additional state set task */
for (nss = 1, pSS = pSP->sscb + 1; nss < pSP->nss; nss++, pSS++)
for (nss = 1, pSS = pSP->pSS + 1; nss < pSP->numSS; nss++, pSS++)
{
/* Form task name from program name + state set number */
sprintf(task_name, "%s_%d", ptask_name, nss);
sprintf(task_name, "%s_%d", pTaskName, nss);
/* Spawn the task */
task_id = taskSpawn(
task_name, /* task name */
SPAWN_PRIORITY+pSS->task_priority, /* priority */
SPAWN_PRIORITY+pSS->taskPriority, /* priority */
SPAWN_OPTIONS, /* task options */
stack_size, /* stack size */
(FUNCPTR)ss_entry, /* entry point */
@@ -85,7 +93,7 @@ char *ptask_name; /* Parent task name */
}
/* First state set jumps directly to entry point */
ss_entry(pSP, pSP->sscb);
ss_entry(pSP, pSP->pSS);
}
/*
* ss_entry() - Task entry point for all state sets.
@@ -100,6 +108,8 @@ SSCB *pSS;
long delay;
char *pVar;
LOCAL VOID seq_waitConnect();
int nWords;
SS_ID ssId;
/* Initialize all ss tasks */
ss_task_init(pSP, pSS);
@@ -109,29 +119,29 @@ SSCB *pSS;
seq_waitConnect(pSP, pSS);
/* Initilaize state set to enter the first state */
pST = pSS->states;
pSS->current_state = 0;
pST = pSS->pStates;
pSS->currentState = 0;
/* Use the event mask for this state */
pSS->pMask = (pST->eventMask);
pSS->pMask = (pST->pEventMask);
nWords = (pSP->numEvents + NBITS - 1) / NBITS;
/* Local ptr to user variables (for reentrant code only) */
pVar = pSP->user_area;
pVar = pSP->pVar;
/* State set id */
ssId = (SS_ID)pSS;
/*
* ============= Main loop ==============
*/
while (1)
{
pSS->time = tickGet(); /* record time we entered this state */
seq_clearDelay(pSS); /* Clear delay list */
pST->delayFunc(ssId, pVar); /* Set up new delay list */
/* Call delay function to set up delays */
pSS->ndelay = 0;
pST->delay_func(pSP, pSS, pVar);
/* Generate a phoney event.
* This guarantees that a when() is always executed at
* least once when a state is entered. */
/* Setting this semaphor here guarantees that a when() is always
* executed at least once when a state is first entered. */
semGive(pSS->syncSemId);
/*
@@ -139,7 +149,7 @@ SSCB *pSS;
*/
do {
/* Wake up on CA event, event flag, or expired time delay */
delay = seq_getTimeout(pSS);
delay = seq_getTimeout(pSS); /* min. delay from list */
if (delay > 0)
semTake(pSS->syncSemId, delay);
@@ -149,38 +159,43 @@ SSCB *pSS;
*/
semTake(pSP->caSemId, WAIT_FOREVER);
ev_trig = pST->event_func(pSP, pSS, pVar); /* check events */
ev_trig = pST->eventFunc(ssId, pVar,
&pSS->transNum, &pSS->nextState); /* check events */
if ( ev_trig && (pSP->options & OPT_NEWEF) == 0 )
/* Clear all event flags (old ef mode only) */
if ( ev_trig && ((pSP->options & OPT_NEWEF) == 0) )
{ /* Clear all event flags (old mode only) */
register int i;
for (i = 0; i < NWRDS; i++)
pSP->events[i] = pSP->events[i] & !pSS->pMask[i];
for (i = 0; i < nWords; i++)
pSP->pEvents[i] = pSP->pEvents[i] & !pSS->pMask[i];
}
semGive(pSP->caSemId);
} while (!ev_trig);
/*
* An event triggered:
* execute the action statements and enter the new state.
*/
/* Change event mask ptr for next state */
pStNext = pSS->states + pSS->next_state;
pSS->pMask = (pStNext->eventMask);
pStNext = pSS->pStates + pSS->nextState;
pSS->pMask = (pStNext->pEventMask);
/* Execute the action for this event */
pSS->action_complete = FALSE;
pST->action_func(pSP, pSS, pVar);
pST->actionFunc(ssId, pVar, pSS->transNum);
/* Flush any outstanding DB requests */
ca_flush_io();
/* Change to next state */
pSS->prev_state = pSS->current_state;
pSS->current_state = pSS->next_state;
pST = pSS->states + pSS->current_state;
pSS->action_complete = TRUE;
pSS->prevState = pSS->currentState;
pSS->currentState = pSS->nextState;
pST = pSS->pStates + pSS->currentState;
}
}
/* Initialize state-set tasks */
@@ -191,14 +206,14 @@ SSCB *pSS;
extern int seqAuxTaskId;
/* Get this task's id */
pSS->task_id = taskIdSelf();
pSS->taskId = taskIdSelf();
/* Import Channel Access context from the auxillary seq. task */
if (pSP->task_id != pSS->task_id)
if (pSP->taskId != pSS->taskId)
ca_import(seqAuxTaskId);
/* Register this task with the EPICS watchdog (no callback function) */
taskwdInsert(pSS->task_id, (VOIDFUNCPTR)0, (VOID *)0);
taskwdInsert(pSS->taskId, (VOIDFUNCPTR)0, (VOID *)0);
return;
}
@@ -212,94 +227,82 @@ SSCB *pSS;
long delay;
delay = 600; /* 10, 20, 30, 40, 40,... sec */
while (pSP->conn_count < pSP->nchan)
while (pSP->connCount < pSP->assignCount)
{
status = semTake(pSS->syncSemId, delay);
if ((status != OK) && (pSP-> task_id == pSS->task_id))
if ((status != OK) && (pSP-> taskId == pSS->taskId))
{
logMsg("%d of %d channels connected\n",
pSP->conn_count, pSP->nchan);
logMsg("%d of %d assigned channels have connected\n",
pSP->connCount, pSP->assignCount);
}
if (delay < 2400)
delay = delay + 600;
}
}
/*
* seq_clearDelay() - clear the time delay list.
*/
LOCAL VOID seq_clearDelay(pSS)
SSCB *pSS;
{
int ndelay;
pSS->timeEntered = tickGet(); /* record time we entered this state */
for (ndelay = 0; ndelay < MAX_NDELAY; ndelay++)
{
pSS->delay[ndelay] = 0;
pSS->delayExpired[ndelay] = FALSE;
}
pSS->numDelays = 0;
return;
}
/*
* seq_getTimeout() - return time-out for pending on events.
* Returns number of tics to next expected timeout of a delay() call.
* Returns MAX_DELAY if no delays pending */
LOCAL long seq_getTimeout(pSS)
SSCB *pSS;
SSCB *pSS;
{
int ndelay;
long timeout; /* expiration clock time (tics) */
long delay, delayMin; /* remaining & min. delay (tics) */
long delay, delayMin, delayN;
if (pSS->ndelay == 0)
if (pSS->numDelays == 0)
return MAX_DELAY;
delay = tickGet() - pSS->timeEntered; /* actual delay since state entered */
delayMin = MAX_DELAY; /* start with largest possible delay */
/* Find the minimum delay among all non-expired timeouts */
for (ndelay = 0; ndelay < pSS->ndelay; ndelay++)
for (ndelay = 0; ndelay < pSS->numDelays; ndelay++)
{
timeout = pSS->timeout[ndelay];
if (timeout == 0)
continue; /* already expired */
delay = timeout - tickGet(); /* convert timeout to remaining delay */
if (delay <= 0)
if (pSS->delayExpired[ndelay])
continue; /* skip if this delay entry already expired */
delayN = pSS->delay[ndelay];
if (delay >= delayN)
{ /* just expired */
delayMin = 0;
pSS->timeout[ndelay] = 0; /* mark as expired */
pSS->delayExpired[ndelay] = TRUE; /* mark as expired */
return 0;
}
else if (delay < delayMin)
else if (delayN < delayMin)
{
delayMin = delay; /* this is the min. delay so far */
delayMin = delayN; /* this is the min. delay so far */
}
}
delay = delayMin - delay;
if (delay < 0)
delay = 0;
return delayMin;
}
/* Set-up for delay() on entering a state. This routine is called
by the state program for each delay in the "when" statement */
VOID seq_start_delay(pSP, pSS, delay_id, delay)
SPROG *pSP;
SSCB *pSS;
int delay_id; /* delay id */
float delay;
{
int td_tics;
/* Note: the following 2 lines could be combined, but doing so produces
* the undefined symbol "Mund", which is not in VxWorks library */
td_tics = delay*60.0;
pSS->timeout[delay_id] = pSS->time + td_tics;
delay_id += 1;
if (delay_id > pSS->ndelay)
pSS->ndelay = delay_id;
return;
}
/* Test for time-out expired */
BOOL seq_test_delay(pSP, pSS, delay_id)
SPROG *pSP;
SSCB *pSS;
int delay_id;
{
if (pSS->timeout[delay_id] == 0)
return TRUE; /* previously expired t-o */
if (tickGet() >= pSS->timeout[delay_id])
{
pSS->timeout[delay_id] = 0; /* mark as expired */
return TRUE;
}
return FALSE;
return delay;
}
/*
* Delete all state set tasks and do general clean-up.
* General procedure is:
* General procedure is to spawn a task that does the following:
* 1. Suspend all state set tasks except self.
* 2. Call the user program's exit routine.
* 3. Disconnect all channels for this state program.
@@ -310,27 +313,46 @@ int delay_id;
*
* This task is run whenever ANY task in the system is deleted.
* Therefore, we have to check the task belongs to a state program.
* Note: We could do this without spawning a task, except for the condition
* when executed in the context of ExcTask. ExcTask is not spawned with
* floating point option, and fp is required to do the cleanup.
*/
sprog_delete(tid)
int tid;
int tid; /* task being deleted */
{
int nss, tid_ss;
SPROG *pSP, *seqFindProg();
SSCB *pSS;
SPROG *pSP;
extern int seq_cleanup();
SEM_ID cleanupSem;
pSP = seqFindProg(tid);
if (pSP == NULL)
return -1; /* not a state program task */
logMsg("Delete %s: pSP=%d=0x%x, tid=%d\n",
pSP->name, pSP, pSP, tid);
/* Create a semaphore for cleanup task */
cleanupSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
/* Is this a real sequencer task? */
if (pSP->magic != MAGIC)
{
logMsg(" Not main state program task\n");
return -1;
}
/* Spawn the cleanup task */
taskSpawn("seqCleanup", SPAWN_PRIORITY-1, VX_FP_TASK, 2000, seq_cleanup,
tid, (int)pSP, (int)cleanupSem, 0,0,0,0,0,0,0);
/* Wait for cleanup task completion */
semTake(cleanupSem, WAIT_FOREVER);
semDelete(cleanupSem);
return 0;
}
/* Cleanup task */
seq_cleanup(tid, pSP, cleanupSem)
int tid;
SPROG *pSP;
SEM_ID cleanupSem; /* indicate cleanup is finished */
{
int nss, tid_ss;
SSCB *pSS;
logMsg("Delete %s: pSP=%d=0x%x, tid=%d\n",
pSP->pProgName, pSP, pSP, tid);
/* Wait for log semaphore (in case a task is doing a write) */
semTake(pSP->logSemId, 600);
@@ -338,20 +360,20 @@ int tid;
/* Remove tasks' watchdog & suspend all state set tasks except self */
#ifdef DEBUG
logMsg(" Suspending state set tasks:\n");
#endif /*DEBUG */
pSS = pSP->sscb;
for (nss = 0; nss < pSP->nss; nss++, pSS++)
#endif DEBUG
pSS = pSP->pSS;
for (nss = 0; nss < pSP->numSS; nss++, pSS++)
{
tid_ss = pSS->task_id;
tid_ss = pSS->taskId;
/* Remove the task from EPICS watchdog */
taskwdRemove(tid_ss);
if ( (tid_ss != 0) && (tid != tid_ss) )
if (tid_ss != taskIdSelf() )
{
#ifdef DEBUG
logMsg(" suspend task: tid=%d\n", tid_ss);
#endif /*DEBUG */
#endif DEBUG
taskSuspend(tid_ss);
}
}
@@ -360,21 +382,21 @@ int tid;
semGive(pSP->logSemId);
/* Call user exit routine (only if task has run) */
if (pSP->sscb->task_id != 0)
if (pSP->pSS->taskId != 0)
{
#ifdef DEBUG
logMsg(" Call exit function\n");
#endif /*DEBUG */
pSP->exit_func(pSP, pSP->user_area);
#endif DEBUG
pSP->exitFunc( (SS_ID)pSP->pSS, pSP->pVar);
}
/* Disconnect all channels */
seq_disconnect(pSP);
/* Cancel the CA context for each state set task */
for (nss = 0, pSS = pSP->sscb; nss < pSP->nss; nss++, pSS++)
for (nss = 0, pSS = pSP->pSS; nss < pSP->numSS; nss++, pSS++)
{
ca_import_cancel(pSS->task_id);
ca_import_cancel(pSS->taskId);
}
/* Close the log file */
@@ -382,7 +404,7 @@ int tid;
{
#ifdef DEBUG
logMsg("Closing log fd=%d\n", pSP->logFd);
#endif /*DEBUG */
#endif DEBUG
close(pSP->logFd);
pSP->logFd = ioGlobalStdGet(1);
}
@@ -391,15 +413,15 @@ int tid;
seqDelProg(pSP);
/* Delete state set tasks (except self) & delete their semaphores */
pSS = pSP->sscb;
for (nss = 0; nss < pSP->nss; nss++, pSS++)
pSS = pSP->pSS;
for (nss = 0; nss < pSP->numSS; nss++, pSS++)
{
tid_ss = pSS->task_id;
tid_ss = pSS->taskId;
if ( (tid != tid_ss) && (tid_ss != 0) )
{
#ifdef DEBUG
logMsg(" delete ss task: tid=%d\n", tid_ss);
#endif /*DEBUG */
#endif DEBUG
taskDelete(tid_ss);
}
@@ -414,15 +436,58 @@ int tid;
semDelete(pSP->caSemId);
semDelete(pSP->logSemId);
/* Free the memory that was allocated for the task area */
#ifdef DEBUG
logMsg("free pSP->dyn_ptr=0x%x\n", pSP->dyn_ptr);
#endif /*DEBUG */
/* Free all allocated memory */
taskDelay(5);
free(pSP->dyn_ptr);
seqFree(pSP);
semGive(cleanupSem);
return 0;
}
/* seqFree()--free all allocated memory */
VOID seqFree(pSP)
SPROG *pSP;
{
SSCB *pSS;
CHAN *pDB;
MACRO *pMac;
int n;
/* Free macro table entries */
for (pMac = pSP->pMacros, n = 0; n < MAX_MACROS; pMac++, n++)
{
if (pMac->pName != NULL)
free(pMac->pName);
if (pMac->pValue != NULL)
free(pMac->pValue);
}
/* Free MACRO table */
free(pSP->pMacros);
/* Free channel names */
for (pDB = pSP->pChan, n = 0; n < pSP->numChans; pDB++, n++)
{
if (pDB->dbName != NULL)
free(pDB->dbName);
}
/* Free channel structures */
free(pSP->pChan);
/* Free STATE blocks */
pSS = pSP->pSS;
free(pSS->pStates);
/* Free event words */
free(pSP->pEvents);
/* Free SSCBs */
free(pSP->pSS);
/* Free SPROG */
free(pSP);
}
/*
* Sequencer auxillary task -- loops on ca_pend_event().

View File

@@ -3,11 +3,15 @@
GTA PROJECT AT division
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
snc.y,v 1.2 1995/06/27 15:26:07 wright Exp
ENVIRONMENT: UNIX
HISTORY:
20nov91,ajk Added new "option" statement.
08nov93,ajk Implemented additional declarations (see VC_CLASS in parse.h).
08nov93,ajk Implemented assignment of array elements to pv's.
02may93,ajk Removed "parameter" definition for functions, and added "%prec"
qualifications to some "expr" definitions.
31may94,ajk Changed method for handling global C code.
***************************************************************************/
/* SNC - State Notation Compiler.
* The general structure of a state program is:
@@ -31,13 +35,12 @@
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "parse.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif /* TRUE */
#endif TRUE
extern int line_num; /* input file line no. */
%}
@@ -74,10 +77,11 @@ extern int line_num; /* input file line no. */
%type <ival> type
%type <pchar> subscript binop asgnop unop
%type <pexpr> state_set_list state_set state_list state transition_list transition
%type <pexpr> parameter expr
%type <pexpr> expr compound_expr assign_list bracked_expr
%type <pexpr> statement stmt_list compound_stmt if_stmt else_stmt while_stmt
%type <pexpr> for_stmt
%type <pexpr> for_stmt escaped_c_list
/* precidence rules for expr evaluation */
%right EQUAL COMMA
%left OR AND
%left GT GE EQ NE LE LT
%left PLUS MINUS
@@ -112,33 +116,60 @@ defn_stmt /* individual definitions for SNL (preceeds state sets) */
| debug_stmt
| sync_stmt
| option_stmt
| C_STMT { defn_c_stmt($1); }
| defn_c_stmt
| pp_code
| error { snc_err("definitions/declarations"); }
;
assign_stmt /* 'assign <var name> to <db name>;' */
: ASSIGN NAME TO STRING SEMI_COLON { assign_stmt($2, $4); }
assign_stmt /* assign <var name> to <db name>; */
: ASSIGN NAME TO STRING SEMI_COLON { assign_single($2, $4); }
/* assign <var name>[<n>] to <db name>; */
| ASSIGN NAME subscript TO STRING SEMI_COLON { assign_subscr($2, $3, $5); }
/* assign <var name> to {<db name>, ... }; */
| ASSIGN NAME TO L_BRACKET assign_list R_BRACKET SEMI_COLON
{ assign_list($2, $5); }
;
assign_list /* {"<db name>", .... } */
: STRING { $$ = expression(E_STRING, $1, 0, 0); }
| assign_list COMMA STRING
{ $$ = link_expr($1, expression(E_STRING, $3, 0, 0)); }
;
monitor_stmt /* variable to be monitored; delta is optional */
: MONITOR NAME SEMI_COLON { monitor_stmt($2, "0"); }
| MONITOR NAME COMMA NUMBER SEMI_COLON { monitor_stmt($2, $4); }
: MONITOR NAME SEMI_COLON { monitor_stmt($2, NULL); }
| MONITOR NAME subscript SEMI_COLON { monitor_stmt($2, $3); }
;
subscript /* e.g. [10] */
: /* empty */ { $$ = 0; }
| L_SQ_BRACKET NUMBER R_SQ_BRACKET { $$ = $2; }
: L_SQ_BRACKET NUMBER R_SQ_BRACKET { $$ = $2; }
;
debug_stmt
: DEBUG_PRINT NUMBER SEMI_COLON { set_debug_print($2); }
;
decl_stmt /* variable declarations (e.g. float x[20];) */
: type NAME subscript SEMI_COLON { decl_stmt($1, $2, $3, (char *)0); }
| type NAME subscript EQUAL NUMBER SEMI_COLON { decl_stmt($1, $2, $3, $5); }
| type NAME subscript EQUAL STRING SEMI_COLON { decl_stmt($1, $2, $3, $5); }
decl_stmt /* variable declarations (e.g. float x[20];)
* decl_stmt(type, class, name, <1-st dim>, <2-nd dim>, value) */
: type NAME SEMI_COLON
{ decl_stmt($1, VC_SIMPLE, $2, NULL, NULL, NULL); }
| type NAME EQUAL NUMBER SEMI_COLON
{ decl_stmt($1, VC_SIMPLE, $2, NULL, NULL, $4 ); }
| type NAME subscript SEMI_COLON
{ decl_stmt($1, VC_ARRAY1, $2, $3, NULL, NULL); }
| type NAME subscript subscript SEMI_COLON
{ decl_stmt($1, VC_ARRAY2, $2, $3, $4, NULL); }
| type ASTERISK NAME SEMI_COLON
{ decl_stmt($1, VC_POINTER, $3, NULL, NULL, NULL); }
| type ASTERISK NAME subscript SEMI_COLON
{ decl_stmt($1, VC_ARRAYP, $3, $4, NULL, NULL); }
;
type /* types for variables defined in SNL */
@@ -153,8 +184,14 @@ type /* types for variables defined in SNL */
;
sync_stmt /* sync <variable> <event flag> */
: SYNC NAME TO NAME SEMI_COLON { sync_stmt($2, $4); }
| SYNC NAME NAME SEMI_COLON { sync_stmt($2, $3); /* archaic syntax */ }
: SYNC NAME TO NAME SEMI_COLON { sync_stmt($2, NULL, $4); }
| SYNC NAME NAME SEMI_COLON { sync_stmt($2, NULL, $3); }
| SYNC NAME subscript TO NAME SEMI_COLON { sync_stmt($2, $3, $5); }
| SYNC NAME subscript NAME SEMI_COLON { sync_stmt($2, $3, $4); }
;
defn_c_stmt /* escaped C in definitions */
: escaped_c_list { defn_c_stmt($1); }
;
option_stmt /* option +/-<option>; e.g. option +a; */
@@ -201,7 +238,8 @@ transition /* define a transition ("when" statment ) */
expr /* general expr: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */
/* Expr *expression(int type, char *value, Expr *left, Expr *right) */
: expr binop expr { $$ = expression(E_BINOP, $2, $1, $3); }
: compound_expr { $$ = $1; }
| expr binop expr %prec UOP { $$ = expression(E_BINOP, $2, $1, $3); }
| expr asgnop expr { $$ = expression(E_ASGNOP, $2, $1, $3); }
| unop expr %prec UOP { $$ = expression(E_UNOP, $1, $2, 0); }
| AUTO_INCR expr %prec UOP { $$ = expression(E_PRE, "++", $2, 0); }
@@ -211,12 +249,20 @@ expr /* general expr: e.g. (-b+2*a/(c+d)) != 0 || (func1(x,y) < 5.0) */
| NUMBER { $$ = expression(E_CONST, $1, 0, 0); }
| STRING { $$ = expression(E_STRING, $1, 0, 0); }
| NAME { $$ = expression(E_VAR, $1, 0, 0); }
| NAME L_PAREN parameter R_PAREN { $$ = expression(E_FUNC, $1, $3, 0); }
| EXIT L_PAREN parameter R_PAREN { $$ = expression(E_FUNC, "exit", $3, 0); }
| NAME L_PAREN expr R_PAREN { $$ = expression(E_FUNC, $1, $3, 0); }
| EXIT L_PAREN expr R_PAREN { $$ = expression(E_FUNC, "exit", $3, 0); }
| L_PAREN expr R_PAREN { $$ = expression(E_PAREN, "", $2, 0); }
| expr L_SQ_BRACKET expr R_SQ_BRACKET %prec SUBSCRIPT
{ $$ = expression(E_SUBSCR, "", $1, $3); }
| /* empty */ { $$ = expression(E_EMPTY, "", 0, 0); }
| expr bracked_expr %prec SUBSCRIPT { $$ = expression(E_SUBSCR, "", $1, $2); }
| /* empty */ { $$ = 0; }
;
compound_expr
: expr COMMA expr { $$ = link_expr($1, $3); }
| compound_expr COMMA expr { $$ = link_expr($1, $3); }
;
bracked_expr /* e.g. [k-1] */
: L_SQ_BRACKET expr R_SQ_BRACKET { $$ = $2; }
;
unop /* Unary operators */
@@ -246,7 +292,6 @@ binop /* Binary operators */
| BIT_AND { $$ = "&"; }
| COMPLEMENT { $$ = "^"; }
| MODULO { $$ = "%"; }
| COMMA { $$ = ","; }
| PERIOD { $$ = "."; } /* fudges structure elements */
| POINTER { $$ = "->"; } /* fudges ptr to structure elements */
;
@@ -265,12 +310,6 @@ asgnop /* Assignment operators */
| CMPL_EQUAL { $$ = "^="; }
;
parameter /* expr, expr, .... */
: expr { $$ = $1; }
| parameter COMMA expr { $$ = link_expr($1, $3); }
| /* empty */ { $$ = 0; }
;
compound_stmt /* compound statement e.g. { ...; ...; ...; } */
: L_BRACKET stmt_list R_BRACKET { $$ = expression(E_CMPND, "",$2, 0); }
| error { snc_err("action statements"); }
@@ -319,8 +358,21 @@ pp_code /* pre-processor code (e.g. # 1 "test.st") */
;
global_c
: C_STMT { global_c_stmt($1); }
: escaped_c_list { global_c_stmt($1); }
;
escaped_c_list
: C_STMT { $$ = expression(E_TEXT, "", $1, 0); }
| escaped_c_list C_STMT { $$ = link_expr($1, expression(E_TEXT, "", $2, 0)); }
;
%%
#include "snc_lex.c"
#include "snc_main.c"
#include "snc_lex.c"
static int yyparse (void);
/* yyparse() is static, so we create global access to it */
void Global_yyparse (void)
{
yyparse ();
}

View File

@@ -4,7 +4,7 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
snc_lex.l,v 1.2 1995/06/27 15:26:09 wright Exp
ENVIRONMENT: UNIX
HISTORY:
20nov91,ajk Added OPTION token.
@@ -12,6 +12,14 @@
17Jul92,rcz changed warn_flag to warn_opt
17Jul92,rcz Ported ajk version from lanl
04apr93,ajk Increased STR_BFR_SIZE from 30000 to 300000
19nov93,ajk Added definitions for octal and hex numbers.
19nov93,ajk Removed optional "-" from definition of FPNUM. This was
causing problems with statements like "k-1".
27man94,ajk Implemented dynamic allocation of strings, thus eliminating
huge string buffer.
31may94,ajk Changed handling of escaped C code.
17feb95,ajk Removed includes "parse.h" & "snc.h", because this module
now gets included in snc.y.
***************************************************************************/
/* Lexical analyzer for State Notation Compiler (snc).
*
@@ -22,10 +30,8 @@
* Comments are recognized as part of the syntax.
*/
/*
#include "parse.h"
#include "snc.h"
*/
#include "string.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
@@ -36,16 +42,14 @@
#else
#define RETURN(param) return(param);
#endif
#define STR_BFR_SIZE 300000
#define STR_BFR_SIZE 1000
extern int line_num, c_line_num; /* input line number */
extern int warn_opt; /* compiler warning flag */
char str_bfr[STR_BFR_SIZE]; /* holding place for strings */
char *str_next = str_bfr; /* current ptr to str_bfr */
char *c_str; /* Start of current string in str_bfr */
int nc;
extern int line_num, c_line_num; /* input line number */
extern int warn_opt; /* compiler warning flag */
char strBfr[STR_BFR_SIZE]; /* holding place for strings */
char *pStr; /* current ptr to strBfr */
double atof();
int one_line_c_code;
int one_line_c_code; /* TRUE for %%; FALSE for %{...}% */
%}
@@ -53,24 +57,25 @@ int one_line_c_code;
%Start SNL C_CODE COMMENT STR PP PP_STR
NAME [a-zA-Z][a-zA-Z0-9_]*
FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
FPNUM (([0-9]+)(\.[0-9]*)?)|(\.[0-9]+)
OCTAL 0[0-7]+
HEX 0x([0-9a-fA-F])+
%% /* Begin rules */
<C_CODE>. *str_next++ = yytext[0];
<C_CODE>. *pStr++ = yytext[0];
<C_CODE>\n {
*str_next++ = '\n';
*pStr++ = 0;
line_num++;
c_line_num = line_num;
yylval.pchar = strdup(strBfr);
pStr = strBfr;
if (one_line_c_code)
{
*str_next++ = 0;
yylval.pchar = c_str;
BEGIN SNL;
RETURN(C_STMT);
}
RETURN(C_STMT);
}
<C_CODE>"}%" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN SNL;
RETURN(C_STMT);
}
@@ -78,29 +83,26 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<COMMENT>"*/" BEGIN SNL;
<COMMENT>. ;
<STR>"\\\"" {
*str_next++ = yytext[0];
*str_next++ = yytext[1];
*pStr++ = yytext[0];
*pStr++ = yytext[1];
}
<STR>\" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN SNL;
RETURN(STRING);
}
<STR>. { *str_next++ = yytext[0]; }
<STR>\n { *str_next++ = '?';
<STR>. { *pStr++ = yytext[0]; }
<STR>\n { *pStr++ = '?';
if (warn_opt)
fprintf(stderr, "Warning: newline in string, line %d\n",
line_num);
line_num++;
}
<PP>{FPNUM} { nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
<PP>{FPNUM} { yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<PP>\" { c_str = str_next; BEGIN PP_STR; }
<PP>\" { pStr = strBfr; BEGIN PP_STR; }
<PP>\n {
BEGIN SNL;
RETURN(CR);
@@ -109,22 +111,22 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<PP>. {
}
<PP_STR>\" {
*str_next++ = 0;
yylval.pchar = c_str;
*pStr++ = 0;
yylval.pchar = strdup(strBfr);
BEGIN PP;
RETURN(STRING);
}
<PP_STR>. { *str_next++ = yytext[0]; }
<PP_STR>\n { *str_next++ = '?'; line_num++; }
<PP_STR>. { *pStr++ = yytext[0]; }
<PP_STR>\n { *pStr++ = '?'; line_num++; }
<SNL>\n { line_num++; }
<SNL>"%{" {
c_str = str_next;
pStr = strBfr;
one_line_c_code = FALSE;
c_line_num = line_num;
BEGIN C_CODE;
}
<SNL>"%%" {
c_str = str_next;
pStr = strBfr;
one_line_c_code = TRUE;
c_line_num = line_num;
BEGIN C_CODE;
@@ -134,7 +136,7 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
RETURN(PP_SYMBOL);
}
<SNL>"/*" BEGIN COMMENT;
<SNL>\" { c_str = str_next; BEGIN STR; }
<SNL>\" { pStr = strBfr; BEGIN STR; }
<SNL>"ss" RETURN(STATE_SET);
<SNL>"state" RETURN(STATE);
<SNL>"when" RETURN(WHEN);
@@ -167,10 +169,7 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
RETURN(NUMBER);
}
<SNL>{NAME} {
nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
yylval.pchar = strdup(yytext);
RETURN(NAME);
}
<SNL>"++" RETURN(AUTO_INCR);
@@ -217,11 +216,16 @@ FPNUM (\-?(([0-9]+)(\.[0-9]*)?)|(\.[0-9]+))
<SNL>"(" RETURN(L_PAREN);
<SNL>")" RETURN(R_PAREN);
<SNL>"," RETURN(COMMA);
<SNL>{HEX} {
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>{OCTAL} {
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>{FPNUM} {
nc = strlen(yytext);
memcpy(str_next, yytext, nc+1);
yylval.pchar = str_next;
str_next += nc+1;
yylval.pchar = strdup(yytext);
RETURN(NUMBER);
}
<SNL>[\t\ ]* /* no action */ ;

View File

@@ -3,7 +3,9 @@
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
snc_main.c,v 1.2 1995/06/27 15:26:11 wright Exp
DESCRIPTION: Main program and miscellaneous routines for
State Notation Compiler.
@@ -12,11 +14,17 @@
20nov91,ajk Removed call to init_snc().
20nov91,ajk Removed some debug stuff.
28apr92,ajk Implemented new event flag mode.
29oct93,ajk Added 'v' (vxWorks include) option.
17may94,ajk Changed setlinebuf() to setvbuf().
17may94,ajk Removed event flag option (-e).
17feb95,ajk Changed yyparse() to Global_yyparse(), because FLEX makes
yyparse() static.
02mar95,ajk Changed bcopy () to strcpy () in 2 places.
26jun95,ajk Due to popular demand, reinstated event flag (-e) option.
***************************************************************************/
extern char *sncVersion; /* snc version and date created */
#include <stdio.h>
#include <string.h>
#ifndef TRUE
#define TRUE 1
@@ -33,10 +41,11 @@ int c_line_num; /* line number for beginning of C code */
int async_opt = FALSE; /* do pvGet() asynchronously */
int conn_opt = TRUE; /* wait for all connections to complete */
int debug_opt = FALSE; /* run-time debug */
int newef_opt = TRUE; /* use new event flag mode */
int newef_opt = TRUE; /* new event flag mode */
int line_opt = TRUE; /* line numbering */
int reent_opt = FALSE; /* reentrant at run-time */
int warn_opt = TRUE; /* compiler warnings */
int vx_opt = TRUE; /* include vxWorks def's */
/*+************************************************************************
* NAME: main
@@ -62,7 +71,6 @@ int argc;
char *argv[];
{
FILE *infp, *outfp, *freopen();
extern char in_file[], out_file[];
/* Get command arguments */
get_args(argc, argv);
@@ -87,17 +95,13 @@ char *argv[];
src_file = in_file;
/* Use line buffered output */
setvbuf(stdout,NULL,_IOLBF,0);
setvbuf(stderr,NULL,_IOLBF,0);
/* setlinebuf() isn't ANSI-C or XPG2/3/4
setlinebuf(stdout);
setlinebuf(stderr);
*/
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
printf("/* %s: %s */\n\n", sncVersion, in_file);
/* Call the SNC parser */
yyparse();
Global_yyparse();
}
/*+************************************************************************
* NAME: get_args
@@ -129,10 +133,11 @@ char *argv[];
fprintf(stderr, " +a - do async. pvGet\n");
fprintf(stderr, " -c - don't wait for all connects\n");
fprintf(stderr, " +d - turn on debug run-time option\n");
fprintf(stderr, " -e - don't use new event flag mode\n");
fprintf(stderr, " -l - supress line numbering\n");
fprintf(stderr, " +r - make reentrant at run-time\n");
fprintf(stderr, " -w - supress compiler warnings\n");
fprintf(stderr, " -e - don't use new event flag mode\n");
fprintf(stderr, " -v - don't include VxWorks definitions\n");
fprintf(stderr, "example:\n snc +a -c vacuum.st\n");
exit(1);
}
@@ -151,7 +156,6 @@ get_options(s)
char *s;
{
int opt_val;
extern int debug_opt, line_opt, reent_opt, warn_opt, async_opt, newef_opt;
if (*s == '+')
opt_val = TRUE;
@@ -172,6 +176,10 @@ char *s;
debug_opt = opt_val;
break;
case 'e':
newef_opt = opt_val;
break;
case 'l':
line_opt = opt_val;
break;
@@ -184,8 +192,8 @@ char *s;
warn_opt = opt_val;
break;
case 'e':
newef_opt = opt_val;
case 'v':
vx_opt = opt_val;
break;
default:
@@ -194,17 +202,15 @@ char *s;
}
}
get_in_file(s)
get_in_file (s)
char *s;
{
extern char in_file[], out_file[];
int ls;
ls = strlen(s);
memcpy(in_file, s, ls);
in_file[ls] = 0;
memcpy(out_file, s, ls);
if ( strcmp(&in_file[ls-3], ".st") == 0 )
ls = strlen (s);
strcpy (in_file, s);
strcpy (out_file, s);
if ( strcmp (&in_file[ls-3], ".st") == 0 )
{
out_file[ls-2] = 'c';
out_file[ls-1] = 0;
@@ -260,9 +266,6 @@ char *err_txt;
yyerror(err)
char *err;
{
extern char *src_file;
extern int line_num;
fprintf(stderr, "%s: line no. %d (%s)\n", err, line_num, src_file);
return;
}
@@ -287,8 +290,6 @@ print_line_num(line_num, src_file)
int line_num;
char *src_file;
{
extern int line_opt;
if (line_opt)
printf("# line %d \"%s\"\n", line_num, src_file);
return;

View File

@@ -2,7 +2,7 @@ EPICS = ../../../..
include Target.include
include $(EPICS)/config/CONFIG_BASE
USR_LDLIBS = -lca -lCom -lm -s
USR_LDLIBS = -lca -lCom -lm
DEPLIBS = $(EPICS_BASE_LIB)/libca.a $(EPICS_BASE_LIB)/libCom.a
SRCS.c = \

View File

@@ -46,6 +46,10 @@
* .08 092292 joh improved message sent to the log
* .09 050494 pg HPUX port changes.
* .10 021694 joh ANSI C
* $Log$
* Revision 1.16 1995/11/08 23:48:26 jhill
* improvents for better client reconnect
*
*/
static char *pSCCSID = "@(#)iocLogServer.c 1.9\t05/05/94";
@@ -54,21 +58,27 @@ static char *pSCCSID = "@(#)iocLogServer.c 1.9\t05/05/94";
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netdb.h>
# ifdef SOLARIS
# include <sys/filio.h>
# endif
#include <bsdProto.h>
#include <envDefs.h>
#include <fdmgr.h>
static long ioc_log_port;
static unsigned short ioc_log_port;
static long ioc_log_file_limit;
static char ioc_log_file_name[64];
@@ -113,6 +123,7 @@ static int getConfig(void);
static int openLogFile(struct ioc_log_server *pserver);
static void handleLogFileError(void);
static void envFailureNotify(ENV_PARAM *pparam);
static void freeLogClient(struct iocLogClient *pclient);
/*
@@ -126,7 +137,7 @@ int main()
struct timeval timeout;
int status;
struct ioc_log_server *pserver;
int optval=1;
int optval;
status = getConfig();
if(status<0){
@@ -158,6 +169,7 @@ int main()
return ERROR;
}
optval = TRUE;
status = setsockopt( pserver->sock,
SOL_SOCKET,
SO_REUSEADDR,
@@ -179,8 +191,8 @@ int main()
sizeof (serverAddr) );
if (status<0) {
fprintf(stderr,
"ioc log server allready installed on port %ld?\n",
ioc_log_port);
"iocLogServer: a server is already installed on port %u?\n",
(unsigned)ioc_log_port);
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return ERROR;
}
@@ -192,6 +204,20 @@ int main()
return ERROR;
}
/*
* Set non blocking IO
* to prevent dead locks
*/
optval = TRUE;
status = ioctl(
pserver->sock,
FIONBIO,
&optval);
if(status<0){
fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
return ERROR;
}
status = openLogFile(pserver);
if(status<0){
fprintf(stderr,
@@ -201,10 +227,11 @@ int main()
return ERROR;
}
status = fdmgr_add_fd(
status = fdmgr_add_callback(
pserver->pfdctx,
pserver->sock,
acceptNewClient,
fdi_read,
acceptNewClient,
pserver);
if(status<0){
return ERROR;
@@ -268,7 +295,7 @@ static void acceptNewClient(void *pParam)
struct sockaddr_in addr;
char *pname;
int status;
int optval;
pclient = (struct iocLogClient *)
malloc(sizeof *pclient);
@@ -279,10 +306,28 @@ static void acceptNewClient(void *pParam)
pclient->insock = accept(pserver->sock, NULL, 0);
if(pclient->insock<0){
free(pclient);
fprintf(stderr, "Accept Error %d\n", errno);
if (errno!=EWOULDBLOCK) {
fprintf(stderr, "Accept Error %d\n", errno);
}
return;
}
/*
* Set non blocking IO
* to prevent dead locks
*/
optval = TRUE;
status = ioctl(
pclient->insock,
FIONBIO,
&optval);
if(status<0){
close(pclient->insock);
free(pclient);
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, strerror(errno));
return;
}
pclient->pserver = pserver;
pclient->need_prefix = TRUE;
pclient->ptopofstack = pclient->recvbuf;
@@ -313,6 +358,7 @@ static void acceptNewClient(void *pParam)
logTime(pclient);
#if 0
status = fprintf(
pclient->pserver->poutfile,
"%s %s ----- Client Connect -----\n",
@@ -321,6 +367,7 @@ static void acceptNewClient(void *pParam)
if(status<0){
handleLogFileError();
}
#endif
/*
* turn on KEEPALIVE so if the client crashes
@@ -340,11 +387,29 @@ static void acceptNewClient(void *pParam)
}
}
fdmgr_add_fd(
pserver->pfdctx,
pclient->insock,
readFromClient,
pclient);
# define SOCKET_SHUTDOWN_WRITE_SIDE 1
status = shutdown(pclient->insock, SOCKET_SHUTDOWN_WRITE_SIDE);
if(status<0){
close(pclient->insock);
free(pclient);
printf("%s:%d %s\n", __FILE__, __LINE__,
strerror(errno));
return;
}
status = fdmgr_add_callback(
pserver->pfdctx,
pclient->insock,
fdi_read,
readFromClient,
pclient);
if (status<0) {
close(pclient->insock);
free(pclient);
fprintf(stderr, "%s:%d client fdmgr_add_callback() failed\n",
__FILE__, __LINE__);
return;
}
}
@@ -362,66 +427,36 @@ static void readFromClient(void *pParam)
int length;
char *pcr;
char *pline;
unsigned stacksize;
int stacksize;
int size;
logTime(pclient);
stacksize = pclient->ptopofstack - pclient->recvbuf;
length = read(pclient->insock,
size = sizeof(pclient->recvbuf)-stacksize-1;
assert(size>0);
length = recv(pclient->insock,
pclient->ptopofstack,
sizeof(pclient->recvbuf)-stacksize-1);
size,
0);
if (length <= 0) {
# ifdef DEBUG
if(length == 0){
fprintf(stderr, "iocLogServer: nil message disconnect\n");
}
# endif
/*
* flush any leftovers
*/
if(stacksize){
status = fprintf(
pclient->pserver->poutfile,
"%s %s ",
pclient->name,
pclient->ascii_time);
if(status<0){
handleLogFileError();
}
status = fwrite(
pclient->recvbuf,
stacksize,
NITEMS,
pclient->pserver->poutfile);
if (status != NITEMS) {
handleLogFileError();
}
status = fprintf(pclient->pserver->poutfile,"\n");
if(status<0){
handleLogFileError();
if (length<0) {
if (errno != EWOULDBLOCK) {
fprintf(stderr,
"%s:%d socket=%d addr=%x size=%d read error=%s\n",
__FILE__, __LINE__, pclient->insock,
pclient->ptopofstack, size, strerror(errno));
freeLogClient(pclient);
}
return;
}
status = fprintf(
pclient->pserver->poutfile,
"%s %s ----- Client Disconnect -----\n",
pclient->name,
pclient->ascii_time);
if(status<0){
handleLogFileError();
else {
/*
* disconnect
*/
freeLogClient(pclient);
return;
}
fdmgr_clear_fd(
pclient->pserver->pfdctx,
pclient->insock);
if(close(pclient->insock)<0)
abort();
free (pclient);
return;
}
pclient->ptopofstack[length] = NULL;
@@ -486,7 +521,76 @@ static void readFromClient(void *pParam)
}
}
/*
* freeLogClient ()
*/
static void freeLogClient(struct iocLogClient *pclient)
{
unsigned stacksize;
int status;
stacksize = pclient->ptopofstack - pclient->recvbuf;
# ifdef DEBUG
if(length == 0){
fprintf(stderr, "iocLogServer: nil message disconnect\n");
}
# endif
/*
* flush any left overs
*/
if(stacksize){
status = fprintf(
pclient->pserver->poutfile,
"%s %s ",
pclient->name,
pclient->ascii_time);
if(status<0){
handleLogFileError();
}
status = fwrite(
pclient->recvbuf,
stacksize,
NITEMS,
pclient->pserver->poutfile);
if (status != NITEMS) {
handleLogFileError();
}
status = fprintf(pclient->pserver->poutfile,"\n");
if(status<0){
handleLogFileError();
}
}
#if 0
status = fprintf(
pclient->pserver->poutfile,
"%s %s ----- Client Disconnect -----\n",
pclient->name,
pclient->ascii_time);
if(status<0){
handleLogFileError();
}
#endif
status = fdmgr_clear_callback(
pclient->pserver->pfdctx,
pclient->insock,
fdi_read);
if (status!=OK) {
fprintf(stderr, "%s:%d fdmgr_clear_callback() failed\n",
__FILE__, __LINE__);
}
if(close(pclient->insock)<0)
abort();
free (pclient);
return;
}
/*
@@ -524,21 +628,23 @@ static int getConfig(void)
{
int status;
char *pstring;
long param;
status = envGetLongConfigParam(
&EPICS_IOC_LOG_PORT,
&ioc_log_port);
if(status<0){
envFailureNotify(&EPICS_IOC_LOG_PORT);
return ERROR;
&param);
if(status>=0){
ioc_log_port = (unsigned short) param;
}
else {
ioc_log_port = 7004U;
}
status = envGetLongConfigParam(
&EPICS_IOC_LOG_FILE_LIMIT,
&ioc_log_file_limit);
if(status<0){
envFailureNotify(&EPICS_IOC_LOG_FILE_LIMIT);
return ERROR;
ioc_log_file_limit = 10000;
}
pstring = envGetConfigParam(