Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25a6340993 | ||
|
|
a3652fd54e | ||
|
|
107ae2cee8 | ||
|
|
deb5e9c973 | ||
|
|
196f2302a4 | ||
|
|
2a21b01b0e | ||
|
|
56465da07f | ||
|
|
ee9457970a | ||
|
|
89a3746869 | ||
|
|
5be8f4999d | ||
|
|
b278c803ce | ||
|
|
50b8361078 | ||
|
|
2a121a4276 | ||
|
|
7b03ab0182 | ||
|
|
73a224a6ce | ||
|
|
f4af420e22 | ||
|
|
b0177729b8 | ||
|
|
c7b5592846 | ||
|
|
2f5202a4e4 | ||
|
|
ecb106fb71 | ||
|
|
b637c15e18 | ||
|
|
d1102b06c0 | ||
|
|
2fb23fd27b | ||
|
|
752b7e257e | ||
|
|
025b13b977 | ||
|
|
4c2822dd2e | ||
|
|
9dcee4c068 | ||
|
|
9bf802557e | ||
|
|
2566ee1e26 | ||
|
|
5a16ba053b | ||
|
|
ad3e5a3272 | ||
|
|
17511136a1 | ||
|
|
ffa22f89bd | ||
|
|
2e7075bd31 | ||
|
|
278eaf84d7 | ||
|
|
d957aebbf4 | ||
|
|
5ac2a99686 | ||
|
|
b782f63a7d | ||
|
|
e62f7d0ae2 | ||
|
|
1ca96e0116 | ||
|
|
44d65d9477 | ||
|
|
dc3ba94fc8 | ||
|
|
41ad7ae2ab | ||
|
|
017c55f9d9 | ||
|
|
196d7538c3 | ||
|
|
5ace66b609 | ||
|
|
0be218bed4 |
72
README
72
README
@@ -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
34
README.Linux
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
133
src/ca/access.c
133
src/ca/access.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
103
src/ca/iocinf.c
103
src/ca/iocinf.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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!!
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -748,7 +748,7 @@ const struct in_addr *pnet_addr
|
||||
)
|
||||
{
|
||||
int v42;
|
||||
int port;
|
||||
unsigned short port;
|
||||
char rej[64];
|
||||
chid chan;
|
||||
int status;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
11
src/libCom/env/envSubr.c
vendored
11
src/libCom/env/envSubr.c
vendored
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
* routines in a backwards compatible way so that
|
||||
* we eliminate delete ambiguity (chance of the same
|
||||
* being reused).
|
||||
* $Log$
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
3163
src/rec/recScan.c
3163
src/rec/recScan.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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!!
|
||||
*
|
||||
|
||||
@@ -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=../../..
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
1.8.3
|
||||
1.9.0(3.12.1)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
#
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_?" };
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
616
src/sequencer/seq_if.c
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */ ;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = \
|
||||
|
||||
@@ -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;
|
||||
¶m);
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user