Compare commits
93 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 | ||
|
|
297f0b8c31 | ||
|
|
cc20412693 | ||
|
|
7021cd3589 | ||
|
|
b7acf453c2 | ||
|
|
c9abc2c82e | ||
|
|
a7484494c4 | ||
|
|
52cfbe92bf | ||
|
|
75f0fb2b0c | ||
|
|
ed36723d6c | ||
|
|
f7a5da9139 | ||
|
|
254c5b1620 | ||
|
|
c6aab85d79 | ||
|
|
d54724fce1 | ||
|
|
60c0acab3c | ||
|
|
69f33b9e23 | ||
|
|
9191863094 | ||
|
|
1beb157ab0 | ||
|
|
41ae285075 | ||
|
|
222063ac53 | ||
|
|
3342ca120f | ||
|
|
13b785e594 | ||
|
|
6931273fef | ||
|
|
8d52177933 | ||
|
|
b64fa8bd87 | ||
|
|
34ce2ab6ac | ||
|
|
43ef20b90c | ||
|
|
818bc0d475 | ||
|
|
ca2f9aff52 | ||
|
|
64a93df872 | ||
|
|
ecc03e9ad9 | ||
|
|
db1b46e5f9 | ||
|
|
d87295397e | ||
|
|
7277c336f7 | ||
|
|
30ad5b1149 | ||
|
|
c6bcd1a10b | ||
|
|
f3cf369071 | ||
|
|
adffe02a2d | ||
|
|
e635080cef | ||
|
|
be85da6a3a | ||
|
|
c16006f34d | ||
|
|
72491d8829 | ||
|
|
cb78c5adb8 | ||
|
|
1a2cd5953d | ||
|
|
5da79a5f56 | ||
|
|
9f2d9587f0 | ||
|
|
74e405969a |
45
COPYRIGHT_UniversityOfChicago
Normal file
45
COPYRIGHT_UniversityOfChicago
Normal file
@@ -0,0 +1,45 @@
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
THE FOLLOWING IS A NOTICE OF COPYRIGHT, AVAILABILITY OF THE CODE,
|
||||
AND DISCLAIMER WHICH MUST BE INCLUDED IN THE PROLOGUE OF THE CODE
|
||||
AND IN ALL SOURCE LISTINGS OF THE CODE.
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
Argonne National Laboratory (ANL), with facilities in the States of
|
||||
Illinois and Idaho, is owned by the United States Government, and
|
||||
operated by the University of Chicago under provision of a contract
|
||||
with the Department of Energy.
|
||||
|
||||
Portions of this material resulted from work developed under a U.S.
|
||||
Government contract and are subject to the following license: For
|
||||
a period of five years from March 30, 1993, the Government is
|
||||
granted for itself and others acting on its behalf a paid-up,
|
||||
nonexclusive, irrevocable worldwide license in this computer
|
||||
software to reproduce, prepare derivative works, and perform
|
||||
publicly and display publicly. With the approval of DOE, this
|
||||
period may be renewed for two additional five year periods.
|
||||
Following the expiration of this period or periods, the Government
|
||||
is granted for itself and others acting on its behalf, a paid-up,
|
||||
nonexclusive, irrevocable worldwide license in this computer
|
||||
software to reproduce, prepare derivative works, distribute copies
|
||||
to the public, perform publicly and display publicly, and to permit
|
||||
others to do so.
|
||||
|
||||
*****************************************************************
|
||||
DISCLAIMER
|
||||
*****************************************************************
|
||||
|
||||
NEITHER THE UNITED STATES GOVERNMENT NOR ANY AGENCY THEREOF, NOR
|
||||
THE UNIVERSITY OF CHICAGO, NOR ANY OF THEIR EMPLOYEES OR OFFICERS,
|
||||
MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
|
||||
LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
|
||||
USEFULNESS OF ANY INFORMATION, APPARATUS, PRODUCT, OR PROCESS
|
||||
DISCLOSED, OR REPRESENTS THAT ITS USE WOULD NOT INFRINGE PRIVATELY
|
||||
OWNED RIGHTS.
|
||||
|
||||
*****************************************************************
|
||||
LICENSING INQUIRIES MAY BE DIRECTED TO THE INDUSTRIAL TECHNOLOGY
|
||||
DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000).
|
||||
15
MakeRelease
15
MakeRelease
@@ -10,6 +10,13 @@
|
||||
# [-b] - For fully built release
|
||||
#
|
||||
# $Log$
|
||||
# Revision 1.2 1995/08/28 15:49:54 jba
|
||||
# Added startup directory to release tar file
|
||||
#
|
||||
# Revision 1.1 1995/08/17 20:14:56 jba
|
||||
# Added base/tools scripts functionality to base/Makefile, removed scripts
|
||||
# Moved base/tools/MakeRelease to base dir.
|
||||
#
|
||||
# Revision 1.14 1994/12/19 18:42:08 tang
|
||||
# Make the args length compatible for HP and SUN.
|
||||
#
|
||||
@@ -100,6 +107,14 @@ ls base/README* | xargs tar cvf ${RELS}.Tar
|
||||
|
||||
ls base/Makefile* > /tmp/make_release.out.$$;
|
||||
|
||||
ls base/*COPYRIGHT* >> /tmp/make_release.out.$$;
|
||||
|
||||
if [ -d startup ];
|
||||
then
|
||||
find startup -name CVS -prune -o ! -type d -print \
|
||||
>> /tmp/make_release.out.$$;
|
||||
fi
|
||||
|
||||
find config base/include base/man base/tools -name CVS -prune -o \
|
||||
! -type d -print >> /tmp/make_release.out.$$;
|
||||
|
||||
|
||||
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
|
||||
|
||||
10
SkeletonCOPYRIGHT_UniversityOfChicago
Normal file
10
SkeletonCOPYRIGHT_UniversityOfChicago
Normal file
@@ -0,0 +1,10 @@
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
153
src/ca/access.c
153
src/ca/access.c
@@ -1,3 +1,4 @@
|
||||
/* $Id$ */
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* L O S A L A M O S */
|
||||
@@ -98,6 +99,26 @@
|
||||
/************************************************************************/
|
||||
/*
|
||||
* $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
|
||||
*
|
||||
* Revision 1.76 1995/08/23 00:34:06 jhill
|
||||
* fixed vxWorks specific SPARC data alignment problem
|
||||
*
|
||||
* Revision 1.75 1995/08/22 00:15:19 jhill
|
||||
* Use 1.0/USEC_PER_SEC and not 1.0e-6
|
||||
* Check for S_db_Pending when calling dbPutNotify()
|
||||
*
|
||||
* Revision 1.74 1995/08/22 00:12:07 jhill
|
||||
* *** empty log message ***
|
||||
*
|
||||
@@ -309,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
|
||||
@@ -328,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,6 +587,8 @@ int ca_os_independent_init (void)
|
||||
ca_spawn_repeater();
|
||||
}
|
||||
|
||||
ca_static->ca_flush_pending = FALSE;
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
@@ -607,7 +631,7 @@ LOCAL void create_udp_fd()
|
||||
|
||||
status = taskSpawn(
|
||||
name,
|
||||
pri-1,
|
||||
pri+1,
|
||||
VX_FP_TASK,
|
||||
4096,
|
||||
(FUNCPTR)cac_recv_task,
|
||||
@@ -968,13 +992,14 @@ int epicsShareAPI ca_search_and_connect
|
||||
* also allocate enough for the channel name & paddr
|
||||
* block
|
||||
*/
|
||||
size = sizeof(*chix) + strcnt + sizeof(struct db_addr);
|
||||
size = CA_MESSAGE_ALIGN(sizeof(*chix) + strcnt) +
|
||||
sizeof(struct db_addr);
|
||||
*chixptr = chix = (chid) calloc(1,size);
|
||||
if (!chix){
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
chix->id.paddr = (struct db_addr *)
|
||||
(strcnt + (char *) (chix + 1));
|
||||
(CA_MESSAGE_ALIGN(sizeof(*chix)+strcnt) + (char *)chix);
|
||||
*chix->id.paddr = tmp_paddr;
|
||||
chix->puser = puser;
|
||||
chix->pConnFunc = conn_func;
|
||||
@@ -1963,7 +1988,7 @@ void (*pfunc)(struct access_rights_handler_args))
|
||||
/*
|
||||
* make certain that it runs at least once
|
||||
*/
|
||||
if(chan->state == cs_conn){
|
||||
if(chan->state == cs_conn && chan->pAccessRightsFunc){
|
||||
args.chid = chan;
|
||||
args.ar = chan->ar;
|
||||
(*chan->pAccessRightsFunc)(args);
|
||||
@@ -2522,6 +2547,8 @@ int epicsShareAPI ca_clear_channel (chid chix)
|
||||
chix->type = TYPENOTINUSE;
|
||||
old_chan_state = chix->state;
|
||||
chix->state = cs_closed;
|
||||
chix->pAccessRightsFunc = NULL;
|
||||
chix->pConnFunc = NULL;
|
||||
|
||||
/* the while is only so I can break to the lock exit */
|
||||
LOCK;
|
||||
@@ -2668,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;
|
||||
@@ -2692,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;
|
||||
}
|
||||
|
||||
@@ -2735,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;
|
||||
}
|
||||
@@ -2850,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,12 @@ 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()
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef VMS
|
||||
@@ -103,13 +109,13 @@ int doacctst(char *pname)
|
||||
chid chix4;
|
||||
struct dbr_gr_float *ptr = NULL;
|
||||
struct dbr_gr_float *pgrfloat = NULL;
|
||||
float *pfloat = NULL;
|
||||
double *pdouble = NULL;
|
||||
dbr_float_t *pfloat = NULL;
|
||||
dbr_double_t *pdouble = NULL;
|
||||
long status;
|
||||
long i, j;
|
||||
evid monix;
|
||||
char pstring[NUM][MAX_STRING_SIZE];
|
||||
|
||||
unsigned size;
|
||||
|
||||
SEVCHK(ca_task_initialize(), "Unable to initialize");
|
||||
|
||||
@@ -123,9 +129,9 @@ int doacctst(char *pname)
|
||||
{
|
||||
TS_STAMP end_time;
|
||||
TS_STAMP start_time;
|
||||
double delay;
|
||||
double request = 0.5;
|
||||
double accuracy;
|
||||
dbr_double_t delay;
|
||||
dbr_double_t request = 0.5;
|
||||
dbr_double_t accuracy;
|
||||
|
||||
tsLocalTime(&start_time);
|
||||
status = ca_pend_event(request);
|
||||
@@ -140,8 +146,8 @@ int doacctst(char *pname)
|
||||
assert (abs(accuracy) < 10.0);
|
||||
}
|
||||
|
||||
ptr = (struct dbr_gr_float *)
|
||||
malloc(dbr_size_n(DBR_GR_FLOAT, NUM));
|
||||
size = dbr_size_n(DBR_GR_FLOAT, NUM);
|
||||
ptr = (struct dbr_gr_float *) malloc(size);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
|
||||
@@ -264,9 +270,9 @@ int doacctst(char *pname)
|
||||
ca_read_access(chix1) &&
|
||||
ca_write_access(chix1)){
|
||||
|
||||
double incr;
|
||||
double epsil;
|
||||
double base;
|
||||
dbr_double_t incr;
|
||||
dbr_double_t epsil;
|
||||
dbr_double_t base;
|
||||
unsigned long iter;
|
||||
|
||||
printf ("float test ...");
|
||||
@@ -328,7 +334,7 @@ int doacctst(char *pname)
|
||||
* solicitations
|
||||
*/
|
||||
if(ca_read_access(chix4)){
|
||||
float temp;
|
||||
dbr_float_t temp;
|
||||
|
||||
printf("Performing multiple get test...");
|
||||
fflush(stdout);
|
||||
@@ -349,7 +355,7 @@ int doacctst(char *pname)
|
||||
printf("Performing multiple put test...");
|
||||
fflush(stdout);
|
||||
for(i=0; i<10000; i++){
|
||||
double fval = 3.3;
|
||||
dbr_double_t fval = 3.3;
|
||||
status = ca_put(DBR_DOUBLE, chix4, &fval);
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
@@ -396,7 +402,7 @@ int doacctst(char *pname)
|
||||
printf("Performing multiple put callback test...");
|
||||
fflush(stdout);
|
||||
for(i=0; i<10000; i++){
|
||||
float fval = 3.3;
|
||||
dbr_float_t fval = 3.3F;
|
||||
status = ca_array_put_callback(
|
||||
DBR_FLOAT,
|
||||
1,
|
||||
@@ -420,8 +426,8 @@ int doacctst(char *pname)
|
||||
printf("Performing multiple monitor test...");
|
||||
fflush(stdout);
|
||||
{
|
||||
evid mid[1000];
|
||||
float temp;
|
||||
evid mid[1000];
|
||||
dbr_float_t temp;
|
||||
|
||||
for(i=0; i<NELEMENTS(mid); i++){
|
||||
SEVCHK(ca_add_event(DBR_GR_FLOAT, chix4, null_event,
|
||||
@@ -499,8 +505,8 @@ int doacctst(char *pname)
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
|
||||
pfloat = (float *) calloc(sizeof(float),NUM);
|
||||
pdouble = (double *) calloc(sizeof(double),NUM);
|
||||
pfloat = (dbr_float_t *) calloc(sizeof(*pfloat),NUM);
|
||||
pdouble = (dbr_double_t *) calloc(sizeof(*pdouble),NUM);
|
||||
pgrfloat = (struct dbr_gr_float *) calloc(sizeof(*pgrfloat),NUM);
|
||||
|
||||
if (VALID_DB_REQ(chix1->type))
|
||||
@@ -643,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");
|
||||
@@ -654,9 +665,15 @@ void null_event(struct event_handler_args args)
|
||||
void write_event(struct event_handler_args args)
|
||||
{
|
||||
int status;
|
||||
float a = *(float *) args.dbr;
|
||||
dbr_float_t *pFloat = (dbr_float_t *) args.dbr;
|
||||
dbr_float_t a;
|
||||
|
||||
a += 10.1;
|
||||
if (!args.dbr) {
|
||||
return;
|
||||
}
|
||||
|
||||
a = *pFloat;
|
||||
a += 10.1F;
|
||||
|
||||
status = ca_array_put(
|
||||
DBR_FLOAT,
|
||||
@@ -745,10 +762,10 @@ void test_sync_groups(chid chix)
|
||||
*/
|
||||
void multiple_sg_requests(chid chix, CA_SYNC_GID gid)
|
||||
{
|
||||
int status;
|
||||
unsigned i;
|
||||
static float fvalput = 3.3;
|
||||
static float fvalget;
|
||||
int status;
|
||||
unsigned i;
|
||||
static dbr_float_t fvalput = 3.3F;
|
||||
static dbr_float_t fvalget;
|
||||
|
||||
for(i=0; i<1000; i++){
|
||||
if(ca_write_access(chix)){
|
||||
|
||||
@@ -19,7 +19,7 @@ void caAddConfiguredAddr(
|
||||
int port);
|
||||
|
||||
int local_addr(SOCKET socket, struct sockaddr_in *plcladdr);
|
||||
int caFetchPortConfig(ENV_PARAM *pEnv, int defaultPort);
|
||||
unsigned short caFetchPortConfig(ENV_PARAM *pEnv, unsigned short defaultPort);
|
||||
|
||||
union caAddr{
|
||||
struct sockaddr_in inetAddr;
|
||||
|
||||
259
src/ca/iocinf.c
259
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,
|
||||
@@ -757,7 +759,7 @@ LOCAL void cac_tcp_send_msg_piiu(struct ioc_in_use *piiu)
|
||||
|
||||
CAC_RING_BUFFER_READ_ADVANCE(&piiu->send, status);
|
||||
|
||||
if (status != sendCnt) {
|
||||
if (((unsigned long)status) != sendCnt) {
|
||||
UNLOCK;
|
||||
return;
|
||||
}
|
||||
@@ -928,7 +930,7 @@ LOCAL void tcp_recv_msg(struct ioc_in_use *piiu)
|
||||
break;
|
||||
}
|
||||
|
||||
assert (status<=writeSpace);
|
||||
assert (((unsigned long)status)<=writeSpace);
|
||||
|
||||
CAC_RING_BUFFER_WRITE_ADVANCE(&piiu->recv, status);
|
||||
|
||||
@@ -938,7 +940,7 @@ LOCAL void tcp_recv_msg(struct ioc_in_use *piiu)
|
||||
*/
|
||||
piiu->timeAtLastRecv = ca_static->currentTime;
|
||||
|
||||
if (status != writeSpace) {
|
||||
if (((unsigned long)status) != writeSpace) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -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,6 +1208,8 @@ void close_ioc (struct ioc_in_use *piiu)
|
||||
piiuCast = NULL;
|
||||
}
|
||||
else {
|
||||
chid pNext;
|
||||
|
||||
/*
|
||||
* remove IOC from the hash table
|
||||
*/
|
||||
@@ -1209,73 +1223,20 @@ void close_ioc (struct ioc_in_use *piiu)
|
||||
* handler tries to use a channel before
|
||||
* I mark it disconnected.
|
||||
*/
|
||||
chix = (chid) &piiu->chidlist.node.next;
|
||||
while (chix = (chid) chix->node.next) {
|
||||
chix->type = TYPENOTCONN;
|
||||
chix->count = 0U;
|
||||
chix = (chid) ellFirst(&piiu->chidlist);
|
||||
while (chix) {
|
||||
chix->state = cs_prev_conn;
|
||||
chix->id.sid = ~0U;
|
||||
chix->ar.read_access = FALSE;
|
||||
chix->ar.write_access = FALSE;
|
||||
/*
|
||||
* try to reconnect
|
||||
*/
|
||||
chix->retry = 0U;
|
||||
chix = (chid) ellNext(&chix->node);
|
||||
}
|
||||
|
||||
if (piiu->chidlist.count) {
|
||||
ca_signal (ECA_DISCONN,piiu->host_name_str);
|
||||
chix = (chid) ellFirst(&piiu->chidlist);
|
||||
while (chix) {
|
||||
pNext = (chid) ellNext(&chix->node);
|
||||
cacDisconnectChannel(chix, TRUE);
|
||||
chix = pNext;
|
||||
}
|
||||
|
||||
/*
|
||||
* clear outstanding get call backs
|
||||
*/
|
||||
caIOBlockListFree (&pend_read_list, chix, TRUE, ECA_DISCONN);
|
||||
|
||||
/*
|
||||
* clear outstanding put call backs
|
||||
*/
|
||||
caIOBlockListFree (&pend_write_list, chix, TRUE, ECA_DISCONN);
|
||||
|
||||
/*
|
||||
* call their connection handler as required
|
||||
*/
|
||||
chix = (chid) &piiu->chidlist.node.next;
|
||||
while (chix = (chid) chix->node.next) {
|
||||
LOCKEVENTS;
|
||||
if (chix->pConnFunc) {
|
||||
struct connection_handler_args args;
|
||||
|
||||
args.chid = chix;
|
||||
args.op = CA_OP_CONN_DOWN;
|
||||
(*chix->pConnFunc) (args);
|
||||
}
|
||||
if (chix->pAccessRightsFunc) {
|
||||
struct access_rights_handler_args args;
|
||||
|
||||
args.chid = chix;
|
||||
args.ar = chix->ar;
|
||||
(*chix->pAccessRightsFunc) (args);
|
||||
}
|
||||
UNLOCKEVENTS;
|
||||
chix->piiu = piiuCast;
|
||||
}
|
||||
|
||||
/*
|
||||
* move all channels to the broadcast IIU
|
||||
*
|
||||
* if we loose the broadcast IIU its a severe error
|
||||
*/
|
||||
assert (piiuCast);
|
||||
ellConcat (&piiuCast->chidlist, &piiu->chidlist);
|
||||
assert (piiu->chidlist.count==0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to reconnect
|
||||
*/
|
||||
ca_static->ca_search_retry = 0;
|
||||
|
||||
if (fd_register_func) {
|
||||
LOCKEVENTS;
|
||||
(*fd_register_func) (fd_register_arg, piiu->sock_chan, FALSE);
|
||||
@@ -1298,11 +1259,78 @@ void close_ioc (struct ioc_in_use *piiu)
|
||||
|
||||
ellFree (&piiu->destAddr);
|
||||
|
||||
ca_signal (ECA_DISCONN,piiu->host_name_str);
|
||||
|
||||
free (piiu);
|
||||
|
||||
UNLOCK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* cacDisconnectChannel()
|
||||
*/
|
||||
void cacDisconnectChannel(chid chix, int fullDisconnect)
|
||||
{
|
||||
struct ioc_in_use *piiu;
|
||||
|
||||
chix->type = TYPENOTCONN;
|
||||
chix->count = 0U;
|
||||
chix->id.sid = ~0U;
|
||||
chix->ar.read_access = FALSE;
|
||||
chix->ar.write_access = FALSE;
|
||||
|
||||
/*
|
||||
* try to reconnect
|
||||
*/
|
||||
chix->retry = 0U;
|
||||
|
||||
/*
|
||||
* call their connection handler as required
|
||||
*/
|
||||
if (fullDisconnect) {
|
||||
chix->state = cs_prev_conn;
|
||||
|
||||
/*
|
||||
* clear outstanding get call backs
|
||||
*/
|
||||
caIOBlockListFree (&pend_read_list, chix,
|
||||
TRUE, ECA_DISCONN);
|
||||
|
||||
/*
|
||||
* clear outstanding put call backs
|
||||
*/
|
||||
caIOBlockListFree (&pend_write_list, chix,
|
||||
TRUE, ECA_DISCONN);
|
||||
|
||||
LOCKEVENTS;
|
||||
if (chix->pConnFunc) {
|
||||
struct connection_handler_args args;
|
||||
|
||||
args.chid = chix;
|
||||
args.op = CA_OP_CONN_DOWN;
|
||||
(*chix->pConnFunc) (args);
|
||||
}
|
||||
if (chix->pAccessRightsFunc) {
|
||||
struct access_rights_handler_args args;
|
||||
|
||||
args.chid = chix;
|
||||
args.ar = chix->ar;
|
||||
(*chix->pAccessRightsFunc) (args);
|
||||
}
|
||||
UNLOCKEVENTS;
|
||||
}
|
||||
piiu = (struct ioc_in_use *)chix->piiu;
|
||||
ellDelete(&piiu->chidlist, &chix->node);
|
||||
assert (piiuCast);
|
||||
chix->piiu = piiuCast;
|
||||
ellAdd(&piiuCast->chidlist, &chix->node);
|
||||
|
||||
/*
|
||||
* Try to reconnect this channel
|
||||
*/
|
||||
ca_static->ca_search_retry = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -1705,7 +1733,7 @@ void caPrintAddrList(ELLLIST *pList)
|
||||
/*
|
||||
* caFetchPortConfig()
|
||||
*/
|
||||
int caFetchPortConfig(ENV_PARAM *pEnv, int defaultPort)
|
||||
unsigned short caFetchPortConfig(ENV_PARAM *pEnv, unsigned short defaultPort)
|
||||
{
|
||||
long longStatus;
|
||||
long epicsParam;
|
||||
@@ -1713,30 +1741,113 @@ int caFetchPortConfig(ENV_PARAM *pEnv, int defaultPort)
|
||||
|
||||
longStatus = envGetLongConfigParam(pEnv, &epicsParam);
|
||||
if (longStatus!=0) {
|
||||
epicsParam = defaultPort;
|
||||
epicsParam = (long) defaultPort;
|
||||
ca_printf ("EPICS \"%s\" integer fetch failed\n", pEnv->name);
|
||||
ca_printf ("setting \"%s\" = %ld\n", pEnv->name, epicsParam);
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be a server port that will fit in a signed
|
||||
* This must be a server port that will fit in an unsigned
|
||||
* short
|
||||
*/
|
||||
if (epicsParam<=IPPORT_USERRESERVED || epicsParam>SHRT_MAX) {
|
||||
if (epicsParam<=IPPORT_USERRESERVED || epicsParam>USHRT_MAX) {
|
||||
ca_printf ("EPICS \"%s\" out of range\n", pEnv->name);
|
||||
/*
|
||||
* Quit if the port is wrong due CA coding error
|
||||
*/
|
||||
assert (epicsParam != defaultPort);
|
||||
epicsParam = defaultPort;
|
||||
assert (epicsParam != (long) defaultPort);
|
||||
epicsParam = (long) defaultPort;
|
||||
ca_printf ("Setting \"%s\" = %ld\n", pEnv->name, epicsParam);
|
||||
}
|
||||
|
||||
/*
|
||||
* ok to clip to int here because we checked the range
|
||||
*/
|
||||
port = (int) epicsParam;
|
||||
port = (unsigned short) epicsParam;
|
||||
|
||||
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,8 +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$ */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
/* $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 */
|
||||
/************************************************************************/
|
||||
/* */
|
||||
@@ -161,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;
|
||||
@@ -193,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) */
|
||||
|
||||
@@ -412,9 +428,11 @@ struct ca_static{
|
||||
void (*ca_exception_func)
|
||||
(struct exception_handler_args);
|
||||
void *ca_exception_arg;
|
||||
#if 0
|
||||
void (*ca_connection_func)
|
||||
(struct connection_handler_args);
|
||||
void *ca_connection_arg;
|
||||
#endif
|
||||
int (*ca_printf_func)(const char *pformat, va_list args);
|
||||
void (*ca_fd_register_func)
|
||||
(void *, SOCKET, int);
|
||||
@@ -433,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;
|
||||
@@ -536,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(
|
||||
@@ -570,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
|
||||
);
|
||||
|
||||
@@ -607,7 +626,9 @@ 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!!
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#ifndef __IOCMSG__
|
||||
/* $Id$ */
|
||||
/*
|
||||
* History
|
||||
* .01 01xx90 joh removed status field in favor of a independent m_cmmd-
|
||||
@@ -23,6 +24,10 @@
|
||||
* .09 050594 joh New command added for CA V4.3 - repeater fanout register
|
||||
*
|
||||
* .10 050594 joh New command added for CA V4.3 - wakeup the server
|
||||
* $Log$
|
||||
* Revision 1.23 1995/08/23 00:35:17 jhill
|
||||
* added log entries
|
||||
*
|
||||
*/
|
||||
|
||||
#define __IOCMSG__
|
||||
@@ -31,7 +36,7 @@ HDRVERSIONID(iocmsgh, "@(#) $Id$ CA version 4.4")
|
||||
|
||||
/* TCP/UDP port number (bumped each protocol change) */
|
||||
#define CA_PROTOCOL_VERSION 4
|
||||
#define CA_MINOR_VERSION 5
|
||||
#define CA_MINOR_VERSION 6
|
||||
#define CA_UKN_MINOR_VERSION 0 /* unknown minor version */
|
||||
#if CA_PROTOCOL_VERSION == 4
|
||||
#define CA_V41(MAJOR,MINOR) ((MINOR)>=1)
|
||||
@@ -39,18 +44,21 @@ HDRVERSIONID(iocmsgh, "@(#) $Id$ CA version 4.4")
|
||||
#define CA_V43(MAJOR,MINOR) ((MINOR)>=3)
|
||||
#define CA_V44(MAJOR,MINOR) ((MINOR)>=4)
|
||||
#define CA_V45(MAJOR,MINOR) ((MINOR)>=5)
|
||||
#define CA_V46(MAJOR,MINOR) ((MINOR)>=6)
|
||||
#elif CA_PROTOCOL_VERSION > 4
|
||||
#define CA_V41(MAJOR,MINOR) ( 1 )
|
||||
#define CA_V42(MAJOR,MINOR) ( 1 )
|
||||
#define CA_V43(MAJOR,MINOR) ( 1 )
|
||||
#define CA_V44(MAJOR,MINOR) ( 1 )
|
||||
#define CA_V45(MAJOR,MINOR) ( 1 )
|
||||
#define CA_V46(MAJOR,MINOR) ( 1 )
|
||||
#else
|
||||
#define CA_V41(MAJOR,MINOR) ( 0 )
|
||||
#define CA_V42(MAJOR,MINOR) ( 0 )
|
||||
#define CA_V43(MAJOR,MINOR) ( 0 )
|
||||
#define CA_V44(MAJOR,MINOR) ( 0 )
|
||||
#define CA_V45(MAJOR,MINOR) ( 0 )
|
||||
#define CA_V46(MAJOR,MINOR) ( 0 )
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -59,7 +67,7 @@ HDRVERSIONID(iocmsgh, "@(#) $Id$ CA version 4.4")
|
||||
* environment variables "EPICS_CA_REPEATER_PORT" and
|
||||
* "EPICS_CA_SERVER_PORT"
|
||||
*/
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
|
||||
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2)
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2+1)
|
||||
|
||||
@@ -104,6 +112,7 @@ typedef ca_uint32_t caResId;
|
||||
#define IOC_ECHO 23 /* CA V4.3 connection verify */
|
||||
#define REPEATER_REGISTER 24 /* registr for repeater fan out */
|
||||
#define IOC_SIGNAL 25 /* knock the server out of select */
|
||||
#define IOC_CLAIM_CIU_FAILED 26 /* unable to create chan resource in server */
|
||||
|
||||
/*
|
||||
* for use with search and not_found (if search fails and
|
||||
@@ -113,15 +122,15 @@ typedef ca_uint32_t caResId;
|
||||
#define DONTREPLY 5
|
||||
|
||||
/* size of object in bytes rounded up to nearest oct word */
|
||||
#define OCT_ROUND(A) ((((unsigned long)A)+7)>>3)
|
||||
#define OCT_ROUND(A) ((((unsigned long)(A))+7)>>3)
|
||||
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest long word */
|
||||
#define QUAD_ROUND(A) (((unsigned long)A)+3)>>2)
|
||||
#define QUAD_ROUND(A) (((unsigned long)(A))+3)>>2)
|
||||
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest short word */
|
||||
#define BI_ROUND(A) ((((unsigned long)A)+1)>>1)
|
||||
#define BI_ROUND(A) ((((unsigned long)(A))+1)>>1)
|
||||
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -307,12 +314,13 @@ static char *os_depenhSccsId = "$Id$";
|
||||
# define UNLOCKEVENTS
|
||||
# define EVENTLOCKTEST (post_msg_active)
|
||||
# define MAXHOSTNAMELEN 75
|
||||
# define IPPORT_USERRESERVED 5000
|
||||
# define IPPORT_USERRESERVED 5000U
|
||||
# define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
# define ENOBUFS WSAENOBUFS
|
||||
# define ECONNRESET WSAECONNRESET
|
||||
# define ETIMEDOUT WSAETIMEDOUT
|
||||
# define EADDRINUSE WSAEADDRINUSE
|
||||
# define ECONNREFUSED WSAECONNREFUSED
|
||||
# define socket_close(S) closesocket(S)
|
||||
# define socket_ioctl(A,B,C) ioctlsocket(A,B,C)
|
||||
# define MYERRNO WSAGetLastError()
|
||||
|
||||
@@ -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$";
|
||||
@@ -85,8 +89,8 @@ static char buf[MAX_UDP];
|
||||
|
||||
LOCAL void register_new_client(struct sockaddr_in *pLocal,
|
||||
struct sockaddr_in *pFrom);
|
||||
#define PORT_ANY 0
|
||||
LOCAL int makeSocket(int port);
|
||||
#define PORT_ANY 0U
|
||||
LOCAL SOCKET makeSocket(unsigned short port);
|
||||
LOCAL void fanOut(struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize);
|
||||
|
||||
|
||||
@@ -104,7 +108,7 @@ void ca_repeater()
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_in local;
|
||||
int from_size = sizeof from;
|
||||
short port;
|
||||
unsigned short port;
|
||||
|
||||
port = caFetchPortConfig(
|
||||
&EPICS_CA_REPEATER_PORT,
|
||||
@@ -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;
|
||||
@@ -241,11 +254,11 @@ LOCAL void fanOut(struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize)
|
||||
/*
|
||||
* makeSocket()
|
||||
*/
|
||||
LOCAL int makeSocket(int port)
|
||||
LOCAL SOCKET makeSocket(unsigned short port)
|
||||
{
|
||||
int status;
|
||||
struct sockaddr_in bd;
|
||||
int sock;
|
||||
SOCKET sock;
|
||||
int true = 1;
|
||||
|
||||
sock = socket( AF_INET, /* domain */
|
||||
|
||||
@@ -263,8 +263,6 @@ const struct in_addr *pnet_addr
|
||||
&piiu->curMsg.m_available);
|
||||
UNLOCK;
|
||||
if(!monix){
|
||||
ca_signal(ECA_INTERNAL,
|
||||
"bad client write io id from server");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -313,8 +311,6 @@ const struct in_addr *pnet_addr
|
||||
&piiu->curMsg.m_available);
|
||||
UNLOCK;
|
||||
if(!monix){
|
||||
ca_signal(ECA_INTERNAL,
|
||||
"bad client read notify io id from server");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -384,8 +380,6 @@ const struct in_addr *pnet_addr
|
||||
&piiu->curMsg.m_available);
|
||||
UNLOCK;
|
||||
if(!monix){
|
||||
ca_signal(ECA_INTERNAL,
|
||||
"bad client event id from server");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -465,8 +459,6 @@ const struct in_addr *pnet_addr
|
||||
&piiu->curMsg.m_available);
|
||||
UNLOCK;
|
||||
if(!pIOBlock){
|
||||
ca_signal(ECA_INTERNAL,
|
||||
"bad client read io id from server");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -640,9 +632,6 @@ const struct in_addr *pnet_addr
|
||||
if (pList) {
|
||||
ellDelete(pList, &monix->node);
|
||||
}
|
||||
else {
|
||||
printf ("CAC - Protocol err - no list for IO blk\n");
|
||||
}
|
||||
caIOBlockFree(monix);
|
||||
}
|
||||
|
||||
@@ -712,6 +701,31 @@ const struct in_addr *pnet_addr
|
||||
reconnect_channel(piiu, chan);
|
||||
break;
|
||||
}
|
||||
case IOC_CLAIM_CIU_FAILED:
|
||||
{
|
||||
chid chan;
|
||||
|
||||
LOCK;
|
||||
chan = bucketLookupItemUnsignedId(
|
||||
pSlowBucket, &piiu->curMsg.m_cid);
|
||||
UNLOCK;
|
||||
if(!chan){
|
||||
/*
|
||||
* end up here if they delete the channel
|
||||
* prior to this response
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* need to move the channel back to the cast IIU
|
||||
* (so we will be able to reconnect)
|
||||
*/
|
||||
LOCK;
|
||||
cacDisconnectChannel(chan, FALSE);
|
||||
UNLOCK;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ca_printf("CAC: post_msg(): Corrupt cmd in msg %x\n",
|
||||
piiu->curMsg.m_cmmd);
|
||||
@@ -734,7 +748,7 @@ const struct in_addr *pnet_addr
|
||||
)
|
||||
{
|
||||
int v42;
|
||||
int port;
|
||||
unsigned short port;
|
||||
char rej[64];
|
||||
chid chan;
|
||||
int status;
|
||||
@@ -828,7 +842,7 @@ const struct in_addr *pnet_addr
|
||||
case ECA_DISCONN:
|
||||
/*
|
||||
* This indicates that the connection is tagged
|
||||
* is tagged for shutdown and we are waiting for
|
||||
* for shutdown and we are waiting for
|
||||
* it to go away. Search replies are ignored
|
||||
* in the interim.
|
||||
*/
|
||||
@@ -979,9 +993,6 @@ chid chan
|
||||
/* decrement the outstanding IO count */
|
||||
CLRPENDRECV(TRUE);
|
||||
}
|
||||
|
||||
|
||||
UNLOCK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* NOTES:
|
||||
* 1) Need to fix if the OP is on a FD that
|
||||
@@ -249,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;
|
||||
@@ -520,7 +526,7 @@ LOCAL void io_complete(struct event_handler_args args)
|
||||
* Update the user's variable
|
||||
* (if its a get)
|
||||
*/
|
||||
if(pcasgop->pValue){
|
||||
if(pcasgop->pValue && args.dbr){
|
||||
size = dbr_size_n(args.type, args.count);
|
||||
memcpy(pcasgop->pValue, args.dbr, size);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,16 +27,18 @@
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Lawrence Berkley National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* $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,48 +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 = (long)st.wSecond + (long)st.wMinute*60 +
|
||||
(long)st.wHour*360;
|
||||
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();
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,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;
|
||||
|
||||
@@ -154,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 ();
|
||||
|
||||
@@ -291,11 +270,8 @@ int local_addr (SOCKET s, struct sockaddr_in *plcladdr)
|
||||
*/
|
||||
void caDiscoverInterfaces(ELLLIST *pList, SOCKET socket, int port)
|
||||
{
|
||||
struct sockaddr_in localAddr;
|
||||
struct sockaddr_in InetAddr;
|
||||
struct in_addr bcast_addr;
|
||||
caAddrNode *pNode;
|
||||
int status;
|
||||
|
||||
pNode = (caAddrNode *) calloc(1,sizeof(*pNode));
|
||||
if(!pNode){
|
||||
@@ -353,6 +329,13 @@ static int get_subnet_mask ( char SubNetMaskStr[256])
|
||||
return RegTcpParams (localadr, SubNetMaskStr);
|
||||
}
|
||||
|
||||
/* For NT 3.51, enumerates network interfaces returns the ip address */
|
||||
/* and subnet mask for the LAST interface found. This needs to be changed */
|
||||
/* to work in conjuction with caDiscoverInterfaces to add all the */
|
||||
/* add all the interfaces to the elist. Also could be more efficient in
|
||||
calling */
|
||||
/* RegKeyOpen */
|
||||
|
||||
static int RegTcpParams (char IpAddrStr[256], char SubNetMaskStr[256])
|
||||
{
|
||||
#define MAX_VALUE_NAME 128
|
||||
@@ -361,37 +344,65 @@ static int RegTcpParams (char IpAddrStr[256], char SubNetMaskStr[256])
|
||||
DWORD cbDataLen;
|
||||
CHAR cbData[256];
|
||||
DWORD dwType;
|
||||
int status;
|
||||
int status, i, card_cnt;
|
||||
char *pNetCard[16], *pData;
|
||||
|
||||
static char IpAddr[256], SubNetMask[256];
|
||||
|
||||
cbDataLen = sizeof(cbData);
|
||||
strcpy(RegPath,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards\\1");
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "ServiceName", &dwType, cbData, &cbDataLen);
|
||||
|
||||
/****
|
||||
strcpy(RegPath,"SOFTWARE\\Microsoft\\Windows
|
||||
NT\\CurrentVersion\\NetworkCards\\1");
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "ServiceName", &dwType,
|
||||
cbData, &cbDataLen);
|
||||
if (status) {
|
||||
strcpy(RegPath,"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards\\01");
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "ServiceName", &dwType, cbData, &cbDataLen);
|
||||
strcpy(RegPath,"SOFTWARE\\Microsoft\\Windows
|
||||
NT\\CurrentVersion\\NetworkCards\\01");
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "ServiceName", &dwType,
|
||||
cbData, &cbDataLen);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
****/
|
||||
|
||||
strcpy(RegPath,"SYSTEM\\CurrentControlSet\\Services\\");
|
||||
strcat(RegPath,cbData);
|
||||
strcat(RegPath,"\\Parameters\\Tcpip");
|
||||
strcpy(RegPath,"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage");
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "Route", &dwType, cbData,
|
||||
&cbDataLen);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
i=0; card_cnt = 0; pData = cbData; /* enumerate network interfaces */
|
||||
|
||||
while( i < 16 && (pNetCard[i]=strtok(pData,"\"")) ) {
|
||||
strcpy(RegPath,"SYSTEM\\CurrentControlSet\\Services\\");
|
||||
strcat(RegPath,pNetCard[i]);
|
||||
strcat(RegPath,"\\Parameters\\Tcpip");
|
||||
|
||||
cbDataLen = sizeof(IpAddr);
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "IPAddress", &dwType,
|
||||
IpAddr, &cbDataLen);
|
||||
if (status == 0) {
|
||||
cbDataLen = sizeof(SubNetMask);
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "SubnetMask",
|
||||
&dwType, SubNetMask, &cbDataLen);
|
||||
if (status)
|
||||
return status;
|
||||
card_cnt++;
|
||||
}
|
||||
pData += strlen(pNetCard[i])+3;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (card_cnt == 0)
|
||||
return 1;
|
||||
|
||||
cbDataLen = sizeof(IpAddr);
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "IPAddress", &dwType, IpAddr, &cbDataLen);
|
||||
if (status)
|
||||
return status;
|
||||
strcpy(IpAddrStr,IpAddr);
|
||||
|
||||
cbDataLen = sizeof(SubNetMask);
|
||||
status = RegKeyData (RegPath, HKEY_LOCAL_MACHINE, "SubnetMask", &dwType, SubNetMask, &cbDataLen);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
strcpy(SubNetMaskStr,SubNetMask);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -418,7 +429,7 @@ static int RegKeyData (CHAR *RegPath, HANDLE hKeyRoot, LPSTR lpzValueName,
|
||||
}
|
||||
|
||||
|
||||
retCode = RegQueryValueEx (hKey, // Key handle returned from RegOpenKeyEx.
|
||||
retCode = RegQueryValueEx (hKey, // Key handle returned from
|
||||
lpzValueName, // Name of value.
|
||||
NULL, // Reserved, dword = NULL.
|
||||
lpdwType, // Type of data.
|
||||
@@ -439,34 +450,57 @@ 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:
|
||||
fprintf(stderr, "Thread attached to ca.dll R12\n");
|
||||
#if _DEBUG
|
||||
fprintf(stderr, "Thread attached to ca.dll R3.12.1\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
fprintf(stderr, "Thread detached from ca.dll R12\n");
|
||||
#if _DEBUG
|
||||
fprintf(stderr, "Thread detached from ca.dll R3.12.1\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -475,4 +509,8 @@ BOOL epicsShareAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
#include <dbFldTypes.h>
|
||||
#include <dbRecDes.h>
|
||||
#include <dbRecType.h>
|
||||
#include <dbEvent.h>
|
||||
#include <db_field_log.h>
|
||||
#include <errMdef.h>
|
||||
#include <recSup.h>
|
||||
|
||||
@@ -622,14 +622,16 @@ int db_post_single_event(struct event_block *pevent)
|
||||
*
|
||||
*/
|
||||
int db_post_events(
|
||||
struct dbCommon *precord,
|
||||
union native_value *pvalue,
|
||||
unsigned int select
|
||||
void *prec,
|
||||
void *pval,
|
||||
unsigned int select
|
||||
)
|
||||
{
|
||||
struct event_block *event;
|
||||
struct event_que *ev_que;
|
||||
unsigned int putix;
|
||||
struct dbCommon *precord = (struct dbCommon *)prec;
|
||||
union native_value *pvalue = (union native_value *)pval;
|
||||
struct event_block *event;
|
||||
struct event_que *ev_que;
|
||||
unsigned int putix;
|
||||
|
||||
if (precord->mlis.count == 0) return OK; /* no monitors set */
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include <dbFldTypes.h>
|
||||
#include <dbRecDes.h>
|
||||
#include <dbRecType.h>
|
||||
#include <dbEvent.h>
|
||||
#include <db_field_log.h>
|
||||
#include <errMdef.h>
|
||||
#include <recSup.h>
|
||||
@@ -2784,7 +2785,6 @@ void *pflin
|
||||
long (*pconvert_routine)();
|
||||
struct dbCommon *pcommon;
|
||||
long status;
|
||||
long *perr_status=NULL;
|
||||
|
||||
|
||||
prset=GET_PRSET(pdbBase->precSup,paddr->record_type);
|
||||
@@ -2803,11 +2803,13 @@ void *pflin
|
||||
}
|
||||
*((unsigned short *)pbuffer)++ = pcommon->acks;
|
||||
*((unsigned short *)pbuffer)++ = pcommon->ackt;
|
||||
*perr_status = 0;
|
||||
}
|
||||
if( (*options) & DBR_UNITS ) {
|
||||
if( prset && prset->get_units ){
|
||||
(*prset->get_units)(paddr,pbuffer);
|
||||
char * pchr = (char *)pbuffer;
|
||||
|
||||
(*prset->get_units)(paddr,pchr);
|
||||
pchr[DB_UNITS_SIZE-1] = '\0';
|
||||
} else {
|
||||
memset(pbuffer,'\0',dbr_units_size);
|
||||
*options = (*options) ^ DBR_UNITS; /*Turn off DBR_UNITS*/
|
||||
@@ -2854,7 +2856,6 @@ GET_DATA:
|
||||
|
||||
sprintf(message,"dbGet - database request type is %d",dbrType);
|
||||
recGblDbaddrError(S_db_badDbrtype,paddr,message);
|
||||
if(perr_status) *perr_status = S_db_badDbrtype;
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
|
||||
@@ -2869,7 +2870,6 @@ GET_DATA:
|
||||
|
||||
sprintf(message,"dbGet - database request type is %d",dbrType);
|
||||
recGblDbaddrError(S_db_badDbrtype,paddr,message);
|
||||
if(perr_status) *perr_status = S_db_badDbrtype;
|
||||
return(S_db_badDbrtype);
|
||||
}
|
||||
/* convert database field to buffer type and place it in the buffer */
|
||||
@@ -2885,7 +2885,6 @@ GET_DATA:
|
||||
status=(*pconvert_routine)(paddr,pbuffer,*nRequest,
|
||||
no_elements,offset);
|
||||
}
|
||||
if(perr_status) *perr_status = status;
|
||||
return(status);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <ellLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <dbAccess.h>
|
||||
|
||||
@@ -439,7 +439,6 @@ DBBASE *pdbbase;
|
||||
ELLLIST *preclist;
|
||||
int recType;
|
||||
if (!pdbbase || !ppvd || !precType) return;
|
||||
dbPvdFreeMem(pdbbase);
|
||||
/* loop thru the recLocs - removing lists then recLoc only */
|
||||
for (recType = 0; recType < precType->number; recType++) {
|
||||
if (!(precLoc = GET_PRECLOC(precHeader, recType))) continue;
|
||||
@@ -461,6 +460,7 @@ DBBASE *pdbbase;
|
||||
free((void *) precLoc);
|
||||
}
|
||||
/* free the rest of the memory allocations */
|
||||
dbPvdFreeMem(pdbbase);
|
||||
if (pdbbase->pchoiceCvt)
|
||||
free((void *) pdbbase->pchoiceCvt);
|
||||
if (pdbbase->pchoiceDev)
|
||||
@@ -4316,7 +4316,8 @@ RECNODE *precnode;
|
||||
ppvdlist=ppvd[hashInd];
|
||||
ppvdNode = (PVDENTRY *) ellFirst(ppvdlist);
|
||||
while(ppvdNode) {
|
||||
if(strcmp(name,(char *)ppvdNode->precnode->precord) == 0) {
|
||||
if(ppvdNode->precnode && ppvdNode->precnode->precord
|
||||
&& strcmp(name,(char *)ppvdNode->precnode->precord) == 0) {
|
||||
ellDelete(ppvdlist, (ELLNODE*)ppvdNode);
|
||||
free((void *)ppvdNode);
|
||||
return;
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <timexLib.h>
|
||||
|
||||
#include <ellLib.h>
|
||||
#include <fast_lock.h>
|
||||
@@ -112,6 +113,7 @@
|
||||
#include <special.h>
|
||||
#include <dbRecDes.h>
|
||||
#include <dbStaticLib.h>
|
||||
#include <dbEvent.h>
|
||||
#include <ellLib.h>
|
||||
#include <callback.h>
|
||||
|
||||
@@ -170,18 +172,6 @@ long dba(char*pname)
|
||||
if(status) return(1); else return(0);
|
||||
}
|
||||
|
||||
/*Following definition is from dbEvent.c*/
|
||||
struct event_block{
|
||||
ELLNODE node;
|
||||
struct dbAddr *paddr;
|
||||
void (*user_sub)();
|
||||
void *user_arg;
|
||||
struct event_que *ev_que;
|
||||
unsigned char select;
|
||||
char valque;
|
||||
unsigned short npend; /* n times this event is on the que */
|
||||
};
|
||||
|
||||
long dbel(char*pname)
|
||||
{
|
||||
struct dbAddr addr;
|
||||
@@ -200,7 +190,7 @@ long dbel(char*pname)
|
||||
return(0);
|
||||
}
|
||||
while(peb) {
|
||||
pfldDes = peb->paddr->pfldDes;
|
||||
pfldDes = ((struct dbAddr *)peb->paddr)->pfldDes;
|
||||
printf("%4.4s",&pfldDes->fldname[0]);
|
||||
if(peb->select&&DBE_VALUE) printf(" VALUE");
|
||||
if(peb->select&&DBE_LOG) printf(" LOG");
|
||||
@@ -1756,7 +1746,8 @@ char *record_name;
|
||||
* Time the record
|
||||
*/
|
||||
dbScanLock(precord);
|
||||
timexN(timing_routine, precord);
|
||||
timexN((FUNCPTR)timing_routine, (int)precord,
|
||||
0,0,0,0,0,0,0);
|
||||
dbScanUnlock(precord);
|
||||
|
||||
return(0);
|
||||
|
||||
@@ -129,6 +129,9 @@
|
||||
#define MAX_STRING_SIZE 40
|
||||
#endif
|
||||
|
||||
#ifndef MAX_UNITS_SIZE
|
||||
#define MAX_UNITS_SIZE 8
|
||||
#endif
|
||||
|
||||
/* VALUES WITH STATUS STRUCTURES */
|
||||
|
||||
@@ -269,7 +272,7 @@ struct dbr_time_double{
|
||||
struct dbr_gr_int{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
short upper_disp_limit; /* upper limit of graph */
|
||||
short lower_disp_limit; /* lower limit of graph */
|
||||
short upper_alarm_limit;
|
||||
@@ -281,7 +284,7 @@ struct dbr_gr_int{
|
||||
struct dbr_gr_short{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
short upper_disp_limit; /* upper limit of graph */
|
||||
short lower_disp_limit; /* lower limit of graph */
|
||||
short upper_alarm_limit;
|
||||
@@ -297,7 +300,7 @@ struct dbr_gr_float{
|
||||
short severity; /* severity of alarm */
|
||||
short precision; /* number of decimal places */
|
||||
short RISC_pad0; /* RISC alignment */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
float upper_disp_limit; /* upper limit of graph */
|
||||
float lower_disp_limit; /* lower limit of graph */
|
||||
float upper_alarm_limit;
|
||||
@@ -320,7 +323,7 @@ struct dbr_gr_enum{
|
||||
struct dbr_gr_char{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
unsigned char upper_disp_limit; /* upper limit of graph */
|
||||
unsigned char lower_disp_limit; /* lower limit of graph */
|
||||
unsigned char upper_alarm_limit;
|
||||
@@ -335,7 +338,7 @@ struct dbr_gr_char{
|
||||
struct dbr_gr_long{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
long upper_disp_limit; /* upper limit of graph */
|
||||
long lower_disp_limit; /* lower limit of graph */
|
||||
long upper_alarm_limit;
|
||||
@@ -351,7 +354,7 @@ struct dbr_gr_double{
|
||||
short severity; /* severity of alarm */
|
||||
short precision; /* number of decimal places */
|
||||
short RISC_pad0; /* RISC alignment */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
double upper_disp_limit; /* upper limit of graph */
|
||||
double lower_disp_limit; /* lower limit of graph */
|
||||
double upper_alarm_limit;
|
||||
@@ -370,7 +373,7 @@ struct dbr_gr_double{
|
||||
struct dbr_ctrl_int{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
short upper_disp_limit; /* upper limit of graph */
|
||||
short lower_disp_limit; /* lower limit of graph */
|
||||
short upper_alarm_limit;
|
||||
@@ -384,7 +387,7 @@ struct dbr_ctrl_int{
|
||||
struct dbr_ctrl_short{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
short upper_disp_limit; /* upper limit of graph */
|
||||
short lower_disp_limit; /* lower limit of graph */
|
||||
short upper_alarm_limit;
|
||||
@@ -402,7 +405,7 @@ struct dbr_ctrl_float{
|
||||
short severity; /* severity of alarm */
|
||||
short precision; /* number of decimal places */
|
||||
short RISC_pad; /* RISC alignment */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
float upper_disp_limit; /* upper limit of graph */
|
||||
float lower_disp_limit; /* lower limit of graph */
|
||||
float upper_alarm_limit;
|
||||
@@ -427,7 +430,7 @@ struct dbr_ctrl_enum{
|
||||
struct dbr_ctrl_char{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
unsigned char upper_disp_limit; /* upper limit of graph */
|
||||
unsigned char lower_disp_limit; /* lower limit of graph */
|
||||
unsigned char upper_alarm_limit;
|
||||
@@ -444,7 +447,7 @@ struct dbr_ctrl_char{
|
||||
struct dbr_ctrl_long{
|
||||
short status; /* status of value */
|
||||
short severity; /* severity of alarm */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
long upper_disp_limit; /* upper limit of graph */
|
||||
long lower_disp_limit; /* lower limit of graph */
|
||||
long upper_alarm_limit;
|
||||
@@ -462,7 +465,7 @@ struct dbr_ctrl_double{
|
||||
short severity; /* severity of alarm */
|
||||
short precision; /* number of decimal places */
|
||||
short RISC_pad0; /* RISC alignment */
|
||||
char units[8]; /* units of value */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
double upper_disp_limit; /* upper limit of graph */
|
||||
double lower_disp_limit; /* lower limit of graph */
|
||||
double upper_alarm_limit;
|
||||
@@ -1017,7 +1020,8 @@ void *pfl;
|
||||
pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1051,7 +1055,8 @@ void *pfl;
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
pold->precision = new.precision;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1083,7 +1088,8 @@ void *pfl;
|
||||
pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1114,7 +1120,8 @@ void *pfl;
|
||||
pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1148,7 +1155,8 @@ void *pfl;
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
pold->precision = new.precision;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1182,7 +1190,8 @@ void *pfl;
|
||||
pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1219,7 +1228,8 @@ void *pfl;
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
pold->precision = new.precision;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1286,7 +1296,8 @@ void *pfl;
|
||||
pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1320,7 +1331,8 @@ void *pfl;
|
||||
status = dbGetField(paddr,DBR_LONG,&new,&options,&nRequest,pfl);
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
@@ -1357,7 +1369,8 @@ void *pfl;
|
||||
pold->status = new.status;
|
||||
pold->severity = new.severity;
|
||||
pold->precision = new.precision;
|
||||
strncpy(pold->units,new.units,8);
|
||||
strncpy(pold->units,new.units,MAX_UNITS_SIZE);
|
||||
pold->units[MAX_UNITS_SIZE-1] = '\0';
|
||||
pold->upper_disp_limit = new.upper_disp_limit;
|
||||
pold->lower_disp_limit = new.lower_disp_limit;
|
||||
pold->upper_alarm_limit = new.upper_alarm_limit;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
|
||||
/*
|
||||
* $Log$
|
||||
* Revision 1.14 1995/08/30 15:38:39 jbk
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.13 1995/08/18 13:19:31 mrk
|
||||
* Made changes for ansi c
|
||||
*
|
||||
* Revision 1.12 1995/08/17 20:35:09 jbk
|
||||
* fixed all the -pendantic errors (pain)
|
||||
*
|
||||
@@ -99,7 +105,8 @@ DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000).
|
||||
*/
|
||||
|
||||
#define MAKE_DEBUG TSdriverDebug
|
||||
#define TS_DRIVER
|
||||
#define TS_DRIVER 1
|
||||
#define TS_ALLOW_FORCE 1
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <vme.h>
|
||||
@@ -213,6 +220,9 @@ TSinfo TSdata = { TS_master_dead, TS_async_slave, TS_async_none,
|
||||
|
||||
extern char* sysBootLine;
|
||||
|
||||
int TSdirectTimeVar = 0; /* aother way to indicate direct time */
|
||||
int TSgoodTimeStamps = 0; /* a way to force use of accurate time stamps */
|
||||
|
||||
static WDOG_ID wd;
|
||||
static long correction_factor = 0;
|
||||
static long correction_count = 0;
|
||||
@@ -383,8 +393,13 @@ long TSgetTimeStamp(int event_number,struct timespec* sp)
|
||||
switch(event_number)
|
||||
{
|
||||
case 0:
|
||||
*sp = TSdata.event_table[0]; /* one tick watch dog maintains */
|
||||
break;
|
||||
#ifdef TS_ALLOW_FORCE
|
||||
if(TSgoodTimeStamps==0)
|
||||
#endif
|
||||
{
|
||||
*sp = TSdata.event_table[0]; /* one tick watch dog maintains */
|
||||
break;
|
||||
}
|
||||
case -1:
|
||||
{
|
||||
struct timespec ts;
|
||||
@@ -494,6 +509,8 @@ long TSinit(void)
|
||||
TSregisterErrorHandler = TSregisterErrorHandlerError;
|
||||
TSforceSync = TSforceSoftSync;
|
||||
TSgetTime = TSgetCurrentTime;
|
||||
TSdriverInit = TSdriverInitError;
|
||||
TSdirectTime = TSdirectTimeError;
|
||||
TSdata.sync_event=ER_EVENT_RESET_TICK;
|
||||
}
|
||||
|
||||
@@ -518,7 +535,7 @@ long TSinit(void)
|
||||
else
|
||||
TSdata.has_event_system = 1;
|
||||
|
||||
if(TSdirectTime()>0) TSdata.has_direct_time=1;
|
||||
if(TSdirectTime()>0 || TSdirectTimeVar>0) TSdata.has_direct_time=1;
|
||||
|
||||
/* allocate the event table */
|
||||
TSdata.event_table=(struct timespec*)malloc(
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <dbBase.h>
|
||||
#include <dbRecType.h>
|
||||
#include <dbRecDes.h>
|
||||
#include <dbEvent.h>
|
||||
#include <dbAccess.h>
|
||||
#include <dbScan.h>
|
||||
#include <devSup.h>
|
||||
@@ -201,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;
|
||||
}
|
||||
|
||||
986
src/dbtools/BSlib.c
Normal file
986
src/dbtools/BSlib.c
Normal file
@@ -0,0 +1,986 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "BSlib.h"
|
||||
|
||||
#ifdef linux
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <in.h>
|
||||
#include <ioctl.h>
|
||||
#include <inetLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <ioLib.h>
|
||||
#include <sockLib.h>
|
||||
#include <selectLib.h>
|
||||
#else
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef SOLARIS
|
||||
#define BSD_COMP
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
||||
|
||||
static long BSgetBroadcastAddr(int soc, struct sockaddr* sin);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* server mode functions */
|
||||
|
||||
#ifndef vxWorks /* server mode functions */
|
||||
static char* filename=(char*)NULL;
|
||||
|
||||
/* ----------------------------- */
|
||||
/* signal catcher for the server */
|
||||
/* ----------------------------- */
|
||||
static void catch_sig(int sig)
|
||||
{
|
||||
fprintf(stderr,"\nbdt server exiting\n");
|
||||
unlink(filename);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* -------------------------------- */
|
||||
/* child reaper for the server mode */
|
||||
/* -------------------------------- */
|
||||
static void get_child(int sig)
|
||||
{
|
||||
#ifdef SOLARIS
|
||||
while(waitpid(-1,(int*)NULL,WNOHANG)>0);
|
||||
#else
|
||||
while(wait3((int *)NULL,WNOHANG,(struct rusage *)NULL)>0);
|
||||
#endif
|
||||
|
||||
#if defined linux || defined SOLARIS
|
||||
signal(SIGCHLD,get_child); /* for reaping children */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------- */
|
||||
/* Clear the signals for a process */
|
||||
/* ------------------------------- */
|
||||
int BSserverClearSignals()
|
||||
{
|
||||
signal(SIGCHLD,SIG_DFL);
|
||||
signal(SIGHUP,SIG_DFL);
|
||||
signal(SIGINT,SIG_DFL);
|
||||
signal(SIGTERM,SIG_DFL);
|
||||
signal(SIGQUIT,SIG_DFL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------- */
|
||||
/* Make a unix process into a generic background process */
|
||||
/* ----------------------------------------------------- */
|
||||
int BSmakeServer(char** argv)
|
||||
{
|
||||
FILE* fd;
|
||||
|
||||
if(filename) return -1;
|
||||
|
||||
/* set up signal handling for the server */
|
||||
signal(SIGCHLD,get_child); /* for reaping children */
|
||||
signal(SIGHUP,catch_sig);
|
||||
signal(SIGINT,catch_sig);
|
||||
signal(SIGTERM,catch_sig);
|
||||
signal(SIGQUIT,catch_sig);
|
||||
|
||||
/* disconnect from parent */
|
||||
switch(fork())
|
||||
{
|
||||
case -1: /* error */
|
||||
perror("Cannot fork");
|
||||
return -1;
|
||||
case 0: /* child */
|
||||
#if defined linux || defined SOLARIS
|
||||
setpgrp();
|
||||
#else
|
||||
setpgrp(0,0);
|
||||
#endif
|
||||
setsid();
|
||||
break;
|
||||
default: /* parent goes away */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* save process ID */
|
||||
filename=(char*)malloc(strlen(argv[0])+10);
|
||||
sprintf(filename,"%s.%d",argv[0],getpid());
|
||||
fd=fopen(filename,"w");
|
||||
fprintf(fd,"%d",getpid());
|
||||
fprintf(stderr,"\npv server pid: %d\n",getpid());
|
||||
fclose(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* server mode functions */
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* open a bulk data socket to a server given the server IP address */
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
BS* BSipOpen(char* address, int Port)
|
||||
{
|
||||
struct hostent* pHostent;
|
||||
unsigned long addr;
|
||||
BSDATA info;
|
||||
struct sockaddr_in* tsin;
|
||||
|
||||
tsin=(struct sockaddr_in*)&(info.sin);
|
||||
|
||||
#ifndef vxWorks
|
||||
/* Deal with the name -vs- IP number issue. */
|
||||
if (isdigit(address[0]))
|
||||
{
|
||||
#endif
|
||||
addr=inet_addr(address);
|
||||
#ifndef vxWorks
|
||||
}
|
||||
else
|
||||
{
|
||||
if((pHostent=gethostbyname(address))==NULL) return NULL;
|
||||
memcpy((char*)&addr,pHostent->h_addr,sizeof(addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
tsin->sin_port=htons(Port);
|
||||
tsin->sin_family=AF_INET;
|
||||
memcpy((char*)&(tsin->sin_addr),(char*)&addr,sizeof(addr));
|
||||
|
||||
return BSipOpenData(&info);
|
||||
}
|
||||
|
||||
BS* BSipOpenData(BSDATA* info)
|
||||
{
|
||||
struct sockaddr_in tsin;
|
||||
int osoc;
|
||||
BS* bdt;
|
||||
|
||||
tsin.sin_port=0;
|
||||
tsin.sin_family=AF_INET;
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((osoc=socket(AF_INET,SOCK_STREAM,BS_TCP))<0)
|
||||
{
|
||||
perror("BSipOpen: create socket failed");
|
||||
return (BS*)NULL;
|
||||
}
|
||||
|
||||
if((bind(osoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BSipOpen: local address bind failed");
|
||||
return (BS*)NULL;
|
||||
}
|
||||
|
||||
if(connect(osoc,(struct sockaddr*)&(info->sin),sizeof(info->sin))<0)
|
||||
{
|
||||
perror("BSipOpen: connect failed");
|
||||
close(osoc);
|
||||
return (BS*)NULL;
|
||||
}
|
||||
|
||||
bdt=(BS*)malloc(sizeof(BS));
|
||||
bdt->soc=osoc;
|
||||
bdt->remaining_send=0;
|
||||
bdt->remaining_recv=0;
|
||||
bdt->state=BSidle;
|
||||
|
||||
#ifndef vxWorks
|
||||
{
|
||||
int j;
|
||||
j = fcntl(bdt->soc, F_GETFL, 0);
|
||||
fcntl(bdt->soc, F_SETFL, j|O_NDELAY);
|
||||
}
|
||||
#endif
|
||||
/* now connected to the bulk data socket on the IOC */
|
||||
return bdt;
|
||||
}
|
||||
|
||||
/* -------------------------------------- */
|
||||
/* write size bytes from buffer to socket */
|
||||
/* -------------------------------------- */
|
||||
int BSwrite(int soc,void* buffer,int size)
|
||||
{
|
||||
int rc;
|
||||
int total;
|
||||
unsigned char* data;
|
||||
fd_set fds;
|
||||
struct timeval to;
|
||||
|
||||
data=(unsigned char*)buffer;
|
||||
total=size;
|
||||
|
||||
to.tv_sec = 5;
|
||||
to.tv_usec = 0;
|
||||
|
||||
do
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc, &fds);
|
||||
if(select(FD_SETSIZE,NULL,&fds,NULL,&to) != 1)
|
||||
{
|
||||
printf("BSwrite: timeout waiting to write data\n");
|
||||
return -1;
|
||||
}
|
||||
/* send block of data */
|
||||
if((rc=send(soc,(char*)&data[size-total],total,0))<0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
rc = 0;
|
||||
else
|
||||
perror("BSwrite: Send to remote failed");
|
||||
}
|
||||
else
|
||||
total-=rc;
|
||||
}
|
||||
while(rc>0 && total>0);
|
||||
|
||||
return (rc<=0)?-1:0;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* send a message header down a BS socket */
|
||||
/* --------------------------------------- */
|
||||
int BSsendHeader(BS* bdt,unsigned short verb,int size)
|
||||
{
|
||||
BSmsgHead buf;
|
||||
|
||||
if(bdt->state!=BSidle)
|
||||
{
|
||||
fprintf(stderr,"BSsendHeader: Interface not idle\n");
|
||||
bdt->state=BSbad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf.verb=htons(verb);
|
||||
buf.size=htonl((unsigned long)size);
|
||||
|
||||
if(BSwrite(bdt->soc,&buf.verb, sizeof(buf.verb))<0)
|
||||
{
|
||||
fprintf(stderr,"BSsendHeader: write to remote failed");
|
||||
return -1;
|
||||
}
|
||||
if(BSwrite(bdt->soc,&buf.size, sizeof(buf.size))<0)
|
||||
{
|
||||
fprintf(stderr,"BSsendHeader: write to remote failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* don't wait for response if data must go out */
|
||||
if(size)
|
||||
{
|
||||
bdt->remaining_send=size;
|
||||
bdt->state=BSsData;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* send a message data chunk down a BS socket */
|
||||
/* ------------------------------------------- */
|
||||
int BSsendData(BS* bdt,void* buffer,int size)
|
||||
{
|
||||
int len;
|
||||
int remaining;
|
||||
int rc;
|
||||
|
||||
if(bdt->state!=BSsData)
|
||||
{
|
||||
fprintf(stderr,"BSsendData: Interface not in send data mode\n");
|
||||
bdt->state=BSbad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
remaining=bdt->remaining_send-size;
|
||||
|
||||
if(remaining<0)
|
||||
{
|
||||
fprintf(stderr,"WARNING -- BSsendData: To much data to send\n");
|
||||
len=bdt->remaining_send;
|
||||
}
|
||||
else
|
||||
len=size;
|
||||
|
||||
if (BSwrite(bdt->soc, buffer, len) < 0)
|
||||
return -1;
|
||||
|
||||
bdt->remaining_send-=len;
|
||||
|
||||
if(bdt->remaining_send<0)
|
||||
{
|
||||
fprintf(stderr,"BSsendData: To much data Sent\n");
|
||||
bdt->remaining_send=0;
|
||||
}
|
||||
|
||||
if(bdt->remaining_send==0)
|
||||
bdt->state=BSidle;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int BSflushOutput(BS* bdt)
|
||||
{
|
||||
#ifdef vxWorks
|
||||
ioctl(bdt->soc, FIOWFLUSH, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------- */
|
||||
/* Read exactly size bytes from remote */
|
||||
/* ------------------------------------- */
|
||||
int BSread(int soc,void* buffer,int size)
|
||||
{
|
||||
int rc,total;
|
||||
unsigned char* data;
|
||||
fd_set fds;
|
||||
struct timeval to;
|
||||
|
||||
to.tv_sec = 5;
|
||||
to.tv_usec = 0;
|
||||
|
||||
data=(unsigned char*)buffer;
|
||||
total=size;
|
||||
|
||||
do
|
||||
{
|
||||
#if 1
|
||||
/* wait for data chunk */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc, &fds);
|
||||
if (select(soc+1, &fds, NULL, NULL, &to) != 1)
|
||||
{
|
||||
printf("BSread: timeout waiting for data\n");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
if((rc=recv(soc,(char*)&data[size-total],total,0))<0)
|
||||
{
|
||||
if(errno==EINTR)
|
||||
{
|
||||
printf("BSread: EINTR");
|
||||
rc=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("BSread: Receive data chunk failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
total-=rc;
|
||||
}
|
||||
while(rc>0 && total>0);
|
||||
|
||||
return (rc<=0)?-1:0;
|
||||
}
|
||||
|
||||
/* ------------------------------------- */
|
||||
/* wait for a message header from remote */
|
||||
/* ------------------------------------- */
|
||||
int BSreceiveHeader(BS* bdt,int* verb,int* size)
|
||||
{
|
||||
BSmsgHead buf;
|
||||
|
||||
/* can only receive header when in the idle state */
|
||||
if (bdt->state == BSeof)
|
||||
return -1;
|
||||
|
||||
if(bdt->state != BSidle)
|
||||
{
|
||||
fprintf(stderr,"BSreceiveHeader: Interface not idle\n");
|
||||
bdt->state=BSbad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(BSread(bdt->soc,&buf.verb,sizeof(buf.verb))<0)
|
||||
{
|
||||
fprintf(stderr,"BSreceiveHeader: Read failed\n");
|
||||
return -1;
|
||||
}
|
||||
if(BSread(bdt->soc,&buf.size,sizeof(buf.size))<0)
|
||||
{
|
||||
fprintf(stderr,"BSreceiveHeader: Read failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy message data to user */
|
||||
*verb=ntohs(buf.verb);
|
||||
*size=ntohl(buf.size);
|
||||
|
||||
if(*size)
|
||||
bdt->state=BSrData;
|
||||
|
||||
bdt->remaining_recv=*size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Wait for a chunk of data from remote.
|
||||
User can continually call this with a maximum size until it return 0.
|
||||
------------------------------------------------------------------------ */
|
||||
int BSreceiveData(BS* bdt,void* buffer,int size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* can only receive data when in the receive data state */
|
||||
switch(bdt->state)
|
||||
{
|
||||
case BSrData: break;
|
||||
case BSidle: return 0;
|
||||
default:
|
||||
fprintf(stderr,"BSreceiveData: bad receive state\n");
|
||||
bdt->state=BSbad;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bdt->remaining_recv < size)
|
||||
size = bdt->remaining_recv;
|
||||
|
||||
if(BSread(bdt->soc,buffer,size)<0)
|
||||
{
|
||||
fprintf(stderr,"BSreceiveData: Read failed\n");
|
||||
bdt->state = BSeof;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bdt->remaining_recv-=size;
|
||||
|
||||
if(bdt->remaining_recv<0)
|
||||
{
|
||||
fprintf(stderr,"BSreceiveData: To much data received\n");
|
||||
bdt->remaining_recv=0;
|
||||
}
|
||||
|
||||
if(bdt->remaining_recv==0)
|
||||
bdt->state=BSidle;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* -------------------- */
|
||||
/* close the connection */
|
||||
/* -------------------- */
|
||||
int BSclose(BS* bdt)
|
||||
{
|
||||
int verb,size,done;
|
||||
|
||||
/* send a close message out */
|
||||
if(BSsendHeader(bdt,BS_Close,0)<0)
|
||||
{
|
||||
fprintf(stderr,"BSclose: Cannot send close message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
done=0;
|
||||
|
||||
do
|
||||
{
|
||||
/* check response */
|
||||
if(BSreceiveHeader(bdt,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"BSclose: Close message response error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(verb)
|
||||
{
|
||||
case BS_Ok:
|
||||
done=1;
|
||||
break;
|
||||
case BS_Error:
|
||||
fprintf(stderr,"BSclose: Close rejected\n");
|
||||
return -1;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
while(done==0);
|
||||
|
||||
BSfreeBS(bdt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* make a listener socket for UDP - simple */
|
||||
/* --------------------------------------- */
|
||||
int BSopenListenerUDP(int Port)
|
||||
{
|
||||
int nsoc;
|
||||
struct sockaddr_in tsin;
|
||||
|
||||
tsin.sin_port=htons(Port);
|
||||
tsin.sin_family=AF_INET;
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((nsoc=socket(AF_INET,SOCK_DGRAM,BS_UDP))<0)
|
||||
{
|
||||
perror("BSopenListenerUDP: open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BSopenListenerUDP: local bind failed");
|
||||
close(nsoc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nsoc;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* make a listener socket for TCP - simple */
|
||||
/* --------------------------------------- */
|
||||
int BSopenListenerTCP(int Port)
|
||||
{
|
||||
int nsoc;
|
||||
struct sockaddr_in tsin;
|
||||
|
||||
memset ((void *)&tsin, 0, sizeof(struct sockaddr_in));
|
||||
tsin.sin_port=htons(Port);
|
||||
tsin.sin_family=htons(AF_INET);
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((nsoc=socket(AF_INET,SOCK_STREAM,BS_TCP))<0)
|
||||
{
|
||||
perror("BSopenListenerTCP: open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BSopenListenerTCP: local bind failed");
|
||||
close(nsoc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(nsoc,5);
|
||||
return nsoc;
|
||||
}
|
||||
|
||||
/* ------------------------------- */
|
||||
/* make BS from a socket - simple */
|
||||
/* ------------------------------- */
|
||||
BS* BSmakeBS(int soc)
|
||||
{
|
||||
BS* bdt;
|
||||
bdt=(BS*)malloc(sizeof(BS));
|
||||
bdt->soc=soc;
|
||||
bdt->remaining_send=0;
|
||||
bdt->remaining_recv=0;
|
||||
bdt->state=BSidle;
|
||||
return bdt;
|
||||
}
|
||||
|
||||
/* --------------------------- */
|
||||
/* free a BS and close socket */
|
||||
/* --------------------------- */
|
||||
int BSfreeBS(BS* bdt)
|
||||
{
|
||||
close(bdt->soc);
|
||||
free(bdt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
Next three function adjust the fields of the BSDATA structure.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
int BSgetAddressPort(BSDATA* info, char* ip_addr, int* dest_port)
|
||||
{
|
||||
char* name;
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin);
|
||||
|
||||
*dest_port=sin->sin_port;
|
||||
name=inet_ntoa(sin->sin_addr);
|
||||
strcpy(ip_addr,name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSsetAddressPort(BSDATA* info, char* ip_addr, int dest_port)
|
||||
{
|
||||
BSsetPort(info, dest_port);
|
||||
return BSsetAddress(info, ip_addr);
|
||||
}
|
||||
|
||||
int BSsetPort(BSDATA* info, int dest_port)
|
||||
{
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin);
|
||||
sin->sin_family=AF_INET;
|
||||
sin->sin_port=htons(dest_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSsetAddress(BSDATA* info, char* ip_addr)
|
||||
{
|
||||
struct hostent *pHostent;
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin);
|
||||
unsigned long addr;
|
||||
|
||||
#ifndef vxWorks
|
||||
/* Deal with the name -vs- IP number issue. */
|
||||
if (isdigit(ip_addr[0]))
|
||||
{
|
||||
#endif
|
||||
if((addr=inet_addr(ip_addr))==-1) return -1;
|
||||
#ifndef vxWorks
|
||||
}
|
||||
else
|
||||
{
|
||||
if((pHostent=gethostbyname(ip_addr))==NULL) return -1;
|
||||
memcpy((char*)&addr,pHostent->h_addr,sizeof(addr));
|
||||
}
|
||||
#endif
|
||||
|
||||
sin->sin_family=AF_INET;
|
||||
memcpy((char*)&(sin->sin_addr),(char*)&addr,sizeof(addr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/*
|
||||
All this function does is send a broadcast message and return the
|
||||
addressing info to the caller of a responder to the broadcast.
|
||||
|
||||
arguments:
|
||||
soc - broadcast socket to use for sending data
|
||||
trys - number of times to send if no response
|
||||
o_info - outgoing BSDATA, address/port info
|
||||
i_info - incoming BSDATA, address/port where response came from
|
||||
omsg/osize - outgoing message and size
|
||||
imsg/isize - incoming message and buffer size
|
||||
|
||||
Returns the number of bytes read.
|
||||
*/
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
int BSbroadcastTrans(int soc,int trys,BSDATA* o_info,BSDATA* i_info,
|
||||
void* omsg,int osize,void* imsg,int isize)
|
||||
{
|
||||
int i;
|
||||
int rc=0;
|
||||
|
||||
for(i=0;rc==0 && i<trys;i++)
|
||||
{
|
||||
/* send out the message */
|
||||
rc=BSwriteUDP(soc,o_info,omsg,osize);
|
||||
if(rc<0) return rc;
|
||||
|
||||
/* wait for a response */
|
||||
rc=BSreadUDP(soc,i_info,1,imsg,isize);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int BSbroadcast(int soc,BSDATA* o_info, void* omsg,int osize)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* send out the message */
|
||||
rc=BSwriteUDP(soc,o_info,omsg,osize);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*
|
||||
This function waits for a message and sends out an ACK when it gets one.
|
||||
addressing info to the caller of a responder to the broadcast.
|
||||
|
||||
Lots of arguments:
|
||||
|
||||
soc - The socket to send the message down.
|
||||
info - The socket information telling where the data read came from
|
||||
(returned to the user).
|
||||
tout - Timeout for read in seconds. 0=no wait, -1=wait forever.
|
||||
buf - Buffer to populate with read data.
|
||||
size - Size of the buf.
|
||||
|
||||
returns the length the read message, 0 is timeout, -1 is error
|
||||
*/
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
int BSreadUDP(int soc,BSDATA* info,BS_ULONG tout,void* buf,int size)
|
||||
{
|
||||
int mlen,rc;
|
||||
fd_set fds;
|
||||
struct timeval to;
|
||||
int error=0;
|
||||
|
||||
do
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc, &fds);
|
||||
|
||||
if(tout==-1)
|
||||
rc=select(FD_SETSIZE,&fds,NULL,NULL,NULL);
|
||||
else
|
||||
{
|
||||
to.tv_sec=tout;
|
||||
to.tv_usec=0;
|
||||
rc=select(FD_SETSIZE,&fds,NULL,NULL,&to);
|
||||
}
|
||||
|
||||
switch(rc)
|
||||
{
|
||||
case -1: /* bad */
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: break;
|
||||
default: error=-1; break;
|
||||
}
|
||||
break;
|
||||
case 0: /* timeout */
|
||||
break;
|
||||
default: /* data ready */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(rc<0 && error==0);
|
||||
|
||||
error=0;
|
||||
|
||||
if(rc>0)
|
||||
{
|
||||
error=0;
|
||||
do
|
||||
{
|
||||
info->len=sizeof(info->sin);
|
||||
mlen=recvfrom(soc,(char*)buf,size,0, &info->sin,&info->len);
|
||||
|
||||
if(mlen<0)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case EINTR: break;
|
||||
default: error=-1; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(mlen<0 && error==0);
|
||||
|
||||
if(mlen<0)
|
||||
rc=-1;
|
||||
else
|
||||
rc=mlen;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
Write a chuck of data to a UDP socket at an internet address
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int BSwriteDataUDP(int soc,int dest_port,char* ip_addr,void* buf,int size)
|
||||
{
|
||||
BSDATA data;
|
||||
|
||||
BSsetAddress(&data,ip_addr);
|
||||
BSsetPort(&data,dest_port);
|
||||
|
||||
return BSwriteUDP(soc,&data,buf,size);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
Write a chunk of data to a UDP socket using BSDATA.
|
||||
Arguments:
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int BSwriteUDP(int soc,BSDATA* info,void* obuf,int osize)
|
||||
{
|
||||
int mlen;
|
||||
|
||||
mlen=sendto(soc,(char*)obuf,osize,0,&info->sin,sizeof(info->sin));
|
||||
|
||||
return mlen;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
Write/Read a chuck of data to a UDP socket using BSDATA.
|
||||
Arguments:
|
||||
soc - socket to send message down and read from
|
||||
info - address/port to send message to
|
||||
obuf/osize - outgoing message and size of it.
|
||||
ibuf/isize - incoming message and size of the buffer.
|
||||
|
||||
Returns the number of bytes read, -1 for error.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int BStransUDP(int soc,BSDATA* info,void* obuf,int osize,void* ibuf,int isize)
|
||||
{
|
||||
int done,i,mlen,flen;
|
||||
struct sockaddr fromsin;
|
||||
fd_set fds;
|
||||
struct timeval tout;
|
||||
|
||||
done=0;
|
||||
mlen=0;
|
||||
|
||||
for(i=0;i<BS_RETRY_COUNT && done==0;i++)
|
||||
{
|
||||
mlen=sendto(soc,(char*)obuf,osize,0,&(info->sin),sizeof(info->sin));
|
||||
if(mlen<0)
|
||||
{
|
||||
printf("send failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tout.tv_sec=0;
|
||||
tout.tv_usec=200000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(soc,&fds);
|
||||
|
||||
switch(select(FD_SETSIZE,&fds,(fd_set*)0,(fd_set*)0,&tout))
|
||||
{
|
||||
case 0: /* timeout */ break;
|
||||
case -1: /* error */
|
||||
printf("select failed\n");
|
||||
return -1;
|
||||
default: /* data ready */
|
||||
flen=sizeof(fromsin);
|
||||
mlen=recvfrom(soc,(char*)ibuf,isize,0,&fromsin,&flen);
|
||||
if(mlen<0) return -1;
|
||||
done=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i>=BS_RETRY_COUNT) return 0;
|
||||
|
||||
return mlen;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
Open a broadcast socket and set port to a default.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int BSipBroadcastOpen(BSDATA* info, int default_dest_port)
|
||||
{
|
||||
struct sockaddr_in* sin;
|
||||
int soc;
|
||||
|
||||
sin=(struct sockaddr_in*)&(info->sin);
|
||||
|
||||
if( (soc=BSgetBroadcastSocket(0,sin)) <0) return -1;
|
||||
|
||||
sin->sin_port=htons(default_dest_port);
|
||||
|
||||
return soc;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
BSgetBroadcastSocket() - return a broadcast socket for a port, return
|
||||
a sockaddr also.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int BSgetBroadcastSocket(int port, struct sockaddr_in* sin)
|
||||
{
|
||||
int on=1;
|
||||
int soc;
|
||||
BS bs;
|
||||
|
||||
sin->sin_port=htons(port);
|
||||
sin->sin_family=AF_INET;
|
||||
sin->sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if( (soc=socket(AF_INET,SOCK_DGRAM,BS_UDP)) < 0 )
|
||||
{
|
||||
perror("socket create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsockopt(soc,SOL_SOCKET,SO_BROADCAST,(char*)&on,sizeof(on));
|
||||
|
||||
if( bind(soc,(struct sockaddr*)sin,sizeof(struct sockaddr_in)) < 0 )
|
||||
{
|
||||
perror("socket bind failed");
|
||||
close(soc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( BSgetBroadcastAddr(soc,(struct sockaddr*)sin) < 0 )
|
||||
return -1;
|
||||
|
||||
return soc;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
BSgetBroadcastAddr() - Determine the broadcast address, this is
|
||||
directly from the Sun Network Programmer's guide.
|
||||
*/
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static long BSgetBroadcastAddr(int soc, struct sockaddr* sin)
|
||||
{
|
||||
struct ifconf ifc;
|
||||
struct ifreq* ifr;
|
||||
struct ifreq* save;
|
||||
char buf[BUFSIZ];
|
||||
int tot,i;
|
||||
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if(ioctl(soc,SIOCGIFCONF,(int)&ifc) < 0)
|
||||
{ perror("ioctl SIOCGIFCONF failed"); return -1; }
|
||||
|
||||
ifr = ifc.ifc_req;
|
||||
tot = ifc.ifc_len/sizeof(struct ifreq);
|
||||
save=(struct ifreq*)NULL;
|
||||
i=0;
|
||||
|
||||
do
|
||||
{
|
||||
if(ifr[i].ifr_addr.sa_family==AF_INET)
|
||||
{
|
||||
if(ioctl(soc,SIOCGIFFLAGS,(int)&ifr[i])<0)
|
||||
{ perror("ioctl SIOCGIFFLAGS failed"); return -1; }
|
||||
|
||||
if( (ifr[i].ifr_flags&IFF_UP) &&
|
||||
!(ifr[i].ifr_flags&IFF_LOOPBACK) &&
|
||||
(ifr[i].ifr_flags&IFF_BROADCAST))
|
||||
{ save=&ifr[i]; }
|
||||
}
|
||||
} while( !save && ++i<tot );
|
||||
|
||||
if(save)
|
||||
{
|
||||
if(ioctl(soc,SIOCGIFBRDADDR,(int)save)<0)
|
||||
{ perror("ioctl SIOCGIFBRDADDR failed"); return -1; }
|
||||
|
||||
memcpy((char*)sin,(char*)&save->ifr_broadaddr,
|
||||
sizeof(save->ifr_broadaddr));
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
188
src/dbtools/BSlib.h
Normal file
188
src/dbtools/BSlib.h
Normal file
@@ -0,0 +1,188 @@
|
||||
#ifndef ___BS_H
|
||||
#define ___BS_H
|
||||
|
||||
/*
|
||||
* $Log$
|
||||
*/
|
||||
|
||||
/*
|
||||
Author: Jim Kowalkowski
|
||||
Date: 9/1/95
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* got from protocols(5) (cheated) or /etc/protocols */
|
||||
#define BS_UDP 17
|
||||
#define BS_TCP 6
|
||||
|
||||
/* server ports - in the user reserved area - above 50000 */
|
||||
#define BS_UDP_PORT 50296
|
||||
#define BS_TCP_PORT 50297
|
||||
|
||||
/* message types */
|
||||
#define BS_Ok 0
|
||||
#define BS_Error 1
|
||||
#define BS_Close 2
|
||||
#define BS_Ping 3
|
||||
#define BS_Done 4
|
||||
|
||||
#define BS_LAST_VERB 4
|
||||
#define BS_RETRY_COUNT 3
|
||||
|
||||
/* protocol states */
|
||||
typedef enum { BSidle,BSunbound,BSsData,BSrData,BSbad,BSeof } BSstate;
|
||||
|
||||
struct bs
|
||||
{
|
||||
int soc;
|
||||
int remaining_send;
|
||||
int remaining_recv;
|
||||
BSstate state;
|
||||
};
|
||||
typedef struct bs BS;
|
||||
|
||||
struct bs_udp_data
|
||||
{
|
||||
struct sockaddr sin;
|
||||
int len;
|
||||
};
|
||||
typedef struct bs_udp_data BSDATA;
|
||||
|
||||
struct BSmsgHead
|
||||
{
|
||||
unsigned short verb;
|
||||
unsigned long size;
|
||||
};
|
||||
typedef struct BSmsgHead BSmsgHead;
|
||||
|
||||
typedef unsigned long BS_ULONG;
|
||||
|
||||
#define BSgetSocket(BS) (BS->soc)
|
||||
#define BSgetResidualWrite(BS) (BS->remaining_send)
|
||||
#define BSgetResidualRead(BS) (BS->remaining_recv)
|
||||
#define BSgetProtoState(BS) (BS->state)
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Server functions:
|
||||
|
||||
BSopenListenerTCP:
|
||||
Open a socket locally bound to the bulk data transfer TCP server port.
|
||||
Set the socket up as a listener. Return the open socket.
|
||||
|
||||
BSopenListenerUDP:
|
||||
Open a socket locally bound to the bulk data transfer UDP server port.
|
||||
Return the open socket.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
int BSopenListenerTCP(int Port);
|
||||
int BSopenListenerUDP(int Port);
|
||||
int BSopenTCP(BSDATA*);
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Utilities functions:
|
||||
|
||||
BSmakeServer:
|
||||
Available under unix only. Put process in the background, disassociate
|
||||
process from controlling terminal and parent process, and prepare
|
||||
signals for reaping children spawned by the process.
|
||||
|
||||
BSserverClearSignals:
|
||||
Clear the signal handlers for a process, set them to default.
|
||||
|
||||
BSmakeBS:
|
||||
Allocate and initialize a BS from a socket.
|
||||
|
||||
BSfreeBS:
|
||||
Close the open socket and free the memory for the BS.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
#ifndef vxWorks
|
||||
int BSmakeServer(char** argv);
|
||||
int BSserverClearSignals();
|
||||
#endif
|
||||
|
||||
BS* BSmakeBS(int socket); /* make a BS from a socket */
|
||||
int BSfreeBS(BS* bdt); /* free a BS */
|
||||
|
||||
int BSgetBroadcastSocket(int port, struct sockaddr_in* sin);
|
||||
int BSipBroadcastOpen(BSDATA* info, int default_dest_port);
|
||||
int BSgetAddressPort(BSDATA* info,char* ip_addr, int* dest_port);
|
||||
int BSsetAddressPort(BSDATA* info,char* ip_addr, int dest_port);
|
||||
int BSsetAddress(BSDATA* info,char* ip_addr);
|
||||
int BSsetPort(BSDATA* info,int dest_port);
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
UDP functions:
|
||||
------------------------------------------------------------------------ */
|
||||
int BStransUDP(int soc,BSDATA* info,void* obuf,int osize,void* ibuf,int isize);
|
||||
int BSwriteUDP(int soc,BSDATA* info,void* obuf,int osize);
|
||||
int BSwriteDataUDP(int soc,int dest_port, char* ip_addr,void* obuf,int osize);
|
||||
int BSreadUDP(int soc,BSDATA* info,BS_ULONG tout,void* buf,int size);
|
||||
int BSbroadcast(int soc,BSDATA* info,void* buf,int size);
|
||||
int BSbroadcastTrans(int soc,int trys,BSDATA* o_info,BSDATA* i_info,
|
||||
void* obuf,int osize,void* ibuf,int isize);
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Client functions:
|
||||
|
||||
BSipOpen:
|
||||
Open a connection to an bulk data transfer given the IP address of the
|
||||
machine where the server exists. The returned BS is returned unbound,
|
||||
a connect must be issued before data transactions can take place.
|
||||
|
||||
BSclose:
|
||||
Completely close a connection to a server and free the BS.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
BS* BSipOpen(char* address, int port);
|
||||
BS* BSipOpenData(BSDATA* info);
|
||||
int BSclose(BS* bdt);
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Client and Server shared functions:
|
||||
|
||||
BSsendHeader:
|
||||
Send a message header out to a connect BS with command and message body
|
||||
size information.
|
||||
|
||||
BSsendData:
|
||||
Send a portion or all the message body out a connected BS. A header
|
||||
must have previously been sent with length information. The interface
|
||||
will only allow the amount of data specified in the header to be sent.
|
||||
|
||||
BSwrite:
|
||||
This call will block until all the data specified in the size parameter
|
||||
are sent down the socket.
|
||||
|
||||
BSread:
|
||||
This call will block until all the data specified in the size parameter
|
||||
is read from the socket.
|
||||
|
||||
BSreceiveHeader:
|
||||
Wait until a message header appears at the BS, return the action and
|
||||
remaining message body size.
|
||||
|
||||
BSreceiveData:
|
||||
Wait for a chunk or the entire body of a message to appear at the BS.
|
||||
Put the data into the buffer for a maximum size. Return the amount of
|
||||
data actually received, or zero if there is no data remaining for the
|
||||
current message.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
int BSsendHeader(BS* bdt, unsigned short verb, int size);
|
||||
int BSsendData(BS* bdt, void* buffer, int size);
|
||||
int BSreceiveHeader(BS* bdt, int* verb, int* size);
|
||||
int BSreceiveData(BS* bdt, void* buffer, int size);
|
||||
int BSread(int socket, void* buffer, int size);
|
||||
int BSwrite(int socket, void* buffer, int size);
|
||||
int BSflushOutput(BS* bdt);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,29 +2,45 @@ EPICS = ../../../..
|
||||
include Target.include
|
||||
include $(EPICS)/config/CONFIG_BASE
|
||||
|
||||
# USR_CFLAGS = -v
|
||||
|
||||
LEX = $(ELEX)
|
||||
YACC = $(EYACC)
|
||||
YACCOPT = -l
|
||||
LEXOPT = -L
|
||||
|
||||
SRCS.c = ../dbVarSub.c dbLoadTemplate_lex.c dbLoadTemplate.c \
|
||||
dbLoadRecords_lex.c dbLoadRecords.c
|
||||
dbLoadRecords_lex.c dbLoadRecords.c \
|
||||
../BSlib.c ../PVSserver.c ../rdbapplist.c ../rdbls.o
|
||||
|
||||
OBJS = dbVarSub.o dbLoadTemplate.o dbLoadRecords.o
|
||||
VAR_OBJS = dbVarSub.o dbLoadTemplate.o dbLoadRecords.o
|
||||
OBJS = $(VAR_OBJS) BSlib.o PVSserver.o rdbapplist.o rdbls.o
|
||||
|
||||
PROD = subtool dbLoadTemplate
|
||||
PROD = subtool dbLoadTemplate rdbls rdbapplist
|
||||
TARGETS = PVSserver
|
||||
|
||||
include $(EPICS)/config/RULES.Unix
|
||||
|
||||
dbLoadTemplate.o: dbLoadTemplate_lex.c
|
||||
dbLoadRecords.o: dbLoadRecords_lex.c
|
||||
|
||||
subtool: dbLoadTemplate.c dbLoadTemplate_lex.c dbVarSub.o
|
||||
$(RM) $@
|
||||
$(LINK.c) $(CFLAGS) -DSUB_TOOL -o subtool dbLoadTemplate.c dbVarSub.o -s
|
||||
PVSserver: PVSserver.o BSlib.o
|
||||
$(LINK.c) $(ARCH_DEP_LDLIBS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
dbLoadTemplate: $(OBJS)
|
||||
$(LINK.c) -o $@ $(OBJS) $(LDLIBS) -lDb
|
||||
rdbls: rdbls.o BSlib.o
|
||||
$(LINK.c) $(ARCH_DEP_LDLIBS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
rdbapplist: rdbapplist.o BSlib.o
|
||||
$(LINK.c) $(ARCH_DEP_LDLIBS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
subtool.o: dbLoadTemplate.c dbLoadTemplate_lex.c
|
||||
$(COMPILE.c) $(CFLAGS) -DSUB_TOOL -o $@ $<
|
||||
|
||||
subtool: subtool.o dbVarSub.o
|
||||
$(LINK.c) $(CFLAGS) -DSUB_TOOL -o $@ $^ -s
|
||||
|
||||
dbLoadTemplate: $(VAR_OBJS)
|
||||
$(LINK.c) -o $@ $^ $(LDLIBS) -lDb
|
||||
|
||||
clean::
|
||||
@$(RM) dbLoadTemplate_lex.c dbLoadTemplate.c dbLoadRecords_lex.c \
|
||||
|
||||
@@ -8,8 +8,9 @@ YACCOPT = -l
|
||||
LEXOPT = -L
|
||||
|
||||
SRCS.c = ../dbVarSub.c dbLoadTemplate_lex.c dbLoadTemplate.c \
|
||||
dbLoadRecords_lex.c dbLoadRecords.c
|
||||
LIBOBJS = dbVarSub.o dbLoadTemplate.o dbLoadRecords.o
|
||||
dbLoadRecords_lex.c dbLoadRecords.c ../BSlib.c ../PVSvx.c
|
||||
|
||||
LIBOBJS = dbVarSub.o dbLoadTemplate.o dbLoadRecords.o BSlib.o PVSvx.o
|
||||
|
||||
LIBNAME = dbSubs
|
||||
|
||||
|
||||
31
src/dbtools/PVS.h
Normal file
31
src/dbtools/PVS.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __PVS_H
|
||||
#define __PVS_H
|
||||
|
||||
#include "BSlib.h"
|
||||
|
||||
#define PVS_RETRY_COUNT 4
|
||||
#define PVS_TRANSFER_SIZE 1024
|
||||
#define PVS_UDP 17
|
||||
#define PVS_TCP 6
|
||||
#define PVS_UDP_PORT 50298
|
||||
#define PVS_TCP_PORT 50299
|
||||
#define PVS_UDP_CPORT 50300
|
||||
|
||||
#define PVS_Data (BS_LAST_VERB+1)
|
||||
#define PVS_Alive (BS_LAST_VERB+2)
|
||||
#define PVS_RecList (BS_LAST_VERB+3)
|
||||
#define PVS_AppList (BS_LAST_VERB+4)
|
||||
#define PVS_RecDump (BS_LAST_VERB+5)
|
||||
|
||||
#define PVS_LAST_VERB PVS_RecDump
|
||||
|
||||
struct pvs_info_packet
|
||||
{
|
||||
unsigned short cmd;
|
||||
char text[90];
|
||||
};
|
||||
typedef struct pvs_info_packet PVS_INFO_PACKET;
|
||||
|
||||
#define PVS_SET_CMD(pvs_info,command) (pvs_info)->cmd=htons(command)
|
||||
|
||||
#endif
|
||||
263
src/dbtools/PVSserver.c
Normal file
263
src/dbtools/PVSserver.c
Normal file
@@ -0,0 +1,263 @@
|
||||
|
||||
/* only runable on work station now */
|
||||
|
||||
#include "PVS.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct PVSnode
|
||||
{
|
||||
BSDATA info;
|
||||
int alive;
|
||||
struct PVSnode* next;
|
||||
};
|
||||
typedef struct PVSnode PVSNODE;
|
||||
|
||||
static PVSNODE* ioc_list = (PVSNODE*)NULL;
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname);
|
||||
|
||||
#ifndef PVS_SERVER_PROG
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
BSDATA info;
|
||||
int serv;
|
||||
int rc;
|
||||
|
||||
if(argc<4)
|
||||
{
|
||||
fprintf(stderr,"usage: %s IOC-name server-number [server-name]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
serv=atoi(argv[2]);
|
||||
BSsetAddress(&info,argv[1]);
|
||||
|
||||
if(serv>PVS_LAST_VERB)
|
||||
rc=read_pvs(&info,serv,argv[3]);
|
||||
else
|
||||
rc=read_pvs(&info,serv,(char*)NULL);
|
||||
|
||||
if(rc<0) fprintf(stderr,"read of data failed horribly\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
int soc,mlen;
|
||||
unsigned short buf,in_buf,ping;
|
||||
BSDATA info;
|
||||
PVSNODE* node;
|
||||
|
||||
if(BSmakeServer(argv)<0)
|
||||
{
|
||||
fprintf(stderr,"Cannot make into a server\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((soc=BSopenListenerUDP(PVS_UDP_PORT))<0)
|
||||
{
|
||||
fprintf(stderr,"Open of UDP listener socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf=htons(BS_Ok); /* always sends this out */
|
||||
ping=htons(BS_Ping); /* always sends this out */
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* wait forever until a message comes in */
|
||||
|
||||
mlen=BSreadUDP(soc,&info,7,&in_buf,sizeof(in_buf));
|
||||
|
||||
/* check for errors */
|
||||
switch(mlen)
|
||||
{
|
||||
case 0: /* timeout */
|
||||
printf("Why did a timeout occur?\n");
|
||||
/* send out a ping to each of the IOCs in the ioc_list */
|
||||
for(node=ioc_list;node;node=node->next)
|
||||
{
|
||||
mlen=BStransUDP(soc,&(node->info),&ping,sizeof(ping),
|
||||
&in_buf,sizeof(in_buf));
|
||||
|
||||
/* check for errors */
|
||||
switch(mlen)
|
||||
{
|
||||
case 0: /* timeout */
|
||||
printf("IOC dead\n");
|
||||
node->alive=0;
|
||||
break;
|
||||
case -1: /* error */
|
||||
printf("Communications failed\n");
|
||||
break;
|
||||
default: /* ok */
|
||||
if(node->alive==0)
|
||||
{
|
||||
switch(fork())
|
||||
{
|
||||
case -1: /* error */
|
||||
perror("fork failure");
|
||||
break;
|
||||
case 0: /* child */
|
||||
close(soc);
|
||||
BSserverClearSignals();
|
||||
sleep(1);
|
||||
if(read_pvs(&(node->info))==0)
|
||||
node->alive=1;
|
||||
default: /* parent */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case -1: /* error */
|
||||
fprintf(stderr,"Communications failure\n");
|
||||
break;
|
||||
default: /* ok */
|
||||
if(BSwriteUDP(soc,&info,&buf,sizeof(buf))<0)
|
||||
fprintf(stderr,"respone send failed\n");
|
||||
else
|
||||
{
|
||||
node=(PVSNODE*)malloc(sizeof(PVSNODE));
|
||||
node->alive=1;
|
||||
node->info=info;
|
||||
BSsetPort(&(node->info),PVS_UDP_CPORT);
|
||||
node->next=ioc_list;
|
||||
ioc_list=node;
|
||||
|
||||
switch(fork())
|
||||
{
|
||||
case -1: /* error */
|
||||
perror("fork failure");
|
||||
break;
|
||||
case 0: /* child */
|
||||
close(soc);
|
||||
BSserverClearSignals();
|
||||
sleep(1);
|
||||
return read_pvs(&info,PVS_RecList,NULL);
|
||||
default: /* parent */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(soc);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname)
|
||||
{
|
||||
BS* bs;
|
||||
int verb,size,done,len,i,port,rsize;
|
||||
char* buffer;
|
||||
char ip_from[40];
|
||||
FILE* fd;
|
||||
|
||||
BSgetAddressPort(info,ip_from,&port);
|
||||
|
||||
/* printf("IOC %s starting\n",ip_from); */
|
||||
|
||||
/* verify ioc not already added */
|
||||
if(access(ip_from,F_OK)==0)
|
||||
{
|
||||
/* delete the existing file for this IOC */
|
||||
unlink(ip_from);
|
||||
}
|
||||
|
||||
done=0;
|
||||
BSsetPort(info,PVS_TCP_PORT);
|
||||
|
||||
if((bs=BSipOpenData(info))==NULL)
|
||||
{
|
||||
fprintf(stderr,"Open of socket to IOC failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(serv>PVS_LAST_VERB)
|
||||
rsize=strlen(sname)+1;
|
||||
else
|
||||
rsize=0;
|
||||
|
||||
if(BSsendHeader(bs,serv,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"Command send failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(rsize>0)
|
||||
{
|
||||
if(BSsendData(bs,sname,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"send of command name failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PVS_SERVER_PROG
|
||||
if((fd=fopen(ip_from,"w"))==(FILE*)NULL)
|
||||
{
|
||||
fprintf(stderr,"Open of name file failed\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
fd=stdout;
|
||||
#endif
|
||||
|
||||
buffer=(char*)malloc(PVS_TRANSFER_SIZE+2);
|
||||
|
||||
while(done==0)
|
||||
{
|
||||
if(BSreceiveHeader(bs,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"Receive header failed\n");
|
||||
done=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(verb)
|
||||
{
|
||||
case PVS_Data: /* read a block of names */
|
||||
if((len=BSreceiveData(bs,buffer,size))<0)
|
||||
{
|
||||
fprintf(stderr,"Receive data failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
if(buffer[i]==' ') buffer[i]='\n';
|
||||
}
|
||||
buffer[len]='\n';
|
||||
buffer[len+1]='\0';
|
||||
|
||||
fputs(buffer,fd);
|
||||
}
|
||||
break;
|
||||
case BS_Done: /* transfers complete */
|
||||
BSclose(bs);
|
||||
done=-1;
|
||||
break;
|
||||
default:
|
||||
if(size>0) done=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PVS_SERVER_PROG
|
||||
fclose(fd);
|
||||
#endif
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
361
src/dbtools/PVSvx.c
Normal file
361
src/dbtools/PVSvx.c
Normal file
@@ -0,0 +1,361 @@
|
||||
|
||||
/* This file not really set up to run under Unix yet, just under vxWorks. */
|
||||
|
||||
#include "PVS.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <iv.h>
|
||||
#include <taskLib.h>
|
||||
#include <sysSymTbl.h>
|
||||
#include <sysLib.h>
|
||||
#include <symLib.h>
|
||||
#include <dbStaticLib.h>
|
||||
|
||||
extern struct dbBase *pdbBase;
|
||||
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
static void PVSserver(int want_annouce,char* name);
|
||||
static int PVSannouce(int want_annouce,char* name);
|
||||
static void handle_requests(BS* bs);
|
||||
static void handle_reclist(BS* bs);
|
||||
static void handle_applist(BS* bs);
|
||||
static void handle_recdump(BS* bs);
|
||||
static void handle_spylist(BS* bs);
|
||||
static void handle_tasklist(BS* bs);
|
||||
void PVS_test_server(BS* bs);
|
||||
|
||||
static char* names = (char*)NULL;
|
||||
static char* buffer = (char*)NULL;
|
||||
|
||||
#ifdef vxWorks
|
||||
int PVSstart(int want_annouce, char* name)
|
||||
#else
|
||||
int main(int argc,char** argv)
|
||||
#endif
|
||||
{
|
||||
#ifndef vxWorks
|
||||
char* name;
|
||||
int want_annouce;
|
||||
#endif
|
||||
|
||||
#ifndef vxWorks
|
||||
if(argc<3)
|
||||
{
|
||||
fprintf(stderr,"bad args\n");
|
||||
fprintf(stderr," usage: %s a_flag host_name\n",
|
||||
argv[0]);
|
||||
fprintf(stderr," where\n");
|
||||
fprintf(stderr," a_flag=0(want),1(don't want) to annouce boot\n");
|
||||
fprintf(stderr," host_name=PV master host (if one exists)\n");
|
||||
return -1;
|
||||
}
|
||||
name=argv[2];
|
||||
if(sscanf(argv[1],"%d",&want_annouce)<1)
|
||||
{
|
||||
fprintf(stderr,"bad a_flag\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
taskSpawn("PVS",150,VX_FP_TASK|VX_STDIO,5000,
|
||||
(FUNCPTR)PVSserver,want_annouce,(int)name,0,0,0,0,0,0,0,0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PVSannouce(int want_annouce,char* name)
|
||||
{
|
||||
int soc,mlen;
|
||||
PVS_INFO_PACKET buf,in_buf;
|
||||
BSDATA info,in_info;
|
||||
|
||||
if(want_annouce==0 && name)
|
||||
{
|
||||
if((soc=BSopenListenerUDP(0))<0)
|
||||
{
|
||||
printf("Open of UDP socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(BSsetAddressPort(&info,name,PVS_UDP_PORT)<0)
|
||||
{
|
||||
printf("Set send port failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PVS_SET_CMD(&buf,PVS_Alive);
|
||||
mlen=BStransUDP(soc,&info,&buf,sizeof(buf),&in_buf,sizeof(in_buf));
|
||||
|
||||
/* check for errors */
|
||||
switch(mlen)
|
||||
{
|
||||
case 0: /* timeout */
|
||||
printf("No server running on host\n");
|
||||
break;
|
||||
case -1: /* error */
|
||||
printf("Communications failed\n");
|
||||
break;
|
||||
default: /* ok */
|
||||
break;
|
||||
}
|
||||
|
||||
close(soc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PVSserver(int want_annouce,char* name)
|
||||
{
|
||||
fd_set fds,rfds;
|
||||
int tsoc,usoc,nsoc,len,s;
|
||||
struct sockaddr stemp;
|
||||
int stemp_len;
|
||||
PVS_INFO_PACKET buf;
|
||||
BSDATA info;
|
||||
BS* bs;
|
||||
|
||||
bs=(BS*)NULL;
|
||||
buffer=(char*)malloc(100); /* just make the buffer */
|
||||
names=(char*)malloc(PVS_TRANSFER_SIZE);
|
||||
|
||||
if((tsoc=BSopenListenerTCP(PVS_TCP_PORT))<0)
|
||||
{
|
||||
printf("PVSserver: Open of TCP listener socket failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if((usoc=BSopenListenerUDP(PVS_UDP_CPORT))<0)
|
||||
{
|
||||
printf("PVSserver: Open of UDP listener socket failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(tsoc,&fds);
|
||||
FD_SET(usoc,&fds);
|
||||
|
||||
PVSannouce(want_annouce,name);
|
||||
|
||||
while(1)
|
||||
{
|
||||
rfds=fds;
|
||||
if(select(FD_SETSIZE,&rfds,(fd_set*)NULL,(fd_set*)NULL,
|
||||
(struct timeval*)NULL)<0)
|
||||
{
|
||||
printf("PVSserver: Select failure\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(FD_ISSET(tsoc,&rfds))
|
||||
{
|
||||
/* handle the request here - single threaded server */
|
||||
|
||||
stemp_len=sizeof(stemp);
|
||||
if((nsoc=accept(tsoc,&stemp,&stemp_len))<0)
|
||||
printf("PVSserver: Bad accept\n");
|
||||
else
|
||||
{
|
||||
bs=BSmakeBS(nsoc);
|
||||
handle_requests(bs);
|
||||
BSfreeBS(bs);
|
||||
}
|
||||
}
|
||||
if(FD_ISSET(usoc,&rfds))
|
||||
{
|
||||
/* only pings will come in here for now */
|
||||
len=BSreadUDP(usoc,&info,0,&buf,sizeof(buf));
|
||||
if(len<=0)
|
||||
printf("PVSserver: UDP listener read failure\n");
|
||||
else
|
||||
{
|
||||
if(BSwriteUDP(usoc,&info,&buf,sizeof(buf))<0)
|
||||
printf("PVSserver: UDP listener ping write failure\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_reclist(BS* bs)
|
||||
{
|
||||
DBENTRY db;
|
||||
long rc;
|
||||
char* n;
|
||||
unsigned long names_len;
|
||||
int s;
|
||||
|
||||
dbInitEntry(pdbBase,&db);
|
||||
names_len=0;
|
||||
|
||||
for(rc=dbFirstRecdes(&db);rc==0;rc=dbNextRecdes(&db))
|
||||
{
|
||||
for(rc=dbFirstRecord(&db);rc==0;rc=dbNextRecord(&db))
|
||||
{
|
||||
/* collect the names util we excede the max */
|
||||
n=dbGetRecordName(&db);
|
||||
s=strlen(n);
|
||||
if((names_len+s)>PVS_TRANSFER_SIZE)
|
||||
{
|
||||
names[names_len++]='\0';
|
||||
if(BSsendHeader(bs,PVS_Data,names_len)<0)
|
||||
printf("PVSserver: data cmd failed\n");
|
||||
else
|
||||
{
|
||||
if(BSsendData(bs,names,names_len)<0)
|
||||
printf("PVSserver: data send failed\n");
|
||||
}
|
||||
names_len=0;
|
||||
}
|
||||
memcpy(&names[names_len],n,s);
|
||||
names_len+=s;
|
||||
names[names_len++]=' ';
|
||||
}
|
||||
}
|
||||
if(names_len>0)
|
||||
{
|
||||
names[names_len++]='\0';
|
||||
if(BSsendHeader(bs,PVS_Data,names_len)<0)
|
||||
printf("PVSserver: data cmd failed\n");
|
||||
else
|
||||
{
|
||||
if(BSsendData(bs,names,names_len)<0)
|
||||
printf("PVSserver: data send failed\n");
|
||||
}
|
||||
}
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
|
||||
static void handle_requests(BS* bs)
|
||||
{
|
||||
int verb,size,notdone,len;
|
||||
void (*func)(BS*);
|
||||
SYM_TYPE stype;
|
||||
|
||||
notdone=1;
|
||||
while(notdone)
|
||||
{
|
||||
/* at this point I should be getting a command */
|
||||
if(BSreceiveHeader(bs,&verb,&size)<0)
|
||||
{
|
||||
printf("PVSserver: receive header failed\n");
|
||||
notdone=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(verb)
|
||||
{
|
||||
case PVS_RecList: handle_reclist(bs); break;
|
||||
case PVS_AppList: handle_applist(bs); break;
|
||||
case PVS_RecDump: handle_recdump(bs); break;
|
||||
case BS_Close:
|
||||
BSsendHeader(bs,BS_Ok,0);
|
||||
notdone=0;
|
||||
break;
|
||||
case PVS_Data: break;
|
||||
case PVS_Alive: break;
|
||||
case BS_Ok: break;
|
||||
case BS_Error: break;
|
||||
case BS_Ping: break;
|
||||
case BS_Done: break;
|
||||
default:
|
||||
/* custom service */
|
||||
if(size>0)
|
||||
{
|
||||
/* this should be the name of the service */
|
||||
/* look up the symbol name in buffer and call as
|
||||
subroutine, passing it the BS */
|
||||
|
||||
len=BSreceiveData(bs,&buffer[1],size);
|
||||
switch(len)
|
||||
{
|
||||
case 0: /* timeout */ notdone=0; break;
|
||||
case -1: /* error */ notdone=0; break;
|
||||
default:
|
||||
buffer[0]='_';
|
||||
|
||||
if(strncmp(buffer,"_PVS",4)==0)
|
||||
{
|
||||
if(symFindByName(sysSymTbl,buffer,
|
||||
(char**)&func,&stype)==ERROR)
|
||||
func=(void (*)(BS*))NULL;
|
||||
|
||||
if(func)
|
||||
func(bs);
|
||||
else
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
else
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("PVSserver: unknown command received\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
struct dbnode
|
||||
{
|
||||
char* name;
|
||||
struct dbnode* next;
|
||||
};
|
||||
typedef struct dbnode DBNODE;
|
||||
|
||||
extern DBNODE* DbApplList;
|
||||
|
||||
void handle_applist(BS* bs)
|
||||
{
|
||||
DBNODE* n;
|
||||
int size,len;
|
||||
|
||||
len=0;
|
||||
for(n=DbApplList;n;n=n->next)
|
||||
{
|
||||
len=strlen(n->name)+1;
|
||||
|
||||
if(BSsendHeader(bs,PVS_Data,len)<0)
|
||||
printf("PVSserver: data cmd failed\n");
|
||||
else
|
||||
{
|
||||
if(BSsendData(bs,n->name,len)<0)
|
||||
printf("PVSserver: data send failed\n");
|
||||
}
|
||||
}
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
|
||||
void handle_recdump(BS* bs)
|
||||
{
|
||||
printf("RecDump server invoked\n");
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
|
||||
void PVS_test_server(BS* bs)
|
||||
{
|
||||
printf("PVS_test_server invoked\n");
|
||||
BSsendHeader(bs,BS_Done,0);
|
||||
}
|
||||
|
||||
void handle_spylist(BS* bs)
|
||||
{
|
||||
printf("PVS spy list server invoked\n");
|
||||
}
|
||||
|
||||
void handle_tasklist(BS* bs)
|
||||
{
|
||||
printf("PVS task list server invoked\n");
|
||||
}
|
||||
@@ -49,6 +49,17 @@ static char subst_buffer[VAR_MAX_SUB_SIZE];
|
||||
static int subst_used;
|
||||
static int line_num;
|
||||
|
||||
struct db_app_node
|
||||
{
|
||||
char* name;
|
||||
struct db_app_node* next;
|
||||
};
|
||||
typedef struct db_app_node DB_APP_NODE;
|
||||
|
||||
DB_APP_NODE* DbApplList=(DB_APP_NODE*)NULL;
|
||||
static DB_APP_NODE* DbCurrentListHead=(DB_APP_NODE*)NULL;
|
||||
static DB_APP_NODE* DbCurrentListTail=(DB_APP_NODE*)NULL;
|
||||
|
||||
static int yyerror();
|
||||
static void sub_pvname(char*,char*);
|
||||
|
||||
@@ -65,8 +76,9 @@ extern struct dbBase *pdbBase;
|
||||
%token <Str> WORD VALUE
|
||||
%token <Str> FIELD
|
||||
%left O_BRACE C_BRACE O_PAREN C_PAREN
|
||||
%left DATABASE CONTAINER RECORD
|
||||
%left NOWHERE
|
||||
%left DATABASE RECORD
|
||||
%left NOWHERE
|
||||
%token APPL
|
||||
|
||||
%union
|
||||
{
|
||||
@@ -105,18 +117,39 @@ n_body: O_BRACE records C_BRACE
|
||||
;
|
||||
|
||||
db_components: /* null */
|
||||
| db_components container
|
||||
| db_components applic
|
||||
| db_components record
|
||||
;
|
||||
|
||||
container: CONTAINER c_head c_body
|
||||
;
|
||||
applic: APPL O_PAREN VALUE C_PAREN
|
||||
{
|
||||
DB_APP_NODE* an=(DB_APP_NODE*)malloc(sizeof(DB_APP_NODE*));
|
||||
|
||||
c_head: O_PAREN WORD C_PAREN
|
||||
{ free($2); }
|
||||
;
|
||||
if(subst_used)
|
||||
{
|
||||
strcpy(subst_buffer,$<Str>3);
|
||||
if(dbDoSubst(subst_buffer,sizeof(subst_buffer),NULL)!=0)
|
||||
fprintf(stderr,"dbDoSubst failed\n");
|
||||
#ifdef vxWorks
|
||||
an->name=strdup(subst_buffer);
|
||||
free($3);
|
||||
#else
|
||||
printf("\napplication(\"%s\")\n",subst_buffer);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef vxWorks
|
||||
an->name=$<Str>3;
|
||||
#else
|
||||
printf("\napplication(\"%s\")\n",$<Str>3);
|
||||
#endif
|
||||
}
|
||||
if(DbCurrentListHead==(DB_APP_NODE*)NULL) DbCurrentListTail=an;
|
||||
|
||||
c_body: O_BRACE db_components C_BRACE
|
||||
an->next=DbCurrentListHead;
|
||||
DbCurrentListHead=an;
|
||||
}
|
||||
;
|
||||
|
||||
records: /* null */
|
||||
@@ -190,13 +223,24 @@ field: FIELD O_PAREN WORD COMMA VALUE C_PAREN
|
||||
static int yyerror(str)
|
||||
char *str;
|
||||
{ fprintf(stderr,"db file parse, Error line %d : %s\n",line_num, yytext); }
|
||||
|
||||
#ifdef vxWorks
|
||||
static char* strdup(char* x)
|
||||
{
|
||||
char* c;
|
||||
c=(char*)malloc(strlen(x)+1);
|
||||
strcpy(c,x);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int is_not_inited = 1;
|
||||
|
||||
int dbLoadRecords(char* pfilename, char* pattern, char* container)
|
||||
int dbLoadRecords(char* pfilename, char* pattern)
|
||||
{
|
||||
FILE* fp;
|
||||
long status;
|
||||
DB_APP_NODE* an;
|
||||
|
||||
#ifdef vxWorks
|
||||
if(pdbBase==NULL)
|
||||
@@ -243,6 +287,21 @@ int dbLoadRecords(char* pfilename, char* pattern, char* container)
|
||||
if(subst_used) dbFreeSubst();
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(DbCurrentListHead==(DB_APP_NODE*)NULL)
|
||||
{
|
||||
/* set up a default list to put on the master application list */
|
||||
DbCurrentListHead=(DB_APP_NODE*)malloc(sizeof(DB_APP_NODE));
|
||||
DbCurrentListTail=DbCurrentListHead;
|
||||
DbCurrentListHead->name=strdup(pfilename);
|
||||
DbCurrentListHead->next=(DB_APP_NODE*)NULL;
|
||||
}
|
||||
|
||||
DbCurrentListTail->next=DbApplList;
|
||||
DbApplList=DbCurrentListHead;
|
||||
DbCurrentListHead=(DB_APP_NODE*)NULL;
|
||||
DbCurrentListTail=(DB_APP_NODE*)NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -276,3 +335,14 @@ static void sub_pvname(char* type, char* name)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef vxWorks
|
||||
int dbAppList()
|
||||
{
|
||||
DB_APP_NODE* an;
|
||||
|
||||
for(an=DbApplList;an;an=an->next)
|
||||
printf("%s\n",an->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12,9 +12,9 @@ value [a-zA-Z0-9_\,\^~\./\*#\[\]%: ;!|\'\-&\(\)@\?\+<>=\$\{\}]
|
||||
"field" { return(FIELD); }
|
||||
"grecord" { return(RECORD); }
|
||||
"record" { return(RECORD); }
|
||||
"container" { return(CONTAINER); }
|
||||
"database" { return(DATABASE); }
|
||||
"nowhere" { return(NOWHERE); }
|
||||
"application" { return(APPL); }
|
||||
|
||||
\"{value}*\" { yylval.Str=(char *)malloc(strlen(yytext)+1); strcpy(yylval.Str,yytext+1); yylval.Str[strlen(yylval.Str)-1] = '\0'; return(VALUE); }
|
||||
|
||||
|
||||
@@ -276,9 +276,11 @@ sub_pat: WORD EQUALS WORD
|
||||
|
||||
#include "dbLoadTemplate_lex.c"
|
||||
|
||||
static int yyerror(str)
|
||||
char *str;
|
||||
{ fprintf(stderr,"templ file parse, Error line %d : %s\n",line_num, yytext); }
|
||||
static int yyerror(char* str)
|
||||
{
|
||||
fprintf(stderr,"Substitution file parse error\n");
|
||||
fprintf(stderr,"line %d:%s\n",line_num,yytext);
|
||||
}
|
||||
|
||||
static int is_not_inited = 1;
|
||||
|
||||
|
||||
116
src/dbtools/rdbapplist.c
Normal file
116
src/dbtools/rdbapplist.c
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
/* only runable on work station now */
|
||||
|
||||
#include "PVS.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname);
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
BSDATA info;
|
||||
int rc;
|
||||
|
||||
if(argc<2)
|
||||
{
|
||||
fprintf(stderr,"usage: %s IOC-ip-address\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(BSsetAddress(&info,argv[1])<0)
|
||||
{
|
||||
fprintf(stderr,"Cannot determine address for %s\n",argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc=read_pvs(&info,PVS_AppList,(char*)NULL);
|
||||
|
||||
if(rc<0) fprintf(stderr,"read of data failed horribly\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname)
|
||||
{
|
||||
BS* bs;
|
||||
int verb,size,done,len,i,port,rsize;
|
||||
char* buffer;
|
||||
char ip_from[40];
|
||||
FILE* fd;
|
||||
|
||||
BSgetAddressPort(info,ip_from,&port);
|
||||
|
||||
/* verify ioc not already added */
|
||||
if(access(ip_from,F_OK)==0)
|
||||
{
|
||||
/* delete the existing file for this IOC */
|
||||
unlink(ip_from);
|
||||
}
|
||||
|
||||
done=0;
|
||||
BSsetPort(info,PVS_TCP_PORT);
|
||||
|
||||
if((bs=BSipOpenData(info))==NULL)
|
||||
{
|
||||
fprintf(stderr,"Open of socket to IOC failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(serv>PVS_LAST_VERB)
|
||||
rsize=strlen(sname)+1;
|
||||
else
|
||||
rsize=0;
|
||||
|
||||
if(BSsendHeader(bs,serv,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"Command send failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(rsize>0)
|
||||
{
|
||||
if(BSsendData(bs,sname,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"send of command name failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd=stdout;
|
||||
buffer=(char*)malloc(PVS_TRANSFER_SIZE+2);
|
||||
|
||||
while(done==0)
|
||||
{
|
||||
if(BSreceiveHeader(bs,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"Receive header failed\n");
|
||||
done=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(verb)
|
||||
{
|
||||
case PVS_Data: /* read a block of names */
|
||||
if((len=BSreceiveData(bs,buffer,size))<0)
|
||||
fprintf(stderr,"Receive data failed\n");
|
||||
else
|
||||
fputs(buffer,fd);
|
||||
fputc('\n',fd);
|
||||
break;
|
||||
case BS_Done: /* transfers complete */
|
||||
BSclose(bs);
|
||||
done=-1;
|
||||
break;
|
||||
default:
|
||||
if(size>0) done=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
128
src/dbtools/rdbls.c
Normal file
128
src/dbtools/rdbls.c
Normal file
@@ -0,0 +1,128 @@
|
||||
|
||||
/* only runable on work station now */
|
||||
|
||||
#include "PVS.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname);
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
BSDATA info;
|
||||
int rc;
|
||||
|
||||
if(argc<2)
|
||||
{
|
||||
fprintf(stderr,"usage: %s IOC-ip-address\n",argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(BSsetAddress(&info,argv[1])<0)
|
||||
{
|
||||
fprintf(stderr,"Cannot determine address for %s\n",argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc=read_pvs(&info,PVS_RecList,(char*)NULL);
|
||||
|
||||
if(rc<0) fprintf(stderr,"read of data failed horribly\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_pvs(BSDATA* info,int serv,char* sname)
|
||||
{
|
||||
BS* bs;
|
||||
int verb,size,done,len,i,port,rsize;
|
||||
char* buffer;
|
||||
char ip_from[40];
|
||||
FILE* fd;
|
||||
|
||||
BSgetAddressPort(info,ip_from,&port);
|
||||
|
||||
/* printf("IOC %s starting\n",ip_from); */
|
||||
|
||||
/* verify ioc not already added */
|
||||
if(access(ip_from,F_OK)==0)
|
||||
{
|
||||
/* delete the existing file for this IOC */
|
||||
unlink(ip_from);
|
||||
}
|
||||
|
||||
done=0;
|
||||
BSsetPort(info,PVS_TCP_PORT);
|
||||
|
||||
if((bs=BSipOpenData(info))==NULL)
|
||||
{
|
||||
fprintf(stderr,"Open of socket to IOC failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(serv>PVS_LAST_VERB)
|
||||
rsize=strlen(sname)+1;
|
||||
else
|
||||
rsize=0;
|
||||
|
||||
if(BSsendHeader(bs,serv,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"Command send failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(rsize>0)
|
||||
{
|
||||
if(BSsendData(bs,sname,rsize)<0)
|
||||
{
|
||||
fprintf(stderr,"send of command name failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd=stdout;
|
||||
buffer=(char*)malloc(PVS_TRANSFER_SIZE+2);
|
||||
|
||||
while(done==0)
|
||||
{
|
||||
if(BSreceiveHeader(bs,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"Receive header failed\n");
|
||||
done=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(verb)
|
||||
{
|
||||
case PVS_Data: /* read a block of names */
|
||||
if((len=BSreceiveData(bs,buffer,size))<0)
|
||||
{
|
||||
fprintf(stderr,"Receive data failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
if(buffer[i]==' ') buffer[i]='\n';
|
||||
}
|
||||
buffer[len]='\n';
|
||||
buffer[len+1]='\0';
|
||||
|
||||
fputs(buffer,fd);
|
||||
}
|
||||
break;
|
||||
case BS_Done: /* transfers complete */
|
||||
BSclose(bs);
|
||||
done=-1;
|
||||
break;
|
||||
default:
|
||||
if(size>0) done=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
* This driver currently needs work on error message generation.
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1995/03/30 19:34:56 jba
|
||||
* Seperated drv files into ansi and old dirs. Added combine dir.
|
||||
*
|
||||
* Revision 1.37 1995/03/24 21:24:25 winans
|
||||
* Probable race condition in PEP TX task. Moved the final transmission
|
||||
* byte assignment into the point where the busy list is locked. This
|
||||
@@ -2532,6 +2535,11 @@ STATIC int pepTxTask(int link)
|
||||
if (bbDebug)
|
||||
printf("pepTxTask(%d): RAC_RESET_SLAVE sent\n", link);
|
||||
|
||||
pBBLink[link]->l.PepLink.bbRegs->stat_ctl = *txMsg;
|
||||
if (bbDebug>30)
|
||||
printf("pepTxTask(%d): outputting last byte %2.2X\n",
|
||||
link,*txMsg);
|
||||
|
||||
pnode->status = BB_OK;
|
||||
|
||||
if (pnode->finishProc != NULL) {
|
||||
|
||||
@@ -122,6 +122,9 @@
|
||||
* for the DMA buffer that is appropriate.
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.1 1995/03/30 19:35:14 jba
|
||||
* Seperated drv files into ansi and old dirs. Added combine dir.
|
||||
*
|
||||
* Revision 1.22 1995/01/06 17:03:43 winans
|
||||
* Added some ifdef'd out test code to see if the end of the sequence program
|
||||
* could be updated to NOT cause an extra sample from port zero to be taken
|
||||
@@ -181,7 +184,7 @@ static char *SccsId = "$Id$";
|
||||
#define ADVANCE_HOLD 0xC0
|
||||
#define RESTART 0x00
|
||||
|
||||
/* analogic 2502 memory structure */
|
||||
/* Analogic 2502 memory structure */
|
||||
struct dvx_2502
|
||||
{
|
||||
unsigned short dev_id; /* device id code (CFF5) */
|
||||
@@ -205,7 +208,7 @@ struct dvx_inbuf
|
||||
short *data; /* data buffer */
|
||||
};
|
||||
|
||||
/* analogic 2502 control structure */
|
||||
/* Analogic 2502 control structure */
|
||||
struct dvx_rec
|
||||
{
|
||||
struct dvx_2502 *pdvx2502; /* pointer to device registers */
|
||||
@@ -224,6 +227,8 @@ struct dvx_rec
|
||||
|
||||
int RearmMode; /* zero if auto-rearm, else manual */
|
||||
|
||||
unsigned short ScanRate; /* User settable scan rate */
|
||||
|
||||
IOSCANPVT *pioscanpvt;
|
||||
};
|
||||
|
||||
@@ -304,19 +309,19 @@ struct {
|
||||
static struct dvx_rec dvx[MAX_DVX_CARDS] = {
|
||||
{ NULL, NULL, NULL, -1, -1, -1, -1, -1, 128, 0, {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}
|
||||
,{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
0 , NULL
|
||||
0 , DVX_DRATE, NULL
|
||||
},
|
||||
{ NULL, NULL, NULL, -1, -1, -1, -1, -1, 128, 0, {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}
|
||||
,{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
0, NULL
|
||||
0, DVX_DRATE, NULL
|
||||
},
|
||||
{ NULL, NULL, NULL, -1, -1, -1, -1, -1, 128, 0, {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}
|
||||
,{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
0, NULL
|
||||
0, DVX_DRATE, NULL
|
||||
},
|
||||
{ NULL, NULL, NULL, -1, -1, -1, -1, -1, 128, 0, {0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}
|
||||
,{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
0, NULL
|
||||
0, DVX_DRATE, NULL
|
||||
}
|
||||
};
|
||||
|
||||
@@ -425,6 +430,16 @@ dvx_int(struct dvx_rec *dvxptr)
|
||||
cptr->csr = dvxptr->csr_shadow;
|
||||
}
|
||||
|
||||
int dvx_SetScanRate(int Card, unsigned int Rate)
|
||||
{
|
||||
/* make sure hardware exists */
|
||||
if ((Card >= ai_num_cards[DVX2502]) || (Card < 0))
|
||||
return(-1);
|
||||
|
||||
dvx[Card].ScanRate = Rate & 0x0000FFFF;
|
||||
dvx[Card].pdvx2502->samp_rate = dvx[Card].ScanRate;
|
||||
return(0);
|
||||
}
|
||||
int dvx_RearmModeSet(int card, int mode)
|
||||
{
|
||||
/* make sure hardware exists */
|
||||
@@ -672,7 +687,11 @@ LOCAL long dvx_driver_init(void)
|
||||
/*
|
||||
* set scan rate and enable external start
|
||||
*/
|
||||
#if 0
|
||||
pDvxA16->samp_rate = DVX_DRATE; /* scan rate of 184 KHz */
|
||||
#else
|
||||
pDvxA16->samp_rate = dvx[i].ScanRate; /* Set scan rate */
|
||||
#endif
|
||||
dvx[i].csr_shadow |= CSR_M_ESTART; /* enable ext start (shadow csr) */
|
||||
pDvxA16->csr = dvx[i].csr_shadow; /* enable external start */
|
||||
dvx[i].mode = RUN_MODE; /* ready to aquire data */
|
||||
@@ -904,12 +923,17 @@ int sramld(int card)
|
||||
#endif
|
||||
|
||||
/* set scan rate and run it once */
|
||||
#if 0
|
||||
dvx[card].pdvx2502->samp_rate = DVX_DRATE;
|
||||
#else
|
||||
dvx[card].pdvx2502->samp_rate = dvx[card].ScanRate; /* Set scan rate */
|
||||
#endif
|
||||
dvx[card].pdvx2502->csr = dvx[card].csr_shadow | CSR_M_START;
|
||||
taskDelay(sysClkRateGet()); /* let scan run */
|
||||
dvx[card].pdvx2502->csr = dvx[card].csr_shadow; /* restore csr */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dvx_driver
|
||||
*
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
# Experimental Physics and Industrial Control System (EPICS)
|
||||
#
|
||||
# $Log$
|
||||
# Revision 1.1 1995/08/17 20:22:09 jba
|
||||
# Moved bldEnvData,blderrSymTbl, makeStatTbl to libCom dir
|
||||
#
|
||||
# Revision 1.3 1995/08/14 19:27:24 jhill
|
||||
# extern => epicsShareExtern
|
||||
#
|
||||
@@ -34,7 +37,7 @@ TOOL=`basename $0`
|
||||
|
||||
# Start by creating a list of the ENV_PARAM declarations
|
||||
PARAMS=`sed -n -e 's/;//' \
|
||||
-e 's/^[ ]*epicsShareExtern[ ][ ]*ENV_PARAM[ ][ ]*//p' \
|
||||
-e 's/^[ ]*epicsShareExtern[ ][ ]*ENV_PARAM[ ][ ]*//p' \
|
||||
${SRC}`
|
||||
|
||||
# Create a new header file
|
||||
@@ -85,7 +88,7 @@ done
|
||||
# Now create an array pointing to all parameters
|
||||
cat >>${OBJ} <<!EOF
|
||||
|
||||
ENV_PARAM* env_param_list[] = {
|
||||
ENV_PARAM* env_param_list[EPICS_ENV_VARIABLE_COUNT+1] = {
|
||||
!EOF
|
||||
|
||||
# Contents are the addresses of each parameter
|
||||
|
||||
@@ -53,7 +53,7 @@ HOST_ARCH=$2
|
||||
MAKE=$3
|
||||
|
||||
case $HOST_ARCH in
|
||||
alpha | hp700)
|
||||
alpha | hp700 | Linux)
|
||||
# Use gcc if it can be found, or makedepend
|
||||
|
||||
GCC=`which gcc`
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
16
src/libCom/env/envSubr.c
vendored
16
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
|
||||
@@ -73,6 +75,7 @@
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef vxWorks
|
||||
@@ -84,10 +87,6 @@
|
||||
#include <envDefs.h>
|
||||
#include <errMdef.h>
|
||||
|
||||
/*
|
||||
* for VMS
|
||||
*/
|
||||
unsigned long inet_addr (char *);
|
||||
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
@@ -198,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;
|
||||
}
|
||||
@@ -253,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;
|
||||
}
|
||||
|
||||
@@ -306,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
|
||||
@@ -73,6 +75,7 @@
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef vxWorks
|
||||
@@ -84,10 +87,6 @@
|
||||
#include <envDefs.h>
|
||||
#include <errMdef.h>
|
||||
|
||||
/*
|
||||
* for VMS
|
||||
*/
|
||||
unsigned long inet_addr (char *);
|
||||
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
@@ -198,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;
|
||||
}
|
||||
@@ -253,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;
|
||||
}
|
||||
|
||||
@@ -306,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:
|
||||
*
|
||||
|
||||
@@ -51,6 +51,7 @@ DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000).
|
||||
* .01 04-07-94 mrk Initial Implementation
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#endif
|
||||
|
||||
@@ -51,6 +51,7 @@ DEVELOPMENT CENTER AT ARGONNE NATIONAL LABORATORY (708-252-2000).
|
||||
* .01 04-07-94 mrk Initial Implementation
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,50 +45,11 @@ SRCS.c += ../recSubArray.c
|
||||
SRCS.c += ../recTimer.c
|
||||
SRCS.c += ../recWait.c
|
||||
SRCS.c += ../recWaitCa.c
|
||||
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 += recWaveform.o
|
||||
LIBOBJS = $(SRCS.c:../%.c=%.o)
|
||||
|
||||
LIBNAME = recSup
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct aaiRecord *paai=(struct aaiRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,paai->egu,sizeof(paai->egu));
|
||||
strncpy(units,paai->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct aaoRecord *paao=(struct aaoRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,paao->egu,sizeof(paao->egu));
|
||||
strncpy(units,paao->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct aiRecord *pai=(struct aiRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pai->egu,sizeof(pai->egu));
|
||||
strncpy(units,pai->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct aoRecord *pao=(struct aoRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pao->egu,sizeof(pao->egu));
|
||||
strncpy(units,pao->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct calcRecord *pcalc=(struct calcRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pcalc->egu,sizeof(pcalc->egu));
|
||||
strncpy(units,pcalc->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct compressRecord *pcompress=(struct compressRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pcompress->egu,sizeof(pcompress->egu));
|
||||
strncpy(units,pcompress->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct dfanoutRecord *pdfanout=(struct dfanoutRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pdfanout->egu,sizeof(pdfanout->egu));
|
||||
strncpy(units,pdfanout->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
542
src/rec/recDynLink.c
Normal file
542
src/rec/recDynLink.c
Normal file
@@ -0,0 +1,542 @@
|
||||
/*recDynLink.c*/
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <rngLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <semLib.h>
|
||||
#include <sysLib.h>
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <taskwd.h>
|
||||
#include <fast_lock.h>
|
||||
#include <db_access.h>
|
||||
#include <cadef.h>
|
||||
#include <caerr.h>
|
||||
#include <caeventmask.h>
|
||||
#include <calink.h>
|
||||
#include <tsDefs.h>
|
||||
#include <task_params.h>
|
||||
#include <recDynLink.h>
|
||||
|
||||
|
||||
/*Definitions to map between old and new database access*/
|
||||
/*because we are using CA must include db_access.h*/
|
||||
/* new field types */
|
||||
#define newDBF_STRING 0
|
||||
#define newDBF_CHAR 1
|
||||
#define newDBF_UCHAR 2
|
||||
#define newDBF_SHORT 3
|
||||
#define newDBF_USHORT 4
|
||||
#define newDBF_LONG 5
|
||||
#define newDBF_ULONG 6
|
||||
#define newDBF_FLOAT 7
|
||||
#define newDBF_DOUBLE 8
|
||||
#define newDBF_ENUM 9
|
||||
|
||||
/* new data request buffer types */
|
||||
#define newDBR_STRING newDBF_STRING
|
||||
#define newDBR_CHAR newDBF_CHAR
|
||||
#define newDBR_UCHAR newDBF_UCHAR
|
||||
#define newDBR_SHORT newDBF_SHORT
|
||||
#define newDBR_USHORT newDBF_USHORT
|
||||
#define newDBR_LONG newDBF_LONG
|
||||
#define newDBR_ULONG newDBF_ULONG
|
||||
#define newDBR_FLOAT newDBF_FLOAT
|
||||
#define newDBR_DOUBLE newDBF_DOUBLE
|
||||
#define newDBR_ENUM newDBF_ENUM
|
||||
#define VALID_newDB_REQ(x) ((x >= 0) && (x <= newDBR_ENUM))
|
||||
static short mapOldToNew[DBF_DOUBLE+1] = {
|
||||
newDBR_STRING,newDBR_SHORT,newDBR_FLOAT,newDBR_ENUM,
|
||||
newDBR_CHAR,newDBR_LONG,newDBR_DOUBLE};
|
||||
static short mapNewToOld[newDBR_ENUM+1] = {
|
||||
DBF_STRING,DBF_CHAR,DBF_CHAR,DBF_SHORT,DBF_SHORT,
|
||||
DBF_LONG,DBF_LONG,DBF_FLOAT,DBF_DOUBLE,DBF_ENUM};
|
||||
|
||||
extern int interruptAccept;
|
||||
|
||||
int recDynLinkQsize = 256;
|
||||
|
||||
LOCAL int inpTaskId=0;
|
||||
LOCAL int outTaskId=0;
|
||||
LOCAL RING_ID inpRingQ;;
|
||||
LOCAL RING_ID outRingQ;;
|
||||
LOCAL SEM_ID wakeUpSem;
|
||||
|
||||
typedef enum{cmdSearch,cmdClear,cmdPut} cmdType;
|
||||
typedef enum{ioInput,ioOutput}ioType;
|
||||
typedef enum{stateStarting,stateSearching,stateGetting,stateConnected}stateType;
|
||||
|
||||
typedef struct dynLinkPvt{
|
||||
FAST_LOCK lock;
|
||||
char *pvname;
|
||||
chid chid;
|
||||
evid evid;
|
||||
recDynCallback searchCallback;
|
||||
recDynCallback monitorCallback;
|
||||
TS_STAMP timestamp;
|
||||
short status;
|
||||
short severity;
|
||||
void *pbuffer;
|
||||
size_t nRequest;
|
||||
short dbrType;
|
||||
double graphicLow,graphHigh;
|
||||
double controlLow,controlHigh;
|
||||
char units[MAX_UNITS_SIZE];
|
||||
short precision;
|
||||
ioType io;
|
||||
stateType state;
|
||||
short scalar;
|
||||
} dynLinkPvt;
|
||||
|
||||
/*For cmdClear data is chid. For all other commands precDynLink*/
|
||||
typedef struct {
|
||||
union {
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
}data;
|
||||
cmdType cmd;
|
||||
}ringBufCmd;
|
||||
|
||||
LOCAL void recDynLinkStartInput(void);
|
||||
LOCAL void recDynLinkStartOutput(void);
|
||||
LOCAL void connectCallback(struct connection_handler_args cha);
|
||||
LOCAL void getCallback(struct event_handler_args eha);
|
||||
LOCAL void monitorCallback(struct event_handler_args eha);
|
||||
LOCAL void recDynLinkInp(void);
|
||||
LOCAL void recDynLinkOut(void);
|
||||
|
||||
long recDynLinkAddInput(recDynLink *precDynLink,char *pvname,
|
||||
short dbrType,int options,
|
||||
recDynCallback searchCallback,recDynCallback monitorCallback)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
struct db_addr dbaddr;
|
||||
ringBufCmd cmd;
|
||||
|
||||
|
||||
if(options&rdlDBONLY && db_name_to_addr(pvname,&dbaddr))return(-1);
|
||||
if(!inpTaskId) recDynLinkStartInput();
|
||||
if(precDynLink->pdynLinkPvt) recDynLinkClear(precDynLink);
|
||||
pdynLinkPvt = (dynLinkPvt *)calloc(1,sizeof(dynLinkPvt));
|
||||
if(!pdynLinkPvt) {
|
||||
printf("recDynLinkAddInput can't allocate storage");
|
||||
taskSuspend(0);
|
||||
}
|
||||
FASTLOCKINIT(&pdynLinkPvt->lock);
|
||||
precDynLink->pdynLinkPvt = pdynLinkPvt;
|
||||
pdynLinkPvt->pvname = pvname;
|
||||
pdynLinkPvt->dbrType = dbrType;
|
||||
pdynLinkPvt->searchCallback = searchCallback;
|
||||
pdynLinkPvt->monitorCallback = monitorCallback;
|
||||
pdynLinkPvt->io = ioInput;
|
||||
pdynLinkPvt->scalar = (options&rdlSCALAR) ? TRUE : FALSE;
|
||||
pdynLinkPvt->state = stateStarting;
|
||||
cmd.data.precDynLink = precDynLink;
|
||||
cmd.cmd = cmdSearch;
|
||||
if(rngBufPut(inpRingQ,(void *)&cmd,sizeof(cmd)) != sizeof(cmd))
|
||||
errMessage(0,"recDynLinkAddInput: rngBufPut error");
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkAddOutput(recDynLink *precDynLink,char *pvname,
|
||||
short dbrType,int options,
|
||||
recDynCallback searchCallback)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
struct db_addr dbaddr;
|
||||
ringBufCmd cmd;
|
||||
|
||||
|
||||
if(options&rdlDBONLY && db_name_to_addr(pvname,&dbaddr))return(-1);
|
||||
if(!outTaskId) recDynLinkStartOutput();
|
||||
if(precDynLink->pdynLinkPvt) recDynLinkClear(precDynLink);
|
||||
pdynLinkPvt = (dynLinkPvt *)calloc(1,sizeof(dynLinkPvt));
|
||||
if(!pdynLinkPvt) {
|
||||
printf("recDynLinkAddOutput can't allocate storage");
|
||||
taskSuspend(0);
|
||||
}
|
||||
FASTLOCKINIT(&pdynLinkPvt->lock);
|
||||
precDynLink->pdynLinkPvt = pdynLinkPvt;
|
||||
pdynLinkPvt->pvname = pvname;
|
||||
pdynLinkPvt->dbrType = dbrType;
|
||||
pdynLinkPvt->searchCallback = searchCallback;
|
||||
pdynLinkPvt->io = ioOutput;
|
||||
pdynLinkPvt->scalar = (options&rdlSCALAR) ? TRUE : FALSE;
|
||||
pdynLinkPvt->state = stateStarting;
|
||||
cmd.data.precDynLink = precDynLink;
|
||||
cmd.cmd = cmdSearch;
|
||||
if(rngBufPut(outRingQ,(void *)&cmd,sizeof(cmd)) != sizeof(cmd))
|
||||
errMessage(0,"recDynLinkAddInput: rngBufPut error");
|
||||
semGive(wakeUpSem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkClear(recDynLink *precDynLink)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
ringBufCmd cmd;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(!pdynLinkPvt) {
|
||||
printf("recDynLinkClear. recDynLinkSearch was never called\n");
|
||||
taskSuspend(0);
|
||||
}
|
||||
if(pdynLinkPvt->chid) ca_puser(pdynLinkPvt->chid) = NULL;
|
||||
cmd.data.pdynLinkPvt = pdynLinkPvt;
|
||||
cmd.cmd = cmdClear;
|
||||
if(pdynLinkPvt->io==ioInput) {
|
||||
if(rngBufPut(inpRingQ,(void *)&cmd,sizeof(cmd)) != sizeof(cmd))
|
||||
errMessage(0,"recDynLinkClear: rngBufPut error");
|
||||
} else {
|
||||
if(rngBufPut(outRingQ,(void *)&cmd,sizeof(cmd)) != sizeof(cmd))
|
||||
errMessage(0,"recDynLinkClear: rngBufPut error");
|
||||
}
|
||||
precDynLink->pdynLinkPvt = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkConnectionStatus(recDynLink *precDynLink)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
long status;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
status = (ca_state(pdynLinkPvt->chid)==cs_conn) ? 0 : -1;
|
||||
return(status);
|
||||
}
|
||||
|
||||
long recDynLinkGetNelem(recDynLink *precDynLink,size_t *nelem)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(ca_state(pdynLinkPvt->chid)!=cs_conn) return(-1);
|
||||
*nelem = ca_element_count(pdynLinkPvt->chid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkGetControlLimits(recDynLink *precDynLink,
|
||||
double *low,double *high)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->state!=stateConnected) return(-1);
|
||||
if(low) *low = pdynLinkPvt->controlLow;
|
||||
if(high) *high = pdynLinkPvt->controlHigh;
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkGetGraphicLimits(recDynLink *precDynLink,
|
||||
double *low,double *high)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->state!=stateConnected) return(-1);
|
||||
if(low) *low = pdynLinkPvt->graphicLow;
|
||||
if(high) *high = pdynLinkPvt->graphHigh;
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkGetPrecision(recDynLink *precDynLink,int *prec)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->state!=stateConnected) return(-1);
|
||||
if(prec) *prec = pdynLinkPvt->precision;
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkGetUnits(recDynLink *precDynLink,char *units,int maxlen)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
int maxToCopy;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->state!=stateConnected) return(-1);
|
||||
maxToCopy = MAX_UNITS_SIZE;
|
||||
if(maxlen<maxToCopy) maxToCopy = maxlen;
|
||||
strncpy(units,pdynLinkPvt->units,maxToCopy);
|
||||
if(maxToCopy<maxlen) units[maxToCopy] = '\0';
|
||||
return(0);
|
||||
}
|
||||
|
||||
long recDynLinkGet(recDynLink *precDynLink,void *pbuffer,size_t *nRequest,
|
||||
TS_STAMP *timestamp,short *status,short *severity)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
long caStatus;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
caStatus = (ca_state(pdynLinkPvt->chid)==cs_conn) ? 0 : -1;
|
||||
if(caStatus) goto all_done;
|
||||
if(*nRequest > pdynLinkPvt->nRequest) {
|
||||
*nRequest = pdynLinkPvt->nRequest;
|
||||
}
|
||||
FASTLOCK(&pdynLinkPvt->lock);
|
||||
memcpy(pbuffer,pdynLinkPvt->pbuffer,
|
||||
(*nRequest * dbr_size[mapNewToOld[pdynLinkPvt->dbrType]]));
|
||||
if(timestamp) *timestamp = pdynLinkPvt->timestamp; /*array copy*/
|
||||
if(status) *status = pdynLinkPvt->status;
|
||||
if(severity) *severity = pdynLinkPvt->severity;
|
||||
FASTUNLOCK(&pdynLinkPvt->lock);
|
||||
all_done:
|
||||
return(caStatus);
|
||||
}
|
||||
|
||||
long recDynLinkPut(recDynLink *precDynLink,void *pbuffer,size_t nRequest)
|
||||
{
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
long status;
|
||||
ringBufCmd cmd;
|
||||
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->io!=ioOutput || pdynLinkPvt->state!=stateConnected) {
|
||||
status = -1;
|
||||
} else {
|
||||
status = (ca_state(pdynLinkPvt->chid)==cs_conn) ? 0 : -1;
|
||||
}
|
||||
if(status) goto all_done;
|
||||
if(pdynLinkPvt->scalar) nRequest = 1;
|
||||
if(nRequest>ca_element_count(pdynLinkPvt->chid))
|
||||
nRequest = ca_element_count(pdynLinkPvt->chid);
|
||||
pdynLinkPvt->nRequest = nRequest;
|
||||
memcpy(pdynLinkPvt->pbuffer,pbuffer,
|
||||
(nRequest * dbr_size[mapNewToOld[pdynLinkPvt->dbrType]]));
|
||||
cmd.data.precDynLink = precDynLink;
|
||||
cmd.cmd = cmdPut;
|
||||
if(rngBufPut(outRingQ,(void *)&cmd,sizeof(cmd)) != sizeof(cmd))
|
||||
errMessage(0,"recDynLinkPut: rngBufPut error");
|
||||
semGive(wakeUpSem);
|
||||
all_done:
|
||||
return(status);
|
||||
}
|
||||
|
||||
LOCAL void recDynLinkStartInput(void)
|
||||
{
|
||||
if((inpRingQ = rngCreate(sizeof(ringBufCmd) * recDynLinkQsize)) == NULL) {
|
||||
errMessage(0,"recDynLinkStart failed");
|
||||
exit(1);
|
||||
}
|
||||
inpTaskId = taskSpawn("recDynINP",CA_CLIENT_PRI-1,VX_FP_TASK,
|
||||
CA_CLIENT_STACK,(FUNCPTR)recDynLinkInp,0,0,0,0,0,0,0,0,0,0);
|
||||
if(inpTaskId==ERROR) {
|
||||
errMessage(0,"recDynLinkStartInput: taskSpawn Failure\n");
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void recDynLinkStartOutput(void)
|
||||
{
|
||||
if((wakeUpSem=semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL)
|
||||
errMessage(0,"semBcreate failed in recDynLinkStart");
|
||||
if((outRingQ = rngCreate(sizeof(ringBufCmd) * recDynLinkQsize)) == NULL) {
|
||||
errMessage(0,"recDynLinkStartOutput failed");
|
||||
exit(1);
|
||||
}
|
||||
outTaskId = taskSpawn("recDynOUT",CA_CLIENT_PRI-1,VX_FP_TASK,
|
||||
CA_CLIENT_STACK,(FUNCPTR)recDynLinkOut,0,0,0,0,0,0,0,0,0,0);
|
||||
if(outTaskId==ERROR) {
|
||||
errMessage(0,"recDynLinkStart: taskSpawn Failure\n");
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void connectCallback(struct connection_handler_args cha)
|
||||
{
|
||||
chid chid = cha.chid;
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
|
||||
precDynLink = (recDynLink *)ca_puser(cha.chid);
|
||||
if(!precDynLink) return;
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(ca_state(chid)==cs_conn) {
|
||||
pdynLinkPvt->state = stateGetting;
|
||||
SEVCHK(ca_get_callback(DBR_CTRL_DOUBLE,chid,getCallback,precDynLink),
|
||||
"ca_get_callback");
|
||||
} else {
|
||||
if(pdynLinkPvt->searchCallback)
|
||||
(pdynLinkPvt->searchCallback)(precDynLink);
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void getCallback(struct event_handler_args eha)
|
||||
{
|
||||
struct dbr_ctrl_double *pdata = (struct dbr_ctrl_double *)eha.dbr;
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
size_t nRequest;
|
||||
|
||||
precDynLink = (recDynLink *)ca_puser(eha.chid);
|
||||
if(!precDynLink) return;
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
pdynLinkPvt -> graphicLow = pdata->lower_disp_limit;
|
||||
pdynLinkPvt -> graphHigh = pdata->upper_disp_limit;
|
||||
pdynLinkPvt -> controlLow = pdata->lower_ctrl_limit;
|
||||
pdynLinkPvt -> controlHigh = pdata->upper_ctrl_limit;
|
||||
pdynLinkPvt -> precision = pdata->precision;
|
||||
strncpy(pdynLinkPvt->units,pdata->units,MAX_UNITS_SIZE);
|
||||
if(pdynLinkPvt->scalar) {
|
||||
pdynLinkPvt->nRequest = 1;
|
||||
} else {
|
||||
pdynLinkPvt->nRequest = ca_element_count(pdynLinkPvt->chid);
|
||||
}
|
||||
nRequest = pdynLinkPvt->nRequest;
|
||||
pdynLinkPvt->pbuffer = calloc(nRequest,
|
||||
dbr_size[mapNewToOld[pdynLinkPvt->dbrType]]);
|
||||
if(pdynLinkPvt->io==ioInput) {
|
||||
SEVCHK(ca_add_array_event(
|
||||
dbf_type_to_DBR_TIME(mapNewToOld[pdynLinkPvt->dbrType]),
|
||||
pdynLinkPvt->nRequest,
|
||||
pdynLinkPvt->chid,monitorCallback,precDynLink,
|
||||
0.0,0.0,0.0,
|
||||
&pdynLinkPvt->evid),"ca_add_array_event");
|
||||
}
|
||||
pdynLinkPvt->state = stateConnected;
|
||||
if(pdynLinkPvt->searchCallback) (pdynLinkPvt->searchCallback)(precDynLink);
|
||||
}
|
||||
|
||||
LOCAL void monitorCallback(struct event_handler_args eha)
|
||||
{
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
long count = eha.count;
|
||||
void *pbuffer = eha.dbr;
|
||||
struct dbr_time_string *pdbr_time_string;
|
||||
void *pdata;
|
||||
short timeType;
|
||||
|
||||
precDynLink = (recDynLink *)ca_puser(eha.chid);
|
||||
if(!precDynLink) return;
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
if(pdynLinkPvt->pbuffer) {
|
||||
FASTLOCK(&pdynLinkPvt->lock);
|
||||
if(count>=pdynLinkPvt->nRequest)
|
||||
count = pdynLinkPvt->nRequest;
|
||||
pdbr_time_string = (struct dbr_time_string *)pbuffer;
|
||||
timeType = dbf_type_to_DBR_TIME(mapNewToOld[pdynLinkPvt->dbrType]);
|
||||
pdata = (void *)((char *)pbuffer + dbr_value_offset[timeType]);
|
||||
pdynLinkPvt->timestamp = pdbr_time_string->stamp; /*array copy*/
|
||||
pdynLinkPvt->status = pdbr_time_string->status;
|
||||
pdynLinkPvt->severity = pdbr_time_string->severity;
|
||||
memcpy(pdynLinkPvt->pbuffer,pdata,
|
||||
(count * dbr_size[mapNewToOld[pdynLinkPvt->dbrType]]));
|
||||
FASTUNLOCK(&pdynLinkPvt->lock);
|
||||
}
|
||||
if(pdynLinkPvt->monitorCallback)
|
||||
(*pdynLinkPvt->monitorCallback)(precDynLink);
|
||||
}
|
||||
|
||||
LOCAL void recDynLinkInp(void)
|
||||
{
|
||||
int status;
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
int caStatus;
|
||||
ringBufCmd cmd;
|
||||
|
||||
taskwdInsert(taskIdSelf(),NULL,NULL);
|
||||
SEVCHK(ca_task_initialize(),"ca_task_initialize");
|
||||
while(TRUE) {
|
||||
while (rngNBytes(inpRingQ)>=sizeof(cmd) && interruptAccept){
|
||||
if(rngBufGet(inpRingQ,(void *)&cmd,sizeof(cmd))
|
||||
!=sizeof(cmd)) {
|
||||
errMessage(0,"recDynLinkTask: rngBufGet error");
|
||||
continue;
|
||||
}
|
||||
if(cmd.cmd==cmdClear) {
|
||||
pdynLinkPvt = cmd.data.pdynLinkPvt;
|
||||
if(pdynLinkPvt->chid)
|
||||
SEVCHK(ca_clear_channel(pdynLinkPvt->chid),
|
||||
"ca_clear_channel");
|
||||
free(pdynLinkPvt->pbuffer);
|
||||
free((void *)pdynLinkPvt);
|
||||
continue;
|
||||
}
|
||||
precDynLink = cmd.data.precDynLink;
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
switch(cmd.cmd) {
|
||||
case(cmdSearch) :
|
||||
SEVCHK(ca_search_and_connect(pdynLinkPvt->pvname,
|
||||
&pdynLinkPvt->chid, connectCallback,precDynLink),
|
||||
"ca_search_and_connect");
|
||||
break;
|
||||
default:
|
||||
epicsPrintf("Logic error statement in recDynLinkTask\n");
|
||||
}
|
||||
}
|
||||
status = ca_pend_event(.1);
|
||||
if(status!=ECA_NORMAL && status!=ECA_TIMEOUT)
|
||||
SEVCHK(status,"ca_pend_event");
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void recDynLinkOut(void)
|
||||
{
|
||||
int status;
|
||||
recDynLink *precDynLink;
|
||||
dynLinkPvt *pdynLinkPvt;
|
||||
ringBufCmd cmd;
|
||||
int caStatus;
|
||||
|
||||
taskwdInsert(taskIdSelf(),NULL,NULL);
|
||||
SEVCHK(ca_task_initialize(),"ca_task_initialize");
|
||||
while(TRUE) {
|
||||
semTake(wakeUpSem,sysClkRateGet());
|
||||
while (rngNBytes(outRingQ)>=sizeof(cmd) && interruptAccept){
|
||||
if(rngBufGet(outRingQ,(void *)&cmd,sizeof(cmd))
|
||||
!=sizeof(cmd)) {
|
||||
errMessage(0,"recDynLinkTask: rngBufGet error");
|
||||
continue;
|
||||
}
|
||||
if(cmd.cmd==cmdClear) {
|
||||
pdynLinkPvt = cmd.data.pdynLinkPvt;
|
||||
if(pdynLinkPvt->chid)
|
||||
SEVCHK(ca_clear_channel(pdynLinkPvt->chid),
|
||||
"ca_clear_channel");
|
||||
free(pdynLinkPvt->pbuffer);
|
||||
free((void *)pdynLinkPvt);
|
||||
continue;
|
||||
}
|
||||
precDynLink = cmd.data.precDynLink;
|
||||
pdynLinkPvt = precDynLink->pdynLinkPvt;
|
||||
switch(cmd.cmd) {
|
||||
case(cmdSearch) :
|
||||
SEVCHK(ca_search_and_connect(pdynLinkPvt->pvname,
|
||||
&pdynLinkPvt->chid, connectCallback,precDynLink),
|
||||
"ca_search_and_connect");
|
||||
break;
|
||||
case(cmdPut) :
|
||||
caStatus = ca_array_put(
|
||||
mapNewToOld[pdynLinkPvt->dbrType],
|
||||
pdynLinkPvt->nRequest,pdynLinkPvt->chid,
|
||||
pdynLinkPvt->pbuffer);
|
||||
if(caStatus!=ECA_NORMAL) {
|
||||
epicsPrintf("recDynLinkTask pv=%s CA Error %s\n",
|
||||
pdynLinkPvt->pvname,ca_message(caStatus));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
epicsPrintf("Logic error statement in recDynLinkTask\n");
|
||||
}
|
||||
}
|
||||
status = ca_pend_event(.00001);
|
||||
if(status!=ECA_NORMAL && status!=ECA_TIMEOUT)
|
||||
SEVCHK(status,"ca_pend_event");
|
||||
}
|
||||
}
|
||||
51
src/rec/recDynLink.h
Normal file
51
src/rec/recDynLink.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*recDynLink.c*/
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
*******************************************************************/
|
||||
#ifndef INCrecDynLinkh
|
||||
#define INCrecDynLinkh
|
||||
|
||||
#include <tsDefs.h>
|
||||
typedef struct recDynLink{
|
||||
void *puserPvt;
|
||||
void *pdynLinkPvt;
|
||||
} recDynLink;
|
||||
typedef void (*recDynCallback)(recDynLink *);
|
||||
|
||||
#define rdlDBONLY 0x1
|
||||
#define rdlSCALAR 0x2
|
||||
|
||||
long recDynLinkAddInput(recDynLink *precDynLink,char *pvname,
|
||||
short dbrType,int options,
|
||||
recDynCallback searchCallback,recDynCallback monitorCallback);
|
||||
long recDynLinkAddOutput(recDynLink *precDynLink,char *pvname,
|
||||
short dbrType,int options,
|
||||
recDynCallback searchCallback);
|
||||
long recDynLinkClear(recDynLink *precDynLink);
|
||||
/*The following routine returns (0,-1) for (connected,not connected)*/
|
||||
long recDynLinkConnectionStatus(recDynLink *precDynLink);
|
||||
/*thye following routine returns (0,-1) if (connected,not connected)*/
|
||||
long recDynLinkGetNelem(recDynLink *precDynLink,size_t *nelem);
|
||||
/*The following 4 routines return (0,-1) if data (is, is not) yet available*/
|
||||
/*searchCallback is not called until this info is available*/
|
||||
long recDynLinkGetControlLimits(recDynLink *precDynLink,
|
||||
double *low,double *high);
|
||||
long recDynLinkGetGraphicLimits(recDynLink *precDynLink,
|
||||
double *low,double *high);
|
||||
long recDynLinkGetPrecision(recDynLink *precDynLink,int *prec);
|
||||
long recDynLinkGetUnits(recDynLink *precDynLink,char *units,int maxlen);
|
||||
|
||||
/*get only valid mfor rdlINPUT. put only valid for rdlOUTPUT*/
|
||||
long recDynLinkGet(recDynLink *precDynLink,
|
||||
void *pbuffer, size_t *nRequest,
|
||||
TS_STAMP *timestamp,short *status,short *severity);
|
||||
long recDynLinkPut(recDynLink *precDynLink,void *pbuffer,size_t nRequest);
|
||||
|
||||
#endif /*INCrecDynLinkh*/
|
||||
191
src/rec/recDynLinkTest.c
Normal file
191
src/rec/recDynLinkTest.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/*recDynLinkTest.c */
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
***********************************************************************/
|
||||
#include <vxWorks.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include <tsDefs.h>
|
||||
#include <recDynLink.h>
|
||||
#include <dbAccess.h>
|
||||
|
||||
/*The remainder of this source module is test code */
|
||||
typedef struct userPvt {
|
||||
char *pvname;
|
||||
double *pbuffer;
|
||||
size_t nRequest;
|
||||
}userPvt;
|
||||
|
||||
LOCAL void mymonitorCallback(recDynLink *precDynLink)
|
||||
{
|
||||
userPvt *puserPvt;
|
||||
long status;
|
||||
size_t nRequest;
|
||||
TS_STAMP timestamp;
|
||||
short AlarmStatus,AlarmSeverity;
|
||||
int i;
|
||||
char timeStr[40];
|
||||
|
||||
puserPvt = (userPvt *)precDynLink->puserPvt;
|
||||
printf("mymonitorCallback: %s\n",puserPvt->pvname);
|
||||
if(recDynLinkConnectionStatus(precDynLink)!=0) {
|
||||
printf(" not connected\n");
|
||||
return;
|
||||
}
|
||||
nRequest = puserPvt->nRequest;
|
||||
status = recDynLinkGet(precDynLink,puserPvt->pbuffer,&nRequest,
|
||||
×tamp,&AlarmStatus,&AlarmSeverity);
|
||||
if(status) {
|
||||
printf("recDynLinkGet returned illegal status\n");
|
||||
return;
|
||||
}
|
||||
tsStampToText(×tamp,TS_TEXT_MMDDYY,timeStr);
|
||||
printf("date %s status %hd severity %hd ",
|
||||
timeStr,AlarmStatus,AlarmSeverity);
|
||||
for(i=0; i<puserPvt->nRequest; i++) {
|
||||
printf(" %f",puserPvt->pbuffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
LOCAL void mysearchCallback(recDynLink *precDynLink)
|
||||
{
|
||||
userPvt *puserPvt;
|
||||
size_t nelem;
|
||||
double controlLow,controlHigh;
|
||||
double graphicLow,graphicHigh;
|
||||
int prec;
|
||||
char units[20];
|
||||
long status;
|
||||
|
||||
puserPvt = (userPvt *)precDynLink->puserPvt;
|
||||
printf("mysearchCallback: %s ",puserPvt->pvname);
|
||||
if(recDynLinkConnectionStatus(precDynLink)==0) {
|
||||
printf("connected\n");
|
||||
status = recDynLinkGetNelem(precDynLink,&nelem);
|
||||
if(status) {
|
||||
printf("recDynLinkGetNelem failed\n");
|
||||
}else{
|
||||
printf("nelem = %u\n",nelem);
|
||||
}
|
||||
status=recDynLinkGetControlLimits(precDynLink,&controlLow,&controlHigh);
|
||||
if(status) {
|
||||
printf("recDynLinkGetControlLimits failed\n");
|
||||
}else{
|
||||
printf("controlLow %f controlHigh %f\n",controlLow,controlHigh);
|
||||
}
|
||||
status=recDynLinkGetGraphicLimits(precDynLink,&graphicLow,&graphicHigh);
|
||||
if(status) {
|
||||
printf("recDynLinkGetGraphicLimits failed\n");
|
||||
}else{
|
||||
printf("graphicLow %f graphicHigh %f\n",graphicLow,graphicHigh);
|
||||
}
|
||||
status = recDynLinkGetPrecision(precDynLink,&prec);
|
||||
if(status) {
|
||||
printf("recDynLinkGetPrecision failed\n");
|
||||
}else{
|
||||
printf("prec = %d\n",prec);
|
||||
}
|
||||
status = recDynLinkGetUnits(precDynLink,units,20);
|
||||
if(status) {
|
||||
printf("recDynLinkGetUnits failed\n");
|
||||
}else{
|
||||
printf("units = %s\n",units);
|
||||
}
|
||||
} else {
|
||||
printf(" not connected\n");
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL recDynLink getDynlink = {NULL,NULL};
|
||||
LOCAL recDynLink putDynlink = {NULL,NULL};
|
||||
|
||||
int recDynTestInput(char *pvname,int nRequest)
|
||||
{
|
||||
userPvt *puserPvt= getDynlink.puserPvt;
|
||||
long status;
|
||||
int options=0;
|
||||
|
||||
if(puserPvt) {
|
||||
recDynLinkClear(&getDynlink);
|
||||
free(puserPvt->pbuffer);
|
||||
free(getDynlink.puserPvt);
|
||||
getDynlink.puserPvt = NULL;
|
||||
}
|
||||
getDynlink.puserPvt = puserPvt = (userPvt *)calloc(1,sizeof(userPvt));
|
||||
puserPvt->pbuffer = calloc(nRequest,sizeof(double));
|
||||
puserPvt->nRequest = nRequest;
|
||||
puserPvt->pvname = pvname;
|
||||
if(nRequest==1) options=rdlSCALAR;;
|
||||
status = recDynLinkAddInput(&getDynlink,pvname,
|
||||
DBR_DOUBLE,options,
|
||||
mysearchCallback,mymonitorCallback);
|
||||
if(status) return(status);
|
||||
return(status);
|
||||
}
|
||||
|
||||
int recDynTestNewOutput(char *pvname,int nRequest)
|
||||
{
|
||||
userPvt *puserPvt= putDynlink.puserPvt;
|
||||
long status;
|
||||
int options=0;
|
||||
|
||||
if(puserPvt) {
|
||||
recDynLinkClear(&putDynlink);
|
||||
free(puserPvt->pbuffer);
|
||||
free(putDynlink.puserPvt);
|
||||
putDynlink.puserPvt = NULL;
|
||||
}
|
||||
putDynlink.puserPvt = puserPvt = (userPvt *)calloc(1,sizeof(userPvt));
|
||||
puserPvt->pbuffer = calloc(nRequest,sizeof(double));
|
||||
puserPvt->nRequest = nRequest;
|
||||
puserPvt->pvname = pvname;
|
||||
if(nRequest==1) options=rdlSCALAR;;
|
||||
status = recDynLinkAddOutput(&putDynlink,pvname,
|
||||
DBR_DOUBLE,options,mysearchCallback);
|
||||
return(status);
|
||||
}
|
||||
|
||||
int recDynTestOutput(int startValue)
|
||||
{
|
||||
userPvt *puserPvt= putDynlink.puserPvt;
|
||||
long status;
|
||||
int i;
|
||||
|
||||
for(i=0; i<puserPvt->nRequest; i++) puserPvt->pbuffer[i] = startValue + i;
|
||||
status = recDynLinkPut(&putDynlink,puserPvt->pbuffer,puserPvt->nRequest);
|
||||
return(status);
|
||||
}
|
||||
|
||||
int recDynTestClearInput(void)
|
||||
{
|
||||
userPvt *puserPvt= getDynlink.puserPvt;
|
||||
|
||||
recDynLinkClear(&getDynlink);
|
||||
free(puserPvt->pbuffer);
|
||||
free(getDynlink.puserPvt);
|
||||
getDynlink.puserPvt = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int recDynTestClearOutput(void)
|
||||
{
|
||||
userPvt *puserPvt= putDynlink.puserPvt;
|
||||
|
||||
recDynLinkClear(&putDynlink);
|
||||
free(puserPvt->pbuffer);
|
||||
free(putDynlink.puserPvt);
|
||||
putDynlink.puserPvt = NULL;
|
||||
return(0);
|
||||
}
|
||||
@@ -201,7 +201,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct gsubRecord *psub=(struct gsubRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psub->egu,sizeof(psub->egu));
|
||||
strncpy(units,psub->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct longinRecord *plongin=(struct longinRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,plongin->egu,sizeof(plongin->egu));
|
||||
strncpy(units,plongin->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct longoutRecord *plongout=(struct longoutRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,plongout->egu,sizeof(plongout->egu));
|
||||
strncpy(units,plongout->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct palRecord *ppal=(struct palRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,ppal->egu,sizeof(ppal->egu));
|
||||
strncpy(units,ppal->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct pidRecord *ppid=(struct pidRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,ppid->egu,sizeof(ppid->egu));
|
||||
strncpy(units,ppid->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
3163
src/rec/recScan.c
3163
src/rec/recScan.c
File diff suppressed because it is too large
Load Diff
@@ -199,7 +199,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct selRecord *psel=(struct selRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psel->egu,sizeof(psel->egu));
|
||||
strncpy(units,psel->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -295,7 +297,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct steppermotorRecord *psm=(struct steppermotorRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psm->egu,sizeof(psm->egu));
|
||||
strncpy(units,psm->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct subRecord *psub=(struct subRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psub->egu,sizeof(psub->egu));
|
||||
strncpy(units,psub->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct subArrayRecord *psa=(struct subArrayRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,psa->egu,sizeof(psa->egu));
|
||||
strncpy(units,psa->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ static long get_units(paddr,units)
|
||||
{
|
||||
struct waveformRecord *pwf=(struct waveformRecord *)paddr->precord;
|
||||
|
||||
strncpy(units,pwf->egu,sizeof(pwf->egu));
|
||||
strncpy(units,pwf->egu,DB_UNITS_SIZE);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
@@ -1580,7 +1580,8 @@ struct client *client
|
||||
int status;
|
||||
unsigned sid;
|
||||
unsigned long count;
|
||||
int type;
|
||||
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,
|
||||
@@ -1643,7 +1647,7 @@ struct client *client
|
||||
}
|
||||
sid = pchannel->sid;
|
||||
count = tmp_addr.no_elements;
|
||||
type = tmp_addr.field_type;
|
||||
type = (ca_uint16_t) tmp_addr.field_type;
|
||||
}
|
||||
|
||||
SEND_LOCK(client);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ int cast_server(void)
|
||||
struct sockaddr_in new_recv_addr;
|
||||
int recv_addr_size;
|
||||
unsigned nchars;
|
||||
short port;
|
||||
unsigned short port;
|
||||
|
||||
taskwdInsert((int)taskIdCurrent,NULL,NULL);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -80,7 +80,7 @@ int rsrv_online_notify_task()
|
||||
int status;
|
||||
int sock;
|
||||
int true = TRUE;
|
||||
short port;
|
||||
unsigned short port;
|
||||
|
||||
taskwdInsert(taskIdSelf(),NULL,NULL);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -174,7 +174,7 @@ char get; /* T: get F: monitor */
|
||||
GLBLTYPE int CASDEBUG;
|
||||
GLBLTYPE int IOC_sock;
|
||||
GLBLTYPE int IOC_cast_sock;
|
||||
GLBLTYPE int ca_server_port;
|
||||
GLBLTYPE unsigned short ca_server_port;
|
||||
GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */
|
||||
GLBLTYPE ELLLIST rsrv_free_clientQ; /* locked by clientQlock */
|
||||
GLBLTYPE ELLLIST rsrv_free_addrq;
|
||||
@@ -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 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 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 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 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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user