Compare commits

..

93 Commits

Author SHA1 Message Date
Janet B. Anderson
25a6340993 Added filio.h include for solaris build. 1995-11-13 16:55:03 +00:00
Jeff Hill
a3652fd54e improvents for better client reconnect 1995-11-08 23:48:26 +00:00
Jeff Hill
107ae2cee8 fixed log client reconnect problems 1995-11-08 23:46:27 +00:00
Jeff Hill
deb5e9c973 add log entries 1995-11-08 23:45:10 +00:00
Jeff Hill
196f2302a4 changes associated with fixing the log client 1995-11-08 23:44:41 +00:00
Jeff Hill
2a21b01b0e fixed bug occuring when diagnostic is printed and the env var cant be found 1995-11-08 23:43:51 +00:00
Jeff Hill
56465da07f log entries changed 1995-11-08 23:38:41 +00:00
Jeff Hill
ee9457970a changes froim chris T 1995-11-08 23:36:31 +00:00
Jeff Hill
89a3746869 changes from Chris T 1995-11-08 23:20:56 +00:00
Janet B. Anderson
5be8f4999d Removed "-s" compile option 1995-11-08 19:28:51 +00:00
Marty Kraimer
b278c803ce When calling db_post_event for argument fields ass DBE_LOG 1995-11-08 15:01:36 +00:00
Jeff Hill
50b8361078 more changes from Chris Timossi 1995-10-25 16:46:01 +00:00
Jeff Hill
2a121a4276 changes from Chris Timossi 1995-10-24 21:21:31 +00:00
Jeff Hill
7b03ab0182 Changes to avoid spurious ECONREFUSED returned from recvfrom() under linux 1995-10-22 22:27:47 +00:00
cvs2svn
73a224a6ce This commit was manufactured by cvs2svn to create tag 'R3.12.1.4'. 1995-10-20 20:21:33 +00:00
Marty Kraimer
f4af420e22 Changes to make stop work 1995-10-20 20:21:32 +00:00
Janet B. Anderson
b0177729b8 Sequencer V1.9.0(3.12.1) form lanl. 1995-10-19 21:35:38 +00:00
Jeff Hill
c7b5592846 make certain we dont use CPU while waiting for a flush to complete 1995-10-19 20:37:19 +00:00
Janet B. Anderson
2f5202a4e4 Assume no DST if tsMinWest is 600 (includes Hawaii and may be exclusively
Hawaii?). (WFL, 95/08/15)
1995-10-19 13:54:50 +00:00
Ned Arnold
ecb106fb71 WAIT Record Version 3.01, channel access dynamic links 1995-10-19 13:42:38 +00:00
Ned Arnold
b637c15e18 SCAN Record Version 3.00. Many changes. 1995-10-19 13:41:47 +00:00
Jeff Hill
d1102b06c0 recv task is now running at a lower priority than the send task under vxWorks 1995-10-18 16:49:23 +00:00
Jeff Hill
2fb23fd27b Use recast delay greater than one vxWorks tick 1995-10-18 16:45:40 +00:00
Jeff Hill
752b7e257e select time out must be greater than a vxWorks tick 1995-10-18 16:44:36 +00:00
John Quintana
025b13b977 *** empty log message *** 1995-10-12 20:50:36 +00:00
Jeff Hill
4c2822dd2e added SOLARIS ifdef around ioctl includes 1995-10-12 18:55:22 +00:00
Jeff Hill
9dcee4c068 removed unused variable 1995-10-12 18:54:41 +00:00
Janet B. Anderson
9bf802557e Updated for R3.12.1.3 1995-10-12 17:09:20 +00:00
Jeff Hill
2566ee1e26 If the IOC is out of memory allow them to connect if they stop
some of the clients.
1995-10-12 01:40:48 +00:00
Jeff Hill
5a16ba053b Changes from Bob Dalesio:
lrd     fix init to limit in overshoot check and retry post monitors
	   for mcw and mccw reprocess records if the setpoint changed
	   while they were moving
1995-10-12 01:38:41 +00:00
Jeff Hill
ad3e5a3272 New ca_flush_io() mechanism 1995-10-12 01:36:39 +00:00
Jeff Hill
17511136a1 Use of port is consistent unsigned short now 1995-10-12 01:36:13 +00:00
Jeff Hill
ffa22f89bd Moved cac_mux_io() to iocinf.c 1995-10-12 01:35:33 +00:00
Jeff Hill
2e7075bd31 Dont include filio.h and sockio.h. They are included by ioctl.h
and dont exist under linux.
1995-10-12 01:34:00 +00:00
Jeff Hill
278eaf84d7 Initial delay between search frames went from .1 to .01 sec,
Added flush pending flag, Make all usage of port be unsigned short.
1995-10-12 01:33:12 +00:00
Jeff Hill
d957aebbf4 make the use of unsigend short for a port consistent. Moved
cac_mux_io() out of os dependent code and into this module.
Added caSendMsgPending() routine.
1995-10-12 01:31:54 +00:00
Jeff Hill
5ac2a99686 improved the test 1995-10-12 01:30:28 +00:00
Jeff Hill
b782f63a7d new ca_flush_io() mechanism prevents deadlock when they call
ca_flush_io() from within an event routine. Also forces early
transmission of leading search UDP frames.
1995-10-12 01:30:10 +00:00
Marty Kraimer
e62f7d0ae2 cvtDoubleToString: honor precision for wierd numbers 1995-10-11 19:42:52 +00:00
Marty Kraimer
1ca96e0116 recGblGetAlarmDouble was not setting upper_warning_limit and lower_alarm_limit 1995-10-11 19:41:22 +00:00
Andrew Johnson
44d65d9477 Fixed main() for use as host tool - was *really* broken. 1995-10-04 20:42:05 +00:00
Andrew Johnson
dc3ba94fc8 Updated for Solaris Native mode compilation instructions. 1995-10-03 22:52:50 +00:00
Andrew Johnson
41ad7ae2ab Generating LIBOBJS automatically from SRCS.c 1995-10-03 21:18:50 +00:00
Andrew Johnson
017c55f9d9 Generating TARGETS automatically from SRCS.c 1995-10-03 21:13:45 +00:00
Andrew Johnson
196d7538c3 Generating LIBOBJS automatically from SRCS.c 1995-10-03 21:04:57 +00:00
Andrew Johnson
5ace66b609 Generating LIBOBJS automatically from SRCS.c 1995-10-03 20:59:44 +00:00
cvs2svn
0be218bed4 This commit was manufactured by cvs2svn to create tag 'R3.12.1.3'. 1995-10-03 15:42:27 +00:00
Janet B. Anderson
297f0b8c31 Added *COPYRIGHT* files to release tar file. 1995-10-03 15:42:26 +00:00
Jeff Hill
cc20412693 added locking for previous change 1995-09-29 22:53:38 +00:00
Jeff Hill
7021cd3589 use unsigned short for port 1995-09-29 22:18:53 +00:00
Jeff Hill
b7acf453c2 added arch independent type 1995-09-29 22:17:57 +00:00
Jeff Hill
c9abc2c82e ms windows changes 1995-09-29 22:17:13 +00:00
Jeff Hill
a7484494c4 changes from LBL 1995-09-29 22:15:26 +00:00
Jeff Hill
52cfbe92bf check for nill dbr pointer 1995-09-29 22:13:59 +00:00
Jeff Hill
75f0fb2b0c allow server to refuse to create a channel without a client disconnect 1995-09-29 22:13:05 +00:00
Jeff Hill
ed36723d6c ms windows changes 1995-09-29 21:58:16 +00:00
Jeff Hill
f7a5da9139 added minor version 6 which allows the server to refuse to create a channel
without disconnecting the client
1995-09-29 21:57:11 +00:00
Jeff Hill
254c5b1620 added func proto for cacDisconnectChannel() 1995-09-29 21:55:38 +00:00
Jeff Hill
c6aab85d79 MS windows changes and added cacDisconnectChannel() 1995-09-29 21:54:40 +00:00
Jeff Hill
d54724fce1 MS windows changes 1995-09-29 21:48:33 +00:00
Jeff Hill
60c0acab3c MS windows changes 1995-09-29 21:47:58 +00:00
Jeff Hill
69f33b9e23 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
1995-09-29 21:47:33 +00:00
Janet B. Anderson
9191863094 Added test for Linux. 1995-09-27 22:09:43 +00:00
Marty Kraimer
1beb157ab0 new database access has units as 16 char null terminated. old has 8 char null 1995-09-27 19:54:50 +00:00
Marty Kraimer
41ae285075 copy units string using DB_UNITS_SIZE 1995-09-27 19:52:45 +00:00
John Winans
222063ac53 Added code to send last byte of a RAC_RESET in pepTxTask(). It was left
out in a previous mod that modes the last byte transmission into a locked
region in order to prevent a TxTask/RxTask race condition.
1995-09-26 14:50:31 +00:00
Janet B. Anderson
3342ca120f Specified return type of functions. 1995-09-21 19:48:26 +00:00
cvs2svn
13b785e594 This commit was manufactured by cvs2svn to create tag 'R3.12.1.2'. 1995-09-13 18:27:49 +00:00
Jim Kowalkowski
6931273fef New utilities to list PVs on an IOC and loaded applications. 1995-09-13 18:27:48 +00:00
Jim Kowalkowski
8d52177933 Fixed the address of ioc by name in BSlib.c.
Added app list to the services of PVSvx.
Removed rdbls from PVSserver - made it a separate file.
1995-09-13 18:26:42 +00:00
Jim Kowalkowski
b64fa8bd87 Fixed bug in TSinit - Gives defaults to TSdirectTime() and TSdriverInit() if
event time disabled with TSconfigure().
1995-09-12 15:01:09 +00:00
Janet B. Anderson
34ce2ab6ac Added include for sockio and a cast for tsin in memset. 1995-09-08 14:56:30 +00:00
Jim Kowalkowski
43ef20b90c Completed first version of vx info server and workstation utility.
Removed the stupid program PVSget.
1995-09-07 21:25:59 +00:00
Jim Kowalkowski
818bc0d475 New library and PV dump programs for IOC and client workstation 1995-09-06 21:06:07 +00:00
Jim Kowalkowski
ca2f9aff52 Corrected a problem with building dbLoadTemplate/subtool.
Added the BS and PVS test functions
1995-09-06 21:05:09 +00:00
Jim Kowalkowski
64a93df872 Changed the error message 1995-09-06 21:04:22 +00:00
Jim Kowalkowski
ecc03e9ad9 Cleanup and addition of application() to db file 1995-09-06 21:03:07 +00:00
John Winans
db1b46e5f9 Added ability to change default clock speed from shell. 1995-09-01 14:36:35 +00:00
Marty Kraimer
d87295397e Still new 1995-09-01 14:35:27 +00:00
Marty Kraimer
7277c336f7 Fixed bug causing memory problem 1995-09-01 14:31:32 +00:00
Marty Kraimer
30ad5b1149 Added so that individual files dont have to have long notice 1995-09-01 12:47:28 +00:00
Marty Kraimer
c6bcd1a10b Still new 1995-08-30 21:31:43 +00:00
Marty Kraimer
f3cf369071 made separate from recDynLink 1995-08-30 21:18:29 +00:00
Marty Kraimer
adffe02a2d Still new 1995-08-30 21:17:46 +00:00
Marty Kraimer
e635080cef Fixed problems with freeing pvd 1995-08-30 17:43:19 +00:00
Jim Kowalkowski
be85da6a3a *** empty log message *** 1995-08-30 15:38:39 +00:00
Marty Kraimer
c16006f34d recDynLink is new 1995-08-29 17:55:20 +00:00
Janet B. Anderson
72491d8829 Added startup directory to release tar file 1995-08-28 15:49:54 +00:00
Marty Kraimer
cb78c5adb8 Changes so that function prototype for db_post_event defined 1995-08-28 14:50:32 +00:00
Jeff Hill
1a2cd5953d added log entries 1995-08-23 00:35:17 +00:00
Jeff Hill
5da79a5f56 fixed vxWorks specific SPARC data alignment problem 1995-08-23 00:34:06 +00:00
Jeff Hill
9f2d9587f0 additional parenthesis in macro to be safe 1995-08-23 00:31:13 +00:00
cvs2svn
74e405969a This commit was manufactured by cvs2svn to create tag 'R3.12.1.1'. 1995-08-22 12:23:38 +00:00
111 changed files with 9567 additions and 4256 deletions

View 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).

View File

@@ -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
View File

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

34
README.Linux Normal file
View File

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

View File

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

View File

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

View File

@@ -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.
**********************************************************************/

View File

@@ -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;
}

View File

@@ -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)){

View File

@@ -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;

View File

@@ -1,4 +1,5 @@
/************************************************************************/
/* $Id$ */
/* */
/* L O S A L A M O S */
/* Los Alamos National Laboratory */
@@ -45,6 +46,7 @@
/* 021794 joh turn on SO_REUSEADDR only after the test for */
/* address in use so that test works on UNIX */
/* kernels that support multicast */
/* $Log$ */
/* */
/*_begin */
/************************************************************************/
@@ -95,7 +97,7 @@ LOCAL char *getToken(char **ppString);
*/
int alloc_ioc(
const struct in_addr *pnet_addr,
int port,
unsigned short port,
struct ioc_in_use **ppiiu
)
{
@@ -148,7 +150,7 @@ struct ioc_in_use **ppiiu
int create_net_chan(
struct ioc_in_use **ppiiu,
const struct in_addr *pnet_addr, /* only used by TCP connections */
int port,
unsigned short port,
int net_proto
)
{
@@ -400,7 +402,7 @@ int net_proto
* let slib pick lcl addr
*/
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(0);
saddr.sin_port = htons(0U);
status = bind( sock,
(struct sockaddr *) &saddr,
@@ -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;
}

View File

@@ -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!!

View File

@@ -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)))
/*

View File

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

View File

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

View File

@@ -1,4 +1,6 @@
/*
* $Id$
*
* REPEATER.C
*
* CA broadcast repeater
@@ -59,6 +61,8 @@
* .08 102993 joh toggle set sock opt to set
* .09 070195 joh discover client has vanished by connecting its
* datagram socket (and watching for ECONNREFUSED)
*
* $Log$
*/
static char *sccsId = "@(#)$Id$";
@@ -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 */

View File

@@ -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;
}

View File

@@ -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);
}

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -51,6 +51,7 @@
#include <ellLib.h>
#include <vxLib.h>
#include <tickLib.h>
#include <sysLib.h>
#include <dbDefs.h>
#include <dbAccess.h>

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

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

View File

@@ -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(

View File

@@ -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
View 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
View 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

View File

@@ -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 \

View File

@@ -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
View 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
View 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
View 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");
}

View File

@@ -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

View File

@@ -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); }

View File

@@ -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
View 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
View 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;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) {

View File

@@ -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
*

View File

@@ -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

View File

@@ -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`

View File

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

View File

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

View File

@@ -32,6 +32,8 @@
* vars under vxWorks
* .05 04-20-95 anj changes to use CONFIG_ENV
* .06 05-24-95 joh added return stmnt to epicsPrtEnvParams()
* .07 11-03-96 joh fixed bug occuring when diagnostic is
* printed and the env var cant be found
*
* make options
* -DvxWorks makes a version for VxWorks
@@ -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;
}

View File

@@ -32,6 +32,8 @@
* vars under vxWorks
* .05 04-20-95 anj changes to use CONFIG_ENV
* .06 05-24-95 joh added return stmnt to epicsPrtEnvParams()
* .07 11-03-96 joh fixed bug occuring when diagnostic is
* printed and the env var cant be found
*
* make options
* -DvxWorks makes a version for VxWorks
@@ -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;
}

View File

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

View File

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

View File

@@ -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

View File

@@ -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

View File

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

View File

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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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
View 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
View 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
View 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,
&timestamp,&AlarmStatus,&AlarmSeverity);
if(status) {
printf("recDynLinkGet returned illegal status\n");
return;
}
tsStampToText(&timestamp,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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -94,6 +94,8 @@
* Stops
* .36 09-15-93 mrk call monitor when starting
* .37 03-29-94 mcn converted to fast links
* .38 09-27-95 lrd fix init to limit in overshoot check and retry
* post monitors for mcw and mccw
*/
#include <vxWorks.h>
@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

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

View File

@@ -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);
}

View File

@@ -439,7 +439,7 @@ struct client *client
/*
* user name will not change if there isnt enough memory
*/
pMalloc = malloc(size);
pMalloc = casMalloc(size);
if(!pMalloc){
send_err(
mp,
@@ -498,7 +498,7 @@ struct client *client
/*
* user name will not change if there isnt enough memory
*/
pMalloc = malloc(size);
pMalloc = casMalloc(size);
if(!pMalloc){
send_err(
mp,
@@ -896,7 +896,7 @@ struct client *client
*/
if(!pciu->pPutNotify){
pciu->pPutNotify =
(RSRVPUTNOTIFY *) calloc(1, sizeof(*pciu->pPutNotify)+size);
(RSRVPUTNOTIFY *) casCalloc(1, sizeof(*pciu->pPutNotify)+size);
if(!pciu->pPutNotify){
putNotifyErrorReply(client, mp, ECA_ALLOCMEM);
return;
@@ -1037,7 +1037,7 @@ struct client *client
ellGet(&rsrv_free_eventq);
FASTUNLOCK(&rsrv_free_eventq_lck);
if (!pevext) {
pevext = (struct event_ext *) malloc(size);
pevext = (struct event_ext *) casMalloc(size);
if (!pevext) {
SEND_LOCK(client);
send_err(
@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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!!
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,19 +2,20 @@
GTA PROJECT AT division
Copyright, 1990, The Regents of the University of California.
Los Alamos National Laboratory
$Id$
gen_ss_code.c,v 1.2 1995/06/27 15:25:43 wright Exp
DESCRIPTION: gen_ss_code.c -- routines to generate state set code
ENVIRONMENT: UNIX
HISTORY:
19nov91,ajk Changed find_var() to findVar().
28apr92,ajk Implemented efClear() & efTestAndClear().
01mar94,ajk Changed table generation to the new structures defined
in seqCom.h.
***************************************************************************/
#include <stdio.h>
#include "parse.h"
#include "cadef.h"
#include <dbDefs.h>
#include <seqU.h>
#include <dbDefs.h>
#include <seqCom.h>
/*+************************************************************************
* NAME: gen_ss_code
@@ -29,6 +30,7 @@
*
* NOTES: All inputs are external globals.
*-*************************************************************************/
/*#define DEBUG 1*/
#define EVENT_STMT 1
#define ACTION_STMT 2
@@ -50,7 +52,7 @@ gen_ss_code()
printf("\f/* Code for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
/* Generate delay processing function */
/* Generate function to set up for delay processing */
gen_delay_func(sp, ssp);
/* Generate event processing function */
@@ -64,9 +66,64 @@ gen_ss_code()
/* Generate exit handler code */
gen_exit_handler();
}
/* Generate a function for each state that sets up delay processing:
* This function gets called prior to the event function to guarantee
* that the initial delay value specified in delay() calls are used.
* Each delay() call is assigned a unique id. The maximum number of
* delays is recorded in the state set structure.
*/
gen_delay_func(sp, ssp)
Expr *ssp;
Expr *sp;
{
Expr *tp;
int eval_delay();
printf("\n/* Delay function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
printf("static D_%s_%s(ssId, pVar)\n", ssp->value, sp->value);
printf("SS_ID\tssId;\n");
printf("struct UserVar\t*pVar;\n{\n");
/* For each transition: */
for (tp = sp->left; tp != NULL; tp = tp->next)
{
print_line_num(tp->line_num, tp->src_file);
traverseExprTree(tp, E_FUNC, "delay", eval_delay, sp);
}
printf("}\n");
}
/* Evaluate the expression within a delay() function and generate
* a call to seq_delayInit(). Adds ssId, delay id parameters and cast to float.
* Example: seq_delayInit(ssId, 1, (float)(<some expression>));
*/
eval_delay(ep, sp)
Expr *ep;
Expr *sp;
{
Expr *epf;
int delay_id;
extern char *stype[];
#ifdef DEBUG
fprintf("stderr, "eval_delay: type=%s\n", stype[ep->type]);
#endif DEBUG
/* Generate 1-st part of function w/ 1-st 2 parameters */
delay_id = (int)ep->right; /* delay id was previously assigned */
printf("\tseq_delayInit(ssId, %d, (", delay_id);
/* Evaluate & generate the 3-rd parameter (an expression) */
eval_expr(EVENT_STMT, ep->left, sp, 0);
/* Complete the function call */
printf("));\n");
}
/* Generate action processing functions:
/* Generate action processing functions:
Each state has one action routine. It's name is derived from the
state set name and the state name.
*/
@@ -78,17 +135,20 @@ Expr *ssp; /* Parent state set */
Expr *ap;
int trans_num;
extern char *prog_name;
extern line_num;
/* Action function declaration */
printf("\n/* Action function for state \"%s\" in state set \"%s\" */\n",
sp->value, ssp->value);
/* action function declaration with ss_ptr as parameter */
printf("static 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);

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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