Initial revision

This commit is contained in:
zimoch
2010-11-29 10:38:06 +00:00
commit 90d03cb45e
1557 changed files with 241151 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
TOP=../..
include $(TOP)/configure/CONFIG
TEMPLATES_DIR = makeBaseApp
TEMPLATES += top/Makefile
TEMPLATES += top/configure/CONFIG
TEMPLATES += top/configure/CONFIG_SITE
TEMPLATES += top/configure/Makefile
TEMPLATES += top/configure/RELEASE
TEMPLATES += top/configure/RULES
TEMPLATES += top/configure/RULES.ioc
TEMPLATES += top/configure/RULES_DIRS
TEMPLATES += top/configure/RULES_TOP
TEMPLATES += top/supportApp/Makefile
TEMPLATES += top/supportApp/Db/Makefile
TEMPLATES += top/supportApp/src/Makefile
TEMPLATES += top/supportApp/src/_APPNAME_.dbd
TEMPLATES += top/iocApp/Makefile
TEMPLATES += top/iocApp/Db/Makefile
TEMPLATES += top/iocApp/src/Makefile
TEMPLATES += top/iocApp/src/_APPNAME_Main.cpp
TEMPLATES += top/exampleApp/Makefile
TEMPLATES += top/exampleApp/Db/Makefile
TEMPLATES += top/exampleApp/Db/dbExample1.db
TEMPLATES += top/exampleApp/Db/dbExample2.db
TEMPLATES += top/exampleApp/Db/dbSubExample.db
TEMPLATES += top/exampleApp/Db/user.substitutions
TEMPLATES += top/exampleApp/Db/userHost.substitutions
TEMPLATES += top/exampleApp/src/Makefile
TEMPLATES += top/exampleApp/src/xxxRecord.dbd
TEMPLATES += top/exampleApp/src/xxxRecord.c
TEMPLATES += top/exampleApp/src/devXxxSoft.c
TEMPLATES += top/exampleApp/src/xxxSupport.dbd
TEMPLATES += top/exampleApp/src/sncExample.stt
TEMPLATES += top/exampleApp/src/sncProgram.st
TEMPLATES += top/exampleApp/src/sncExample.dbd
TEMPLATES += top/exampleApp/src/dbSubExample.c
TEMPLATES += top/exampleApp/src/dbSubExample.dbd
TEMPLATES += top/exampleApp/src/_APPNAME_Main.cpp
TEMPLATES += top/exampleApp/src/_APPNAME_Hello.c
TEMPLATES += top/exampleApp/src/_APPNAME_Hello.dbd
TEMPLATES += top/exampleApp/src/initTrace.c
TEMPLATES += top/exampleApp/src/initTrace.dbd
TEMPLATES += top/exampleBoot/Makefile
TEMPLATES += top/exampleBoot/nfsCommands@vxWorks
TEMPLATES += top/exampleBoot/nfsCommands@RTEMS
TEMPLATES += top/exampleBoot/ioc/Makefile@Common
TEMPLATES += top/exampleBoot/ioc/Makefile@vxWorks
TEMPLATES += top/exampleBoot/ioc/Makefile@win32
TEMPLATES += top/exampleBoot/ioc/st.cmd@Common
TEMPLATES += top/exampleBoot/ioc/st.cmd@vxWorks
TEMPLATES += top/exampleBoot/ioc/st.cmd@RTEMS
TEMPLATES += top/exampleBoot/ioc/README@Common
TEMPLATES += top/exampleBoot/ioc/README@vxWorks
TEMPLATES += top/caClientApp/Makefile
TEMPLATES += top/caClientApp/caExample.c
TEMPLATES += top/caClientApp/caMonitor.c
TEMPLATES += top/caServerApp/Makefile
TEMPLATES += top/caServerApp/README
TEMPLATES += top/caServerApp/exAsyncPV.cc
TEMPLATES += top/caServerApp/exChannel.cc
TEMPLATES += top/caServerApp/exPV.cc
TEMPLATES += top/caServerApp/exScalarPV.cc
TEMPLATES += top/caServerApp/exServer.cc
TEMPLATES += top/caServerApp/exServer.h
TEMPLATES += top/caServerApp/exVectorPV.cc
TEMPLATES += top/caServerApp/main.cc
TEMPLATES += top/caServerApp/test.adl
TEMPLATES += top/caServerApp/vxEntry.cc
TEMPLATES += top/iocBoot/Makefile
TEMPLATES += top/iocBoot/nfsCommands@vxWorks
TEMPLATES += top/iocBoot/nfsCommands@RTEMS
TEMPLATES += top/iocBoot/ioc/Makefile@Common
TEMPLATES += top/iocBoot/ioc/Makefile@vxWorks
TEMPLATES += top/iocBoot/ioc/Makefile@win32
TEMPLATES += top/iocBoot/ioc/st.cmd@Common
TEMPLATES += top/iocBoot/ioc/st.cmd@Cross
TEMPLATES += top/iocBoot/ioc/st.cmd@vxWorks
TEMPLATES += top/iocBoot/ioc/st.cmd@RTEMS
SCRIPTS_HOST += makeBaseApp.pl
include $(TOP)/configure/RULES
+508
View File
@@ -0,0 +1,508 @@
eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
if $running_under_some_shell; # makeBaseApp
# Authors: Ralph Lange, Marty Kraimer, Andrew Johnson and Janet Anderson
# Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd
use Cwd;
use Getopt::Std;
use File::Find;
use File::Path;
$app_top = cwd();
%release = (TOP => $app_top);
@apps = (TOP);
$bad_ident_chars = '[^0-9A-Za-z_]';
&GetUser; # Ensure we know who's in charge
&readRelease("configure/RELEASE", \%release, \@apps) if (-r "configure/RELEASE");
&readRelease("configure/RELEASE.$ENV{EPICS_HOST_ARCH}", \%release, \@apps)
if (-r "configure/RELEASE.$ENV{EPICS_HOST_ARCH}");
&expandRelease(\%release, \@apps);
&get_commandline_opts; # Check command-line options
#
# Declare two default callback routines for file copy plus two
# hook routines to add conversions
# These may be overriden within $top/$apptypename/Replace.pl
# First: the hooks
sub ReplaceFilenameHook { return $_[0]; }
sub ReplaceLineHook { return $_[0]; }
# ReplaceFilename
# called with the source (template) file or directory name, returns
# the target file/dir name (current directory is the application top).
# Inside iocBoot, templates can install different files for different
# IOC architectures or OSs: 'name@<arch>', 'name@<os>' & 'name@Common'
# The best match is installed as 'name', but if the best matching file
# is empty then no file is created, allowing a file 'name@Common' to
# be omitted by providing an empty 'name@<arch>' or 'name@<os>'.
# Returning an empty string means don't copy this file.
sub ReplaceFilename { # (filename)
my($file) = $_[0];
$file =~ s|.*/CVS/?.*||; # Ignore CVS files and Replace.pl scripts
$file =~ s|.*/$apptypename/Replace\.pl$||;
if($opt_i) {
# Handle name@arch stuff, copy only the closest matching file
# NB: Won't work with directories, don't use '@' in a directory name!
my($base,$filearch) = split /@/, $file;
if ($base ne $file) { # This file is arch-specific
my($os,$cpu,$toolset) = split /-/, $arch, 3;
if (-r "$base\@$arch") { # A version exists for this arch
$base = '' unless ($filearch eq $arch && -s $file);
} elsif (-r "$base\@$os") { # A version exists for this os
$base = '' unless ($filearch eq $os && -s $file);
} elsif ( $ENV{EPICS_HOST_ARCH} !~ "$os-$cpu" &&
-r "$base\@Cross" ) { # Cross version exists
$base = '' unless ($filearch eq "Cross" && -s $file);
} elsif (-r "$base\@Common") { # Default version exists
$base = '' unless ($filearch eq "Common" && -s $file);
} else { # No default version
$base = '';
}
$file = $base; # Strip the @... part from the target name
}
$file =~ s|/$apptypename|/iocBoot|; # templateBoot => iocBoot
}
if ($ioc) {
$file =~ s|/iocBoot/ioc|/iocBoot/$ioc|; # name the ioc subdirectory
$file =~ s|_IOC_|$ioc|;
} else {
$file =~ s|.*/iocBoot/ioc/?.*||; # Not doing IOCs here
}
if ($app) {
$file =~ s|/$apptypename|/$appdir|; # templateApp => namedApp
$file =~ s|/$appdir/configure|/configure/$apptype|;
}
$file =~ s|_APPNAME_|$appname|;
$file =~ s|_APPTYPE_|$apptype|;
my $qmtop = quotemeta($top);
$file =~ s|$qmtop/||; # Change to the target location
$file = &ReplaceFilenameHook($file); # Call the apptype's hook
return $file;
}
# ReplaceLine
# called with one line of a file, returns the line after replacing
# this and that
sub ReplaceLine { # (line)
my($line) = $_[0];
$line =~ s/_IOC_/$ioc/g if ($ioc);
$line =~ s/_USER_/$user/go;
$line =~ s/_EPICS_BASE_/$app_epics_base/go;
$line =~ s/_TEMPLATE_TOP_/$app_template_top/go;
$line =~ s/_TOP_/$app_top/go;
$line =~ s/_APPNAME_/$appname/g;
$line =~ s/_CSAFEAPPNAME_/$csafeappname/g;
$line =~ s/_APPTYPE_/$apptype/go;
$line =~ s/_ARCH_/$arch/go if ($opt_i);
$line = &ReplaceLineHook($line); # Call the apptype's hook
return $line;
}
# Source replace overrides for file copy
if (-r "$top/$apptypename/Replace.pl") {
require "$top/$apptypename/Replace.pl";
}
#
# Copy files and dirs from <top> (other than App & Boot) if not present
#
opendir TOPDIR, "$top" or die "Can't open $top: $!";
foreach $f ( grep !/^\.\.?$|^[^\/]*(App|Boot)/, readdir TOPDIR ) {
find({wanted => \&FCopyTree, follow => 1}, "$top/$f") unless (-e "$f");
}
closedir TOPDIR;
#
# Create ioc directories
#
if ($opt_i) {
find({wanted => \&FCopyTree, follow => 1}, "$top/$apptypename");
$appname=$appnameIn if $appnameIn;
foreach $ioc ( @names ) {
($appname = $ioc) =~ s/App$// if !$appnameIn;
($csafeappname = $appname) =~ s/$bad_ident_chars/_/og;
$ioc = "ioc" . $ioc unless ($ioc =~ m/ioc/);
if (-d "iocBoot/$ioc") {
print "iocBoot/$ioc exists, not modified.\n";
next;
}
find({wanted => \&FCopyTree, follow => 1}, "$top/$apptypename/ioc");
}
exit 0; # finished here for -i (no xxxApps)
}
#
# Create app directories (if any names given)
#
foreach $app ( @names ) {
($appname = $app) =~ s/App$//;
($csafeappname = $appname) =~ s/$bad_ident_chars/_/og;
$appdir = $appname . "App";
if (-d "$appdir") {
print "$appname exists, not modified.\n";
next;
}
print "Creating $appname from template type $apptypename\n" if $opt_d;
find({wanted => \&FCopyTree, follow => 1}, "$top/$apptypename/");
}
exit 0; # END OF SCRIPT
#
# Get commandline options and check for validity
#
sub get_commandline_opts { #no args
getopts("a:b:dhilp:T:t:") or Cleanup(1);
# Options help
Cleanup(0) if $opt_h;
# Locate epics_base
my ($command) = UnixPath($0);
if ($opt_b) { # first choice is -b base
$epics_base = UnixPath($opt_b);
} elsif ($release{"EPICS_BASE"}) { # second choice is configure/RELEASE
$epics_base = UnixPath($release{"EPICS_BASE"});
$epics_base =~s|^\$\(TOP\)/||;
} elsif ($ENV{EPICS_MBA_BASE}) { # third choice is env var EPICS_MBA_BASE
$epics_base = UnixPath($ENV{EPICS_MBA_BASE});
} elsif ($command =~ m|/bin/|) { # assume script was run with full path to base
$epics_base = $command;
$epics_base =~ s|^(.*)/bin/.*makeBaseApp.*|$1|;
}
$epics_base and -d "$epics_base" or Cleanup(1, "Can't find EPICS base");
$app_epics_base = LocalPath($epics_base);
$app_epics_base =~ s|^\.\.|\$(TOP)/..|;
# Locate template top directory
if ($opt_T) { # first choice is -T templ-top
$top = UnixPath($opt_T);
} elsif ($release{"TEMPLATE_TOP"}) { # second choice is configure/RELEASE
$top = UnixPath($release{"TEMPLATE_TOP"});
$top =~s|^\$\(EPICS_BASE\)|$epics_base|;
$top =~s|^\$\(TOP\)/||;
}
$top = $ENV{EPICS_MBA_TEMPLATE_TOP} unless $top && -d $top; # third choice is env var
$top = $epics_base . "/templates/makeBaseApp/top" unless $top && -d $top; # final
$top and -d "$top" or Cleanup(1, "Can't find template top directory");
$app_template_top = LocalPath($top);
$app_template_top =~s|^\.\.|\$(TOP)/..|;
$app_template_top =~s|^$epics_base/|\$\(EPICS_BASE\)/|;
# Print application type list?
if ($opt_l) {
&ListAppTypes;
exit 0; # finished for -l command
}
if (!@ARGV){
if ($opt_t) {
if ($opt_i) {
my @iocs = map {s/iocBoot\///; $_} glob 'iocBoot/ioc*';
if (@iocs) {
print "The following IOCs already exist here:\n",
map {" $_\n"} @iocs;
}
print "Name the IOC(s) to be created.\n",
"Names given will have \"ioc\" prepended to them.\n",
"IOC names? ";
} else {
print "Name the application(s) to be created.\n",
"Names given will have \"App\" appended to them.\n",
"Application names? ";
}
$namelist = <STDIN>;
chomp($namelist);
@names = split /[\s,]/, $namelist;
} else {
Cleanup(1);
}
} else {
@names = @ARGV;
}
# ioc architecture and application name
if ($opt_i && @names) {
# ioc architecture
opendir BINDIR, "$epics_base/bin" or die "Can't open $epics_base/bin: $!";
my @archs = grep !/^\./, readdir BINDIR; # exclude .files
closedir BINDIR;
if ($opt_a) {
$arch = $opt_a;
} elsif (@archs == 1) {
$arch = $archs[0];
print "Using target architecture $arch (only one available)\n";
} else {
print "The following target architectures are available in base:\n";
foreach $arch (@archs) {
print " $arch\n";
}
print "What architecture do you want to use? ";
$arch = <STDIN>;
chomp($arch);
}
grep /^$arch$/, @archs or Cleanup(1, "Target architecture $arch not available");
# Application name
if ($opt_p){
$appnameIn = $opt_p if ($opt_p);
} else {
my @apps = glob '*App';
if (@apps) {
print "The following applications are available:\n",
map {s/App$//; " $_\n"} @apps;
}
print "What application should the IOC(s) boot?\n",
"The default uses the IOC's name, even if not listed above.\n",
"Application name? ";
$appnameIn = <STDIN>;
chomp($appnameIn);
}
}
# Application type
$appext = $opt_i ? "Boot" : "App";
if ($opt_t) { # first choice is -t type
$apptype = $opt_t;
$apptype =~ s/$appext$//;
} elsif ($ENV{EPICS_MBA_DEF_APP_TYPE}) { # second choice is environment var
$apptype = $ENV{EPICS_MBA_DEF_APP_TYPE};
$apptype =~ s/(App)|(Boot)$//;
} elsif (-d "$top/default$appext") { # third choice is default
$apptype = "default";
} elsif (-d "$top/example$appext") { # fourth choice is example
$apptype = "example";
}
$apptype or Cleanup(1, "No application type set");
$apptypename = $apptype . $appext;
(-r "$top/$apptypename") or
Cleanup(1, "Can't access template directory '$top/$apptypename'.\n");
print "\nCommand line / environment options validated:\n"
. " Templ-Top: $top\n"
. "Templ-Type: $apptype\n"
. "Templ-Name: $apptypename\n"
. " opt_i: $opt_i\n"
. " arch: $arch\n"
. "EPICS-Base: $epics_base\n\n" if $opt_d;
}
#
# Parse a configure/RELEASE file.
#
# NB: This subroutine also appears in base/configure/tools/convertRelease.pl
# If you make changes here, they will be needed there as well.
#
sub readRelease {
my ($file, $Rmacros, $Rapps) = @_;
# $Rmacros is a reference to a hash, $Rapps a ref to an array
my ($pre, $var, $post, $macro, $path);
local *IN;
open(IN, $file) or die "Can't open $file: $!\n";
while (<IN>) {
chomp;
s/\r$//; # Shouldn't need this, but sometimes...
s/\s*#.*$//; # Remove trailing comments
next if /^\s*$/; # Skip blank lines
# Expand all already-defined macros in the line:
while (($pre,$var,$post) = /(.*)\$\((\w+)\)(.*)/) {
last unless (exists $Rmacros->{$var});
$_ = $pre . $Rmacros->{$var} . $post;
}
# Handle "<macro> = <path>"
($macro, $path) = /^\s*(\w+)\s*=\s*(.*)/;
if ($macro ne "") {
$Rmacros->{$macro} = $path;
push @$Rapps, $macro;
next;
}
# Handle "include <path>" syntax
($path) = /^\s*include\s+(.*)/;
&readRelease($path, $Rmacros, $Rapps) if (-r $path);
}
close IN;
}
sub expandRelease {
my ($Rmacros, $Rapps) = @_;
# $Rmacros is a reference to a hash, $Rapps a ref to an array
# Expand any (possibly nested) macros that were defined after use
while (($macro, $path) = each %$Rmacros) {
while (($pre,$var,$post) = $path =~ /(.*)\$\((\w+)\)(.*)/) {
$path = $pre . $Rmacros->{$var} . $post;
$Rmacros->{$macro} = $path;
}
}
}
#
# List application types
#
sub ListAppTypes { # no args
opendir TYPES, "$top" or die "Can't open $top: $!";
my @allfiles = readdir TYPES;
closedir TYPES;
my @apps = grep /.*App$/, @allfiles;
my @boots = grep /.*Boot$/, @allfiles;
print "Valid application types are:\n";
foreach $name (@apps) {
$name =~ s|App||;
printf "\t$name\n" if ($name && -r "$top/$name" . "App");
}
print "Valid iocBoot types are:\n";
foreach $name (@boots) {
$name =~ s|Boot||;
printf "\t$name\n" if ($name && -r "$top/$name" . "Boot");;
}
}
#
# Copy a file with replacements
#
sub CopyFile { # (source)
$source = $_[0];
$target = &ReplaceFilename($source);
if ($target and !-e $target) {
open(INP, "<$source") and open(OUT, ">$target")
or die "$! Copying $source -> $target";
print "Copying file $source -> $target\n" if $opt_d;
while (<INP>) {
print OUT &ReplaceLine($_);
}
close INP; close OUT;
}
}
#
# Find() callback for file or structure copy
#
sub FCopyTree {
chdir $app_top; # Sigh
if (-d "$File::Find::name"
and ($dir = &ReplaceFilename($File::Find::name))) {
print "Creating directory $dir\n" if $opt_d;
&mkpath($dir) unless (-d "$dir");
} else {
&CopyFile($File::Find::name);
}
chdir $File::Find::dir;
}
#
# Cleanup and exit
#
sub Cleanup { # (return-code [ messsage-line1, line 2, ... ])
my ($rtncode, @message) = @_;
if (@message) {
print join("\n", @message), "\n";
} else {
&Usage;
}
exit $rtncode;
}
sub Usage {
print <<EOF;
Usage:
<base>/bin/<arch>/makeBaseApp.pl -h
display help on command options
<base>/bin/<arch>/makeBaseApp.pl -l [options]
list application types
<base>/bin/<arch>/makeBaseApp.pl -t type [options] [app ...]
create application directories
<base>/bin/<arch>/makeBaseApp.pl -i -t type [options] [ioc ...]
create ioc boot directories
where
app Application name (the created directory will have \"App\" appended)
ioc IOC name (the created directory will have \"ioc\" prepended)
EOF
print <<EOF if ($opt_h);
-a arch Set the IOC architecture for use with -i (e.g. vxWorks-68040)
If arch is not specified, you will be prompted
-b base Set the location of EPICS base (full path)
If not specified, base path is taken from configure/RELEASE
If configure does not exist, from environment
If not found in environment, from makeBaseApp.pl location
-d Enable debug messages
-i Specifies that ioc boot directories will be generated
-l List valid application types for this installation
If this is specified the other options are not used
-p app Set the application name for use with -i
If not specified, you will be prompted
-T top Set the template top directory (where the application templates are)
If not specified, top path is taken from configure/RELEASE
If configure does not exist, top path is taken from environment
If not found in environment, the templates from EPICS base are used
-t type Set the application type (-l for a list of valid types)
If not specified, type is taken from environment
If not found in environment, \"default\" is used
Environment:
EPICS_MBA_DEF_APP_TYPE Application type you want to use as default
EPICS_MBA_TEMPLATE_TOP Template top directory
EPICS_MBA_BASE Location of EPICS base
Example: Create exampleApp
<base>/bin/<arch>/makeBaseApp.pl -t example example
<base>/bin/<arch>/makeBaseApp.pl -i -t example example
EOF
}
sub GetUser {
# add to this list if new possibilities arise,
# currently it's UNIX and WIN32:
$user = $ENV{USER} || $ENV{USERNAME} || Win32::LoginName();
$user =~ s/\s+//g; # Bl**dy Windows stupidity...
unless ($user) {
print "Strange, I cannot figure out your user name!\n";
print "What should you be called ? ";
$user = <STDIN>;
chomp $user;
}
die "No user name" unless $user;
}
# Path rewriting rules for various OSs
# These functions are duplicated in configure/convertRelease.pl
sub UnixPath {
my ($newpath) = @_;
if ($^O eq 'cygwin') {
$newpath =~ s{\\}{/}go;
$newpath =~ s{^([a-zA-Z]):/}{/cygdrive/$1/};
} elsif ($^O eq 'MSWin32') {
$newpath =~ s{\\}{/}go;
} elsif ($^O eq 'sunos') {
$newpath =~ s{^/tmp_mnt/}{/};
}
return $newpath;
}
sub LocalPath {
my ($newpath) = @_;
if ($^O eq "cygwin") {
$newpath =~ s{^/cygdrive/([a-zA-Z])/}{$1:/};
} elsif ($^O eq "darwin") {
# These rules are likely to be site-specific
$newpath =~ s{^/private/var/auto\.home/}{/home/}; # APS
}
return $newpath;
}
+17
View File
@@ -0,0 +1,17 @@
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), configure)
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *App))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard iocBoot))
define DIR_template
$(1)_DEPEND_DIRS = configure
endef
$(foreach dir, $(filter-out configure,$(DIRS)),$(eval $(call DIR_template,$(dir))))
iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS))
include $(TOP)/configure/RULES_TOP
+19
View File
@@ -0,0 +1,19 @@
TOP=..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
PROD_HOST += caExample
caExample_SRCS += caExample.c
caExample_LIBS += $(EPICS_BASE_HOST_LIBS)
PROD_HOST += caMonitor
caMonitor_SRCS += caMonitor.c
caMonitor_LIBS += $(EPICS_BASE_HOST_LIBS)
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1,25 @@
/*caExample.c*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cadef.h"
int main(int argc,char **argv)
{
double data;
chid mychid;
if(argc != 2) {
fprintf(stderr,"usage: caExample pvname\n");
exit(1);
}
SEVCHK(ca_context_create(ca_disable_preemptive_callback),"ca_context_create");
SEVCHK(ca_create_channel(argv[1],NULL,NULL,10,&mychid),"ca_create_channel failure");
SEVCHK(ca_pend_io(5.0),"ca_pend_io failure");
SEVCHK(ca_get(DBR_DOUBLE,mychid,(void *)&data),"ca_get failure");
SEVCHK(ca_pend_io(5.0),"ca_pend_io failure");
printf("%s %f\n",argv[1],data);
return(0);
}
+127
View File
@@ -0,0 +1,127 @@
/*caMonitor.c*/
/* This example accepts a file containing a list of pvs to monitor
* It prints a message for all ca evemts: connection, access rights, data
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cadef.h"
#include "dbDefs.h"
#include "epicsString.h"
#include "cantProceed.h"
#define MAX_PV 1000
#define MAX_PV_NAME_LEN 40
typedef struct{
char value[20];
chid mychid;
evid myevid;
} MYNODE;
static void printChidInfo(chid chid, char *message)
{
printf("\n%s\n",message);
printf("pv: %s type(%d) nelements(%ld) host(%s)",
ca_name(chid),ca_field_type(chid),ca_element_count(chid),
ca_host_name(chid));
printf(" read(%d) write(%d) state(%d)\n",
ca_read_access(chid),ca_write_access(chid),ca_state(chid));
}
static void exceptionCallback(struct exception_handler_args args)
{
chid chid = args.chid;
long stat = args.stat; /* Channel access status code*/
const char *channel;
static char *noname = "unknown";
channel = (chid ? ca_name(chid) : noname);
if(chid) printChidInfo(chid,"exceptionCallback");
printf("exceptionCallback stat %s channel %s\n",
ca_message(stat),channel);
}
static void connectionCallback(struct connection_handler_args args)
{
chid chid = args.chid;
printChidInfo(chid,"connectionCallback");
}
static void accessRightsCallback(struct access_rights_handler_args args)
{
chid chid = args.chid;
printChidInfo(chid,"accessRightsCallback");
}
static void eventCallback(struct event_handler_args eha)
{
chid chid = eha.chid;
if(eha.status!=ECA_NORMAL) {
printChidInfo(chid,"eventCallback");
} else {
char *pdata = (char *)eha.dbr;
printf("Event Callback: %s = %s\n",ca_name(eha.chid),pdata);
}
}
int main(int argc,char **argv)
{
char *filename;
int npv = 0;
MYNODE *pmynode[MAX_PV];
char *pname[MAX_PV];
int i;
char tempStr[MAX_PV_NAME_LEN];
char *pstr;
FILE *fp;
if (argc != 2) {
fprintf(stderr,"usage: caMonitor filename\n");
exit(1);
}
filename = argv[1];
fp = fopen(filename,"r");
if (!fp) {
perror("fopen failed");
return(1);
}
while (npv < MAX_PV) {
size_t len;
pstr = fgets(tempStr, MAX_PV_NAME_LEN, fp);
if (!pstr) break;
len = strlen(pstr);
if (len <= 1) continue;
pstr[len - 1] = '\0'; /* Strip newline */
pname[npv] = epicsStrDup(pstr);
pmynode[npv] = callocMustSucceed(1, sizeof(MYNODE), "caMonitor");
npv++;
}
SEVCHK(ca_context_create(ca_disable_preemptive_callback),"ca_context_create");
SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
"ca_add_exception_event");
for(i=0; i<npv; i++) {
SEVCHK(ca_create_channel(pname[i],connectionCallback,
pmynode[i],20,&pmynode[i]->mychid),
"ca_create_channel");
SEVCHK(ca_replace_access_rights_event(pmynode[i]->mychid,
accessRightsCallback),
"ca_replace_access_rights_event");
SEVCHK(ca_add_event(DBR_STRING,pmynode[i]->mychid,eventCallback,
pmynode[i],&pmynode[i]->myevid),
"ca_add_event");
}
/*Should never return from following call*/
SEVCHK(ca_pend_event(0.0),"ca_pend_event");
return(0);
}
+34
View File
@@ -0,0 +1,34 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP=..
include $(TOP)/configure/CONFIG
PROD_LIBS += $(EPICS_BASE_HOST_LIBS)
#
# Added ws2_32 winmm user32 for the non-dll build
#
SYS_PROD_LIBS_WIN32 += ws2_32 advapi32 user32
SRCS += main.cc
SRCS += exServer.cc
SRCS += exPV.cc
SRCS += exVectorPV.cc
SRCS += exScalarPV.cc
SRCS += exAsyncPV.cc
SRCS += exChannel.cc
PROD_HOST = casexample
include $(TOP)/configure/RULES
+63
View File
@@ -0,0 +1,63 @@
The files in this directory build an example CA server. This code
is meant to provide some examples of how the CA server library can
be used but is not intended to be an example of exemplary code organization
and therefore care should be taken when emulating what is found here.
The example server exports the process variables (PVs) in the table below.
ScanPeriod Name HOPR LOPR Type Asynchronous Elements
.1 "jane" 10.0 0.0 DBR_DOUBLE No 1
2.0 "fred" 10.0 -10.0 DBR_DOUBLE No 1
.1 "janet" 10.0 0.0 DBR_DOUBLE Yes 1
2.0 "freddy"10.0 -10.0 DBR_DOUBLE Yes 1
2.0 "alan" 10.0 -10.0 DBR_DOUBLE No 100
20.0 "albert"10.0 -10.0 DBR_DOUBLE No 1000
-1.0 "boot" 10.0 -10.0 DBR_ENUM No 1
-1.0 "booty" 10.0 -10.0 DBR_ENUM Yes 1
-1.0 "bill" 10.0 -10.0 DBR_DOUBLE No 1
-1.0 "billy" 10.0 -10.0 DBR_DOUBLE Yes 1
-1.0 "bloaty"10.0 -10.0 DBR_DOUBLE No 100000
Many ca servers will find that synchronous variables will meet
their needs and will not require the increased complexity
associated with asynchronous PVs. Asynchronous PVs are needed
when read and write IO requests cant be completed immediately.
The PVs in the example server are updated periodically if the
"ScanPeriod" column above contains a positive number. Some random
"noise" is added to a PV's current value each time that it is
updated.
usage:
excas [-d<debug level> -t<execution time> -p<PV name prefix>
-c<numbered alias count> -s<1=scan on (default), 0=scan off>
-ss<1=synchronous scan (default), 0=asynchronous scan>]
-d<debug level>
Increased diagnostics messages with increasing debug level. Defaults to no
messages.
-t<execution time>
Specifies the duration that the server will run. Defaults to forever.
-p<PV name prefix>
Specifies the prefix applied to all PV names. If you specify "-pxxx:"
then clients must specify PV names like "xxx:fred" or "xxx:jane".
This is useful when several example servers are running on the same
IP subnet for testing purposes. Defaults to no prefix.
-c<numbered alias count>
Useful when you need lots of aliased PV names. The alias names are
of the form "fred1", "fred2", etc. Defaults to no aliases.
-s<1=scan on (default), 0=scan off>
Used to turn off updating of the PVs with random noise. Default is
to update all PVs with a positive scan period.
-ss<1=synchronous scan (default), 0=asynchronous scan>
Controls updating of PVs from an asynchronous thread (tests thread
safety of the server library). Defaults to synchronous.
@@ -0,0 +1,229 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
// (asynchrronous process variable)
//
#include "exServer.h"
exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
bool preCreateFlag, bool scanOnIn,
double asyncDelayIn ) :
exScalarPV ( cas, setup, preCreateFlag, scanOnIn ),
asyncDelay ( asyncDelayIn ),
simultAsychReadIOCount ( 0u ),
simultAsychWriteIOCount ( 0u )
{
}
//
// exAsyncPV::read()
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
}
}
this->simultAsychReadIOCount++;
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::writeNotify()
//
caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
}
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::write()
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
// implement the discard intermediate values, but last value
// sent always applied behavior that IOCs provide excepting
// that we will alow N requests to pend instead of a limit
// of only one imposed in the IOC
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
// Implementing a specialized update for exAsyncPV
// allows standby value to update when we update
// the PV from an asynchronous write timer expiration
// which is a better time compared to removeIO below
// which, if used, gets the reads and writes out of
// order. This type of reordering can cause the
// regression tests to fail.
caStatus exAsyncPV :: updateFromAsyncWrite ( const gdd & src )
{
caStatus stat = this->update ( src );
if ( this->simultAsychWriteIOCount <=1 &&
pStandbyValue.valid () ) {
//printf("updateFromAsyncWrite: write standby\n");
stat = this->update ( *this->pStandbyValue );
this->pStandbyValue.set ( 0 );
}
return stat;
}
void exAsyncPV::removeReadIO ()
{
if ( this->simultAsychReadIOCount > 0u ) {
this->simultAsychReadIOCount--;
}
else {
fprintf ( stderr, "inconsistent simultAsychReadIOCount?\n" );
}
}
void exAsyncPV::removeWriteIO ()
{
if ( this->simultAsychWriteIOCount > 0u ) {
this->simultAsychWriteIOCount--;
if ( this->simultAsychWriteIOCount == 0 &&
pStandbyValue.valid () ) {
//printf("removeIO: write standby\n");
this->update ( *this->pStandbyValue );
this->pStandbyValue.set ( 0 );
}
}
else {
fprintf ( stderr, "inconsistent simultAsychWriteIOCount?\n" );
}
}
//
// exAsyncWriteIO::exAsyncWriteIO()
//
exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
const casCtx & ctxIn, exAsyncPV & pvIn,
const gdd & valueIn, double asyncDelay ) :
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, asyncDelay );
}
//
// exAsyncWriteIO::~exAsyncWriteIO()
//
exAsyncWriteIO::~exAsyncWriteIO()
{
this->timer.destroy ();
// if the timer hasnt expired, and the value
// hasnt been written then force it to happen
// now so that regression testing works
if ( this->pValue.valid () ) {
this->pv.updateFromAsyncWrite ( *this->pValue );
}
this->pv.removeWriteIO();
}
//
// exAsyncWriteIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncWriteIO::
expire ( const epicsTime & /* currentTime */ )
{
assert ( this->pValue.valid () );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
return noRestart;
}
//
// exAsyncReadIO::exAsyncReadIO()
//
exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
exAsyncPV & pvIn, gdd & protoIn,
double asyncDelay ) :
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, asyncDelay );
}
//
// exAsyncReadIO::~exAsyncReadIO()
//
exAsyncReadIO::~exAsyncReadIO()
{
this->pv.removeReadIO ();
this->timer.destroy ();
}
//
// exAsyncReadIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus
exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
//
// map between the prototype in and the
// current value
//
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
return noRestart;
}
@@ -0,0 +1,41 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
//
#include "exServer.h"
//
// exChannel::setOwner ()
//
void exChannel::setOwner(const char * const /* pUserName */,
const char * const /* pHostName */)
{
}
//
// exChannel::readAccess ()
//
bool exChannel::readAccess () const
{
return true;
}
//
// exChannel::writeAccess ()
//
bool exChannel::writeAccess () const
{
return true;
}
+345
View File
@@ -0,0 +1,345 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
//
#include "exServer.h"
#include "gddApps.h"
//
// static data for exPV
//
char exPV::hasBeenInitialized = 0;
gddAppFuncTable<exPV> exPV::ft;
epicsTime exPV::currentTime;
//
// special gddDestructor guarantees same form of new and delete
//
class exFixedStringDestructor: public gddDestructor {
virtual void run (void *);
};
//
// exPV::exPV()
//
exPV::exPV ( exServer & casIn, pvInfo & setup,
bool preCreateFlag, bool scanOnIn ) :
cas ( casIn ),
timer ( cas.createTimer() ),
info ( setup ),
interest ( false ),
preCreate ( preCreateFlag ),
scanOn ( scanOnIn )
{
//
// no dataless PV allowed
//
assert (this->info.getElementCount()>=1u);
//
// start a very slow background scan
// (we will speed this up to the normal rate when
// someone is watching the PV)
//
if ( this->scanOn && this->info.getScanPeriod () > 0.0 ) {
this->timer.start ( *this, this->getScanPeriod() );
}
}
//
// exPV::~exPV()
//
exPV::~exPV()
{
this->timer.destroy ();
this->info.unlinkPV();
}
//
// exPV::destroy()
//
// this is replaced by a noop since we are
// pre-creating most of the PVs during init in this simple server
//
void exPV::destroy()
{
if ( ! this->preCreate ) {
delete this;
}
}
//
// exPV::update()
//
caStatus exPV::update ( const gdd & valueIn )
{
# if DEBUG
printf("Setting %s too:\n", this->info.getName().string());
valueIn.dump();
# endif
caStatus status = this->updateValue ( valueIn );
if ( status || ( ! this->pValue.valid() ) ) {
return status;
}
//
// post a value change event
//
caServer * pCAS = this->getCAS();
if ( this->interest == true && pCAS != NULL ) {
casEventMask select ( pCAS->valueEventMask() | pCAS->logEventMask() );
this->postEvent ( select, *this->pValue );
}
return S_casApp_success;
}
//
// exScanTimer::expire ()
//
epicsTimerNotify::expireStatus
exPV::expire ( const epicsTime & /*currentTime*/ ) // X aCC 361
{
this->scan();
if ( this->scanOn && this->getScanPeriod() > 0.0 ) {
return expireStatus ( restart, this->getScanPeriod() );
}
else {
return noRestart;
}
}
//
// exPV::bestExternalType()
//
aitEnum exPV::bestExternalType () const
{
return this->info.getType ();
}
//
// exPV::interestRegister()
//
caStatus exPV::interestRegister ()
{
if ( ! this->getCAS() ) {
return S_casApp_success;
}
this->interest = true;
if ( this->scanOn && this->getScanPeriod() > 0.0 &&
this->getScanPeriod() < this->timer.getExpireDelay() ) {
this->timer.start ( *this, this->getScanPeriod() );
}
return S_casApp_success;
}
//
// exPV::interestDelete()
//
void exPV::interestDelete()
{
this->interest = false;
}
//
// exPV::show()
//
void exPV::show ( unsigned level ) const
{
if (level>1u) {
if ( this->pValue.valid () ) {
printf ( "exPV: cond=%d\n", this->pValue->getStat () );
printf ( "exPV: sevr=%d\n", this->pValue->getSevr () );
printf ( "exPV: value=%f\n", static_cast < double > ( * this->pValue ) );
}
printf ( "exPV: interest=%d\n", this->interest );
this->timer.show ( level - 1u );
}
}
//
// exPV::initFT()
//
void exPV::initFT ()
{
if ( exPV::hasBeenInitialized ) {
return;
}
//
// time stamp, status, and severity are extracted from the
// GDD associated with the "value" application type.
//
exPV::ft.installReadFunc ("value", &exPV::getValue);
exPV::ft.installReadFunc ("precision", &exPV::getPrecision);
exPV::ft.installReadFunc ("graphicHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("graphicLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("controlHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("controlLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("alarmHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("alarmLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("alarmHighWarning", &exPV::getHighLimit);
exPV::ft.installReadFunc ("alarmLowWarning", &exPV::getLowLimit);
exPV::ft.installReadFunc ("units", &exPV::getUnits);
exPV::ft.installReadFunc ("enums", &exPV::getEnums);
exPV::hasBeenInitialized = 1;
}
//
// exPV::getPrecision()
//
caStatus exPV::getPrecision ( gdd & prec )
{
prec.put(4u);
return S_cas_success;
}
//
// exPV::getHighLimit()
//
caStatus exPV::getHighLimit ( gdd & value )
{
value.put(info.getHopr());
return S_cas_success;
}
//
// exPV::getLowLimit()
//
caStatus exPV::getLowLimit ( gdd & value )
{
value.put(info.getLopr());
return S_cas_success;
}
//
// exPV::getUnits()
//
caStatus exPV::getUnits( gdd & units )
{
aitString str("furlongs", aitStrRefConstImortal);
units.put(str);
return S_cas_success;
}
//
// exPV::getEnums()
//
// returns the eneumerated state strings
// for a discrete channel
//
// The PVs in this example are purely analog,
// and therefore this isnt appropriate in an
// analog context ...
//
caStatus exPV::getEnums ( gdd & enumsIn )
{
if ( this->info.getType () == aitEnumEnum16 ) {
static const unsigned nStr = 2;
aitFixedString *str;
exFixedStringDestructor *pDes;
str = new aitFixedString[nStr];
if (!str) {
return S_casApp_noMemory;
}
pDes = new exFixedStringDestructor;
if (!pDes) {
delete [] str;
return S_casApp_noMemory;
}
strncpy (str[0].fixed_string, "off",
sizeof(str[0].fixed_string));
strncpy (str[1].fixed_string, "on",
sizeof(str[1].fixed_string));
enumsIn.setDimension(1);
enumsIn.setBound (0,0,nStr);
enumsIn.putRef (str, pDes);
return S_cas_success;
}
return S_cas_success;
}
//
// exPV::getValue()
//
caStatus exPV::getValue ( gdd & value )
{
caStatus status;
if ( this->pValue.valid () ) {
gddStatus gdds;
gdds = gddApplicationTypeTable::
app_table.smartCopy ( &value, & (*this->pValue) );
if (gdds) {
status = S_cas_noConvert;
}
else {
status = S_cas_success;
}
}
else {
status = S_casApp_undefined;
}
return status;
}
//
// exPV::write()
// (synchronous default)
//
caStatus exPV::write ( const casCtx &, const gdd & valueIn )
{
return this->update ( valueIn );
}
//
// exPV::read()
// (synchronous default)
//
caStatus exPV::read ( const casCtx &, gdd & protoIn )
{
return this->ft.read ( *this, protoIn );
}
//
// exPV::createChannel()
//
// for access control - optional
//
casChannel *exPV::createChannel ( const casCtx &ctx,
const char * const /* pUserName */,
const char * const /* pHostName */ )
{
return new exChannel ( ctx );
}
//
// exFixedStringDestructor::run()
//
// special gddDestructor guarantees same form of new and delete
//
void exFixedStringDestructor::run ( void * pUntyped )
{
aitFixedString *ps = (aitFixedString *) pUntyped;
delete [] ps;
}
@@ -0,0 +1,120 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include "exServer.h"
#include "gddApps.h"
#define myPI 3.14159265358979323846
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// exScalarPV::scan
//
void exScalarPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
float newValue;
float limit;
int gddStatus;
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
// throughput under sunos4 because gettimeofday() is
// slow)
//
this->currentTime = epicsTime::getCurrent ();
pDD = new gddScalar ( gddAppType_value, aitEnumFloat64 );
if ( ! pDD.valid () ) {
return;
}
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference ();
assert ( ! gddStatus );
radians = ( rand () * 2.0 * myPI ) / RAND_MAX;
if ( this->pValue.valid () ) {
this->pValue->getConvert(newValue);
}
else {
newValue = 0.0f;
}
newValue += (float) ( sin (radians) / 10.0 );
limit = (float) this->info.getHopr ();
newValue = tsMin ( newValue, limit );
limit = (float) this->info.getLopr ();
newValue = tsMax ( newValue, limit );
*pDD = newValue;
aitTimeStamp gddts ( this->currentTime );
pDD->setTimeStamp ( & gddts );
status = this->update ( *pDD );
if (status!=S_casApp_success) {
errMessage ( status, "scalar scan update failed\n" );
}
}
//
// exScalarPV::updateValue ()
//
// NOTES:
// 1) This should have a test which verifies that the
// incoming value in all of its various data types can
// be translated into a real number?
// 2) We prefer to unreference the old PV value here and
// reference the incomming value because this will
// result in each value change events retaining an
// independent value on the event queue.
//
caStatus exScalarPV::updateValue ( const gdd & valueIn )
{
//
// Really no need to perform this check since the
// server lib verifies that all requests are in range
//
if ( ! valueIn.isScalar() ) {
return S_casApp_outOfBounds;
}
if ( ! pValue.valid () ) {
this->pValue = new gddScalar (
gddAppType_value, this->info.getType () );
if ( ! pValue.valid () ) {
return S_casApp_noMemory;
}
}
this->pValue->put ( & valueIn );
return S_casApp_success;
}
+436
View File
@@ -0,0 +1,436 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// fileDescriptorManager.process(delay);
// (the name of the global symbol has leaked in here)
//
//
// Example EPICS CA server
//
#include "exServer.h"
//
// static list of pre-created PVs
//
pvInfo exServer::pvList[] = {
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, aitEnumFloat64, excasIoSync, 1u),
pvInfo (2.0, "fred", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1u),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, aitEnumFloat64, excasIoAsync, 1u),
pvInfo (2.0, "freddy", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u),
pvInfo (2.0, "alan", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100u),
pvInfo (20.0, "albert", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1000u),
pvInfo (-1.0, "boot", 10.0f, -10.0f, aitEnumEnum16, excasIoSync, 1u),
pvInfo (1.0, "booty", 10.0f, -10.0f, aitEnumEnum16, excasIoAsync, 1u),
pvInfo (-1.0, "bill", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1u),
pvInfo (-1.0, "billy", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u)
};
const unsigned exServer::pvListNElem = NELEMENTS (exServer::pvList);
//
// static on-the-fly PVs
//
pvInfo exServer::billy (-1.0, "billybob", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u);
pvInfo exServer::bloater (.010, "bloater", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 10000u);
pvInfo exServer::bloaty (.010, "bloaty", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100000u);
//
// exServer::exServer()
//
exServer::exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOnIn,
bool asyncScan, double asyncDelayIn,
unsigned maxSimultAsyncIOIn ) :
pTimerQueue ( 0 ), simultAsychIOCount ( 0u ),
_maxSimultAsyncIO ( maxSimultAsyncIOIn ),
asyncDelay ( asyncDelayIn ), scanOn ( scanOnIn )
{
unsigned i;
exPV *pPV;
pvInfo *pPVI;
pvInfo *pPVAfter = &exServer::pvList[pvListNElem];
char pvAlias[256];
const char * const pNameFmtStr = "%.100s%.20s";
const char * const pAliasFmtStr = "%.100s%.20s%.6u";
exPV::initFT();
if ( asyncScan ) {
unsigned timerPriotity;
epicsThreadBooleanStatus etbs = epicsThreadLowestPriorityLevelAbove (
epicsThreadGetPrioritySelf (), & timerPriotity );
if ( etbs != epicsThreadBooleanStatusSuccess ) {
timerPriotity = epicsThreadGetPrioritySelf ();
}
this->pTimerQueue = & epicsTimerQueueActive::allocate ( false, timerPriotity );
}
//
// pre-create all of the simple PVs that this server will export
//
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
pPV = pPVI->createPV (*this, true, scanOnIn, this->asyncDelay );
if (!pPV) {
fprintf(stderr, "Unable to create new PV \"%s\"\n",
pPVI->getName());
}
//
// Install canonical (root) name
//
sprintf(pvAlias, pNameFmtStr, pvPrefix, pPVI->getName());
this->installAliasName(*pPVI, pvAlias);
//
// Install numbered alias names
//
for (i=0u; i<aliasCount; i++) {
sprintf(pvAlias, pAliasFmtStr, pvPrefix,
pPVI->getName(), i);
this->installAliasName(*pPVI, pvAlias);
}
}
//
// Install create on-the-fly PVs
// into the PV name hash table
//
sprintf ( pvAlias, pNameFmtStr, pvPrefix, billy.getName() );
this->installAliasName ( billy, pvAlias );
sprintf ( pvAlias, pNameFmtStr, pvPrefix, bloater.getName() );
this->installAliasName ( bloater, pvAlias );
sprintf ( pvAlias, pNameFmtStr, pvPrefix, bloaty.getName() );
this->installAliasName ( bloaty, pvAlias );
}
//
// exServer::~exServer()
//
exServer::~exServer()
{
this->destroyAllPV ();
this->stringResTbl.traverse ( &pvEntry::destroy );
}
void exServer::destroyAllPV ()
{
for ( unsigned i = 0;
i < NELEMENTS(exServer::pvList); i++ ) {
exServer::pvList[i].deletePV ();
}
}
//
// exServer::installAliasName()
//
void exServer::installAliasName(pvInfo &info, const char *pAliasName)
{
pvEntry *pEntry;
pEntry = new pvEntry(info, *this, pAliasName);
if (pEntry) {
int resLibStatus;
resLibStatus = this->stringResTbl.add(*pEntry);
if (resLibStatus==0) {
return;
}
else {
delete pEntry;
}
}
fprintf ( stderr,
"Unable to enter PV=\"%s\" Alias=\"%s\" in PV name alias hash table\n",
info.getName(), pAliasName );
}
//
// More advanced pvExistTest() isnt needed so we forward to
// original version. This avoids sun pro warnings and speeds
// up execution.
//
pvExistReturn exServer::pvExistTest
( const casCtx & ctx, const caNetAddr &, const char * pPVName )
{
return this->pvExistTest ( ctx, pPVName );
}
//
// exServer::pvExistTest()
//
pvExistReturn exServer::pvExistTest // X aCC 361
( const casCtx& ctxIn, const char * pPVName )
{
//
// lifetime of id is shorter than lifetime of pName
//
stringId id ( pPVName, stringId::refString );
pvEntry *pPVE;
//
// Look in hash table for PV name (or PV alias name)
//
pPVE = this->stringResTbl.lookup ( id );
if ( ! pPVE ) {
return pverDoesNotExistHere;
}
pvInfo & pvi = pPVE->getInfo();
//
// Initiate async IO if this is an async PV
//
if ( pvi.getIOType() == excasIoSync ) {
return pverExistsHere;
}
else {
if ( this->simultAsychIOCount >= this->_maxSimultAsyncIO ) {
return pverDoesNotExistHere;
}
this->simultAsychIOCount++;
exAsyncExistIO * pIO =
new exAsyncExistIO ( pvi, ctxIn, *this );
if ( pIO ) {
return pverAsyncCompletion;
}
else {
this->simultAsychIOCount--;
return pverDoesNotExistHere;
}
}
}
//
// exServer::pvAttach()
//
pvAttachReturn exServer::pvAttach // X aCC 361
(const casCtx &ctx, const char *pName)
{
//
// lifetime of id is shorter than lifetime of pName
//
stringId id(pName, stringId::refString);
exPV *pPV;
pvEntry *pPVE;
pPVE = this->stringResTbl.lookup(id);
if (!pPVE) {
return S_casApp_pvNotFound;
}
pvInfo &pvi = pPVE->getInfo();
//
// If this is a synchronous PV create the PV now
//
if (pvi.getIOType() == excasIoSync) {
pPV = pvi.createPV(*this, false, this->scanOn, this->asyncDelay );
if (pPV) {
return *pPV;
}
else {
return S_casApp_noMemory;
}
}
//
// Initiate async IO if this is an async PV
//
else {
if (this->simultAsychIOCount>=this->_maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
exAsyncCreateIO *pIO =
new exAsyncCreateIO ( pvi, *this, ctx,
this->scanOn, this->asyncDelay );
if (pIO) {
return S_casApp_asyncCompletion;
}
else {
this->simultAsychIOCount--;
return S_casApp_noMemory;
}
}
}
//
// exServer::setDebugLevel ()
//
void exServer::setDebugLevel ( unsigned level )
{
this->caServer::setDebugLevel ( level );
}
//
// exServer::createTimer ()
//
class epicsTimer & exServer::createTimer ()
{
if ( this->pTimerQueue ) {
return this->pTimerQueue->createTimer ();
}
else {
return this->caServer::createTimer ();
}
}
//
// pvInfo::createPV()
//
exPV *pvInfo::createPV ( exServer & cas, bool preCreateFlag,
bool scanOn, double asyncDelay )
{
if (this->pPV) {
return this->pPV;
}
exPV *pNewPV;
//
// create an instance of the appropriate class
// depending on the io type and the number
// of elements
//
if (this->elementCount==1u) {
switch (this->ioType){
case excasIoSync:
pNewPV = new exScalarPV ( cas, *this, preCreateFlag, scanOn );
break;
case excasIoAsync:
pNewPV = new exAsyncPV ( cas, *this,
preCreateFlag, scanOn, asyncDelay );
break;
default:
pNewPV = NULL;
break;
}
}
else {
if ( this->ioType == excasIoSync ) {
pNewPV = new exVectorPV ( cas, *this, preCreateFlag, scanOn );
}
else {
pNewPV = NULL;
}
}
//
// load initial value (this is not done in
// the constructor because the base class's
// pure virtual function would be called)
//
// We always perform this step even if
// scanning is disable so that there will
// always be an initial value
//
if (pNewPV) {
this->pPV = pNewPV;
pNewPV->scan();
}
return pNewPV;
}
//
// exServer::show()
//
void exServer::show (unsigned level) const
{
//
// server tool specific show code goes here
//
this->stringResTbl.show(level);
//
// print information about ca server libarary
// internals
//
this->caServer::show(level);
}
//
// exAsyncExistIO::exAsyncExistIO()
//
exAsyncExistIO::exAsyncExistIO ( const pvInfo &pviIn, const casCtx &ctxIn,
exServer &casIn ) :
casAsyncPVExistIO ( ctxIn ), pvi ( pviIn ),
timer ( casIn.createTimer () ), cas ( casIn )
{
this->timer.start ( *this, 0.00001 );
}
//
// exAsyncExistIO::~exAsyncExistIO()
//
exAsyncExistIO::~exAsyncExistIO()
{
this->cas.removeIO ();
this->timer.destroy ();
}
//
// exAsyncExistIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncExistIO::expire ( const epicsTime & /*currentTime*/ )
{
//
// post IO completion
//
this->postIOCompletion ( pvExistReturn(pverExistsHere) );
return noRestart;
}
//
// exAsyncCreateIO::exAsyncCreateIO()
//
exAsyncCreateIO ::
exAsyncCreateIO ( pvInfo &pviIn, exServer &casIn,
const casCtx &ctxIn, bool scanOnIn, double asyncDelayIn ) :
casAsyncPVAttachIO ( ctxIn ), pvi ( pviIn ),
timer ( casIn.createTimer () ),
cas ( casIn ), asyncDelay ( asyncDelayIn ), scanOn ( scanOnIn )
{
this->timer.start ( *this, 0.00001 );
}
//
// exAsyncCreateIO::~exAsyncCreateIO()
//
exAsyncCreateIO::~exAsyncCreateIO()
{
this->cas.removeIO ();
this->timer.destroy ();
}
//
// exAsyncCreateIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncCreateIO::expire ( const epicsTime & /*currentTime*/ )
{
exPV * pPV = this->pvi.createPV ( this->cas, false,
this->scanOn, this->asyncDelay );
if ( pPV ) {
this->postIOCompletion ( pvAttachReturn ( *pPV ) );
}
else {
this->postIOCompletion ( pvAttachReturn ( S_casApp_noMemory ) );
}
return noRestart;
}
+590
View File
@@ -0,0 +1,590 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
//
//
// caServer
// |
// exServer
//
// casPV
// |
// exPV-----------
// | |
// exScalarPV exVectorPV
// |
// exAsyncPV
//
// casChannel
// |
// exChannel
//
//
// ANSI C
//
#include <string.h>
#include <stdio.h>
//
// EPICS
//
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "gddAppFuncTable.h"
#include "smartGDDPointer.h"
#include "epicsTimer.h"
#include "casdef.h"
#include "epicsAssert.h"
#include "resourceLib.h"
#include "tsMinMax.h"
#ifndef NELEMENTS
# define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif
//
// info about all pv in this server
//
enum excasIoType { excasIoSync, excasIoAsync };
class exPV;
class exServer;
//
// pvInfo
//
class pvInfo {
public:
pvInfo ( double scanPeriodIn, const char * pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn, aitEnum typeIn,
excasIoType ioTypeIn, unsigned countIn );
pvInfo ( const pvInfo & copyIn );
~pvInfo ();
double getScanPeriod () const;
const char * getName ()
const; double getHopr () const;
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
exPV *createPV ( exServer & exCAS, bool preCreateFlag,
bool scanOn, double asyncDelay );
void deletePV ();
private:
const double scanPeriod;
const char * pName;
const double hopr;
const double lopr;
aitEnum type;
const excasIoType ioType;
const unsigned elementCount;
exPV * pPV;
pvInfo & operator = ( const pvInfo & );
};
//
// pvEntry
//
// o entry in the string hash table for the pvInfo
// o Since there may be aliases then we may end up
// with several of this class all referencing
// the same pv info class (justification
// for this breaking out into a seperate class
// from pvInfo)
//
class pvEntry // X aCC 655
: public stringId, public tsSLNode < pvEntry > {
public:
pvEntry ( pvInfo &infoIn, exServer & casIn,
const char * pAliasName );
~pvEntry();
pvInfo & getInfo() const { return this->info; }
void destroy ();
private:
pvInfo & info;
exServer & cas;
pvEntry & operator = ( const pvEntry & );
pvEntry ( const pvEntry & );
};
//
// exPV
//
class exPV : public casPV, public epicsTimerNotify,
public tsSLNode < exPV > {
public:
exPV ( exServer & cas, pvInfo & setup,
bool preCreateFlag, bool scanOn );
virtual ~exPV();
void show ( unsigned level ) const;
//
// Called by the server libary each time that it wishes to
// subscribe for PV the server tool via postEvent() below.
//
caStatus interestRegister ();
//
// called by the server library each time that it wishes to
// remove its subscription for PV value change events
// from the server tool via caServerPostEvents()
//
void interestDelete ();
aitEnum bestExternalType () const;
//
// chCreate() is called each time that a PV is attached to
// by a client. The server tool must create a casChannel object
// (or a derived class) each time that this routine is called
//
// If the operation must complete asynchronously then return
// the status code S_casApp_asyncCompletion and then
// create the casChannel object at some time in the future
//
//casChannel *createChannel ();
//
// This gets called when the pv gets a new value
//
caStatus update ( const gdd & );
//
// Gets called when we add noise to the current value
//
virtual void scan () = 0;
//
// If no one is watching scan the PV with 10.0
// times the specified period
//
double getScanPeriod ();
caStatus read ( const casCtx &, gdd & protoIn );
caStatus readNoCtx ( smartGDDPointer pProtoIn );
caStatus write ( const casCtx &, const gdd & value );
void destroy ();
const pvInfo & getPVInfo ();
const char * getName() const;
static void initFT();
casChannel * createChannel ( const casCtx &ctx,
const char * const pUserName,
const char * const pHostName );
protected:
smartGDDPointer pValue;
exServer & cas;
epicsTimer & timer;
pvInfo & info;
bool interest;
bool preCreate;
bool scanOn;
static epicsTime currentTime;
virtual caStatus updateValue ( const gdd & ) = 0;
private:
//
// scan timer expire
//
expireStatus expire ( const epicsTime & currentTime );
//
// Std PV Attribute fetch support
//
gddAppFuncTableStatus getPrecision(gdd &value);
gddAppFuncTableStatus getHighLimit(gdd &value);
gddAppFuncTableStatus getLowLimit(gdd &value);
gddAppFuncTableStatus getUnits(gdd &value);
gddAppFuncTableStatus getValue(gdd &value);
gddAppFuncTableStatus getEnums(gdd &value);
exPV & operator = ( const exPV & );
exPV ( const exPV & );
//
// static
//
static gddAppFuncTable<exPV> ft;
static char hasBeenInitialized;
};
//
// exScalarPV
//
class exScalarPV : public exPV {
public:
exScalarPV ( exServer & cas, pvInfo &setup,
bool preCreateFlag, bool scanOnIn ) :
exPV ( cas, setup,
preCreateFlag, scanOnIn) {}
void scan();
private:
caStatus updateValue ( const gdd & );
exScalarPV & operator = ( const exScalarPV & );
exScalarPV ( const exScalarPV & );
};
//
// exVectorPV
//
class exVectorPV : public exPV {
public:
exVectorPV ( exServer & cas, pvInfo &setup,
bool preCreateFlag, bool scanOnIn ) :
exPV ( cas, setup,
preCreateFlag, scanOnIn) {}
void scan();
unsigned maxDimension() const;
aitIndex maxBound (unsigned dimension) const;
private:
caStatus updateValue ( const gdd & );
exVectorPV & operator = ( const exVectorPV & );
exVectorPV ( const exVectorPV & );
};
//
// exServer
//
class exServer : private caServer {
public:
exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOn,
bool asyncScan, double asyncDelay,
unsigned maxSimultAsyncIO );
~exServer ();
void show ( unsigned level ) const;
void removeIO ();
void removeAliasName ( pvEntry & entry );
class epicsTimer & createTimer ();
void setDebugLevel ( unsigned level );
void destroyAllPV ();
unsigned maxSimultAsyncIO () const;
private:
resTable < pvEntry, stringId > stringResTbl;
epicsTimerQueueActive * pTimerQueue;
unsigned simultAsychIOCount;
const unsigned _maxSimultAsyncIO;
double asyncDelay;
bool scanOn;
void installAliasName ( pvInfo & info, const char * pAliasName );
pvExistReturn pvExistTest ( const casCtx &,
const caNetAddr &, const char * pPVName );
pvExistReturn pvExistTest ( const casCtx &,
const char * pPVName );
pvAttachReturn pvAttach ( const casCtx &,
const char * pPVName );
exServer & operator = ( const exServer & );
exServer ( const exServer & );
//
// list of pre-created PVs
//
static pvInfo pvList[];
static const unsigned pvListNElem;
//
// on-the-fly PVs
//
static pvInfo bill;
static pvInfo billy;
static pvInfo bloater;
static pvInfo bloaty;
static pvInfo boot;
static pvInfo booty;
};
//
// exAsyncPV
//
class exAsyncPV : public exScalarPV {
public:
exAsyncPV ( exServer & cas, pvInfo &setup,
bool preCreateFlag, bool scanOnIn, double asyncDelay );
caStatus read ( const casCtx & ctxIn, gdd & protoIn );
caStatus write ( const casCtx & ctxIn, const gdd & value );
caStatus writeNotify ( const casCtx & ctxIn, const gdd & value );
void removeReadIO();
void removeWriteIO();
caStatus updateFromAsyncWrite ( const gdd & );
private:
double asyncDelay;
smartConstGDDPointer pStandbyValue;
unsigned simultAsychReadIOCount;
unsigned simultAsychWriteIOCount;
exAsyncPV & operator = ( const exAsyncPV & );
exAsyncPV ( const exAsyncPV & );
};
//
// exChannel
//
class exChannel : public casChannel{
public:
exChannel ( const casCtx & ctxIn );
void setOwner ( const char * const pUserName,
const char * const pHostName );
bool readAccess () const;
bool writeAccess () const;
private:
exChannel & operator = ( const exChannel & );
exChannel ( const exChannel & );
};
//
// exAsyncWriteIO
//
class exAsyncWriteIO : public casAsyncWriteIO, public epicsTimerNotify {
public:
exAsyncWriteIO ( exServer &, const casCtx & ctxIn,
exAsyncPV &, const gdd &, double asyncDelay );
~exAsyncWriteIO ();
private:
exAsyncPV & pv;
epicsTimer & timer;
smartConstGDDPointer pValue;
expireStatus expire ( const epicsTime & currentTime );
exAsyncWriteIO & operator = ( const exAsyncWriteIO & );
exAsyncWriteIO ( const exAsyncWriteIO & );
};
//
// exAsyncReadIO
//
class exAsyncReadIO : public casAsyncReadIO, public epicsTimerNotify {
public:
exAsyncReadIO ( exServer &, const casCtx &,
exAsyncPV &, gdd &, double asyncDelay );
virtual ~exAsyncReadIO ();
private:
exAsyncPV & pv;
epicsTimer & timer;
smartGDDPointer pProto;
expireStatus expire ( const epicsTime & currentTime );
exAsyncReadIO & operator = ( const exAsyncReadIO & );
exAsyncReadIO ( const exAsyncReadIO & );
};
//
// exAsyncExistIO
// (PV exist async IO)
//
class exAsyncExistIO : public casAsyncPVExistIO, public epicsTimerNotify {
public:
exAsyncExistIO ( const pvInfo & pviIn, const casCtx & ctxIn,
exServer & casIn );
virtual ~exAsyncExistIO ();
private:
const pvInfo & pvi;
epicsTimer & timer;
exServer & cas;
expireStatus expire ( const epicsTime & currentTime );
exAsyncExistIO & operator = ( const exAsyncExistIO & );
exAsyncExistIO ( const exAsyncExistIO & );
};
//
// exAsyncCreateIO
// (PV create async IO)
//
class exAsyncCreateIO : public casAsyncPVAttachIO, public epicsTimerNotify {
public:
exAsyncCreateIO ( pvInfo & pviIn, exServer & casIn,
const casCtx & ctxIn, bool scanOnIn, double asyncDelay );
virtual ~exAsyncCreateIO ();
private:
pvInfo & pvi;
epicsTimer & timer;
exServer & cas;
double asyncDelay;
bool scanOn;
expireStatus expire ( const epicsTime & currentTime );
exAsyncCreateIO & operator = ( const exAsyncCreateIO & );
exAsyncCreateIO ( const exAsyncCreateIO & );
};
inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn,
aitEnum typeIn, excasIoType ioTypeIn,
unsigned countIn ) :
scanPeriod ( scanPeriodIn ), pName ( pNameIn ),
hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ),
ioType ( ioTypeIn ), elementCount ( countIn ),
pPV ( 0 )
{
}
//
// for use when MSVC++ will not build a default copy constructor
// for this class
//
inline pvInfo::pvInfo ( const pvInfo & copyIn ) :
scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ),
hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ),
ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ),
pPV ( copyIn.pPV )
{
}
inline pvInfo::~pvInfo ()
{
//
// GDD cleanup gets rid of GDD's that are in use
// by the PV before the file scope destructer for
// this class runs here so this does not seem to
// be a good idea
//
//if ( this->pPV != NULL ) {
// delete this->pPV;
//}
}
inline void pvInfo::deletePV ()
{
if ( this->pPV != NULL ) {
delete this->pPV;
}
}
inline double pvInfo::getScanPeriod () const
{
return this->scanPeriod;
}
inline const char *pvInfo::getName () const
{
return this->pName;
}
inline double pvInfo::getHopr () const
{
return this->hopr;
}
inline double pvInfo::getLopr () const
{
return this->lopr;
}
inline aitEnum pvInfo::getType () const
{
return this->type;
}
inline excasIoType pvInfo::getIOType () const
{
return this->ioType;
}
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
}
inline void pvInfo::unlinkPV ()
{
this->pPV = NULL;
}
inline pvEntry::pvEntry ( pvInfo & infoIn, exServer & casIn,
const char * pAliasName ) :
stringId ( pAliasName ), info ( infoIn ), cas ( casIn )
{
assert ( this->stringId::resourceName() != NULL );
}
inline pvEntry::~pvEntry ()
{
this->cas.removeAliasName ( *this );
}
inline void pvEntry::destroy ()
{
delete this;
}
inline void exServer::removeAliasName ( pvEntry & entry )
{
pvEntry * pE;
pE = this->stringResTbl.remove ( entry );
assert ( pE == &entry );
}
inline double exPV::getScanPeriod ()
{
double curPeriod = this->info.getScanPeriod ();
if ( ! this->interest ) {
curPeriod *= 10.0L;
}
return curPeriod;
}
inline caStatus exPV::readNoCtx ( smartGDDPointer pProtoIn )
{
return this->ft.read ( *this, *pProtoIn );
}
inline const pvInfo & exPV::getPVInfo ()
{
return this->info;
}
inline const char * exPV::getName () const
{
return this->info.getName();
}
inline void exServer::removeIO()
{
if ( this->simultAsychIOCount > 0u ) {
this->simultAsychIOCount--;
}
else {
fprintf ( stderr,
"simultAsychIOCount underflow?\n" );
}
}
inline unsigned exServer :: maxSimultAsyncIO () const
{
return this->_maxSimultAsyncIO;
}
inline exChannel::exChannel ( const casCtx & ctxIn ) :
casChannel(ctxIn)
{
}
@@ -0,0 +1,266 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "exServer.h"
#include "gddApps.h"
#define myPI 3.14159265358979323846
//
// SUN C++ does not have RAND_MAX yet
//
#if ! defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
# if 0
# define RAND_MAX INT_MAX
# else
# define RAND_MAX SHRT_MAX
# endif
#endif
//
// special gddDestructor guarantees same form of new and delete
//
class exVecDestructor: public gddDestructor {
virtual void run (void *);
};
//
// exVectorPV::maxDimension()
//
unsigned exVectorPV::maxDimension() const
{
return 1u;
}
//
// exVectorPV::maxBound()
//
aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361
{
if (dimension==0u) {
return this->info.getElementCount();
}
else {
return 0u;
}
}
//
// exVectorPV::scan
//
void exVectorPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
aitFloat32 *pF, *pFE;
const aitFloat32 *pCF;
float newValue;
float limit;
exVecDestructor *pDest;
int gddStatus;
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
// throughput under sunos4 because gettimeofday() is
// slow)
//
this->currentTime = epicsTime::getCurrent();
pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount());
if ( ! pDD.valid () ) {
return;
}
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference();
assert (!gddStatus);
//
// allocate array buffer
//
pF = new aitFloat32 [this->info.getElementCount()];
if (!pF) {
return;
}
pDest = new exVecDestructor;
if (!pDest) {
delete [] pF;
return;
}
//
// install the buffer into the DD
// (do this before we increment pF)
//
pDD->putRef(pF, pDest);
//
// double check for reasonable bounds on the
// current value
//
pCF=NULL;
if ( this->pValue.valid () ) {
if (this->pValue->dimension()==1u) {
const gddBounds *pB = this->pValue->getBounds();
if (pB[0u].size()==this->info.getElementCount()) {
pCF = *this->pValue;
}
}
}
pFE = &pF[this->info.getElementCount()];
while (pF<pFE) {
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (pCF) {
newValue = *pCF++;
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue = tsMin (newValue, limit);
limit = (float) this->info.getLopr();
newValue = tsMax (newValue, limit);
*(pF++) = newValue;
}
aitTimeStamp gddts = this->currentTime;
pDD->setTimeStamp ( & gddts );
status = this->update ( *pDD );
if ( status != S_casApp_success ) {
errMessage (status, "vector scan update failed\n");
}
}
//
// exVectorPV::updateValue ()
//
// NOTES:
// 1) This should have a test which verifies that the
// incoming value in all of its various data types can
// be translated into a real number?
// 2) We prefer to unreference the old PV value here and
// reference the incomming value because this will
// result in value change events each retaining an
// independent value on the event queue. With large arrays
// this may result in too much memory consumtion on
// the event queue.
//
caStatus exVectorPV::updateValue ( const gdd & value )
{
//
// Check bounds of incoming request
// (and see if we are replacing all elements -
// replaceOk==true)
//
// Perhaps much of this is unnecessary since the
// server lib checks the bounds of all requests
//
if ( value.isAtomic()) {
if ( value.dimension() != 1u ) {
return S_casApp_badDimension;
}
const gddBounds* pb = value.getBounds ();
if ( pb[0u].first() != 0u ) {
return S_casApp_outOfBounds;
}
else if ( pb[0u].size() > this->info.getElementCount() ) {
return S_casApp_outOfBounds;
}
}
else if ( ! value.isScalar() ) {
//
// no containers
//
return S_casApp_outOfBounds;
}
//
// Create a new array data descriptor
// (so that old values that may be referenced on the
// event queue are not replaced)
//
smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount() ) );
if ( ! pNewValue.valid() ) {
return S_casApp_noMemory;
}
//
// smart pointer class takes care of the reference count
// from here down
//
gddStatus gdds = pNewValue->unreference( );
assert ( ! gdds );
//
// allocate array buffer
//
aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()];
if (!pF) {
return S_casApp_noMemory;
}
//
// Install (and initialize) array buffer
// if no old values exist
//
unsigned count = this->info.getElementCount();
for ( unsigned i = 0u; i < count; i++ ) {
pF[i] = 0.0f;
}
exVecDestructor * pDest = new exVecDestructor;
if (!pDest) {
delete [] pF;
return S_casApp_noMemory;
}
//
// install the buffer into the DD
// (do this before we increment pF)
//
pNewValue->putRef ( pF, pDest );
//
// copy in the values that they are writing
//
gdds = pNewValue->put( & value );
if ( gdds ) {
return S_cas_noConvert;
}
this->pValue = pNewValue;
return S_casApp_success;
}
//
// exVecDestructor::run()
//
// special gddDestructor guarantees same form of new and delete
//
void exVecDestructor::run ( void *pUntyped )
{
aitFloat32 * pf = reinterpret_cast < aitFloat32 * > ( pUntyped );
delete [] pf;
}
+151
View File
@@ -0,0 +1,151 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "envDefs.h"
#include "errlog.h"
#include "exServer.h"
#include "fdManager.h"
//
// main()
// (example single threaded ca server tool main loop)
//
extern int main ( int argc, const char **argv )
{
epicsTime begin (epicsTime::getCurrent());
exServer *pCAS;
unsigned debugLevel = 0u;
double executionTime = 0.0;
double asyncDelay = 0.1;
char pvPrefix[128] = "";
unsigned aliasCount = 1u;
unsigned scanOn = true;
unsigned syncScan = true;
char arraySize[64] = "";
bool forever = true;
unsigned maxSimultAsyncIO = 1000u;
int i;
i = 1;
while ( i < argc ) {
if ( strcmp ( argv[i], "-d" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & debugLevel ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i],"-t" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%lf", & executionTime ) == 1 ) {
forever = false;
i += 2;
continue;
}
}
if ( strcmp ( argv[i], "-p" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%127s", pvPrefix ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i], "-c" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & aliasCount ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i], "-s" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & scanOn ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i], "-a" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%63s", arraySize ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i],"-ss" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & syncScan ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i],"-ad" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%lf", & asyncDelay ) == 1 ) {
i += 2;
continue;
}
}
if ( strcmp ( argv[i],"-an" ) == 0 ) {
if ( i+1 < argc && sscanf ( argv[i+1], "%u", & maxSimultAsyncIO ) == 1 ) {
i += 2;
continue;
}
}
printf ( "\"%s\"?\n", argv[i] );
if ( i + 1 < argc ) {
printf ( "\"%s\"?\n", argv[i+1] );
}
printf (
"usage: %s [-d <debug level> -t <execution time> -p <PV name prefix> "
"-c <numbered alias count> -s <1=scan on (default), 0=scan off> "
"-ss <1=synchronous scan (default), 0=asynchronous scan> "
"-a <max array size> -ad <async delay> "
"-an <max simultaneous async>\n",
argv[0]);
return (1);
}
if ( arraySize[0] != '\0' ) {
epicsEnvSet ( "EPICS_CA_MAX_ARRAY_BYTES", arraySize );
}
try {
pCAS = new exServer ( pvPrefix, aliasCount,
scanOn != 0, syncScan == 0, asyncDelay,
maxSimultAsyncIO );
}
catch ( ... ) {
errlogPrintf ( "Server initialization error\n" );
errlogFlush ();
return (-1);
}
pCAS->setDebugLevel(debugLevel);
if ( forever ) {
//
// loop here forever
//
while (true) {
fileDescriptorManager.process(1000.0);
}
}
else {
double delay = epicsTime::getCurrent() - begin;
//
// loop here untill the specified execution time
// expires
//
while ( delay < executionTime ) {
fileDescriptorManager.process ( executionTime - delay );
delay = epicsTime::getCurrent() - begin;
}
}
//pCAS->show(2u);
delete pCAS;
errlogFlush ();
return (0);
}
+844
View File
@@ -0,0 +1,844 @@
file {
name="test.dl"
}
display {
magic="305419896"
majv="2"
mnrv="4"
ndyng="0"
npc="5"
nstr="8"
ndynamic="12"
nplot="0"
nrd="0"
nes="0"
nkd="0"
object {
x="0"
y="0"
width="421"
height="306"
}
clr="0"
bclr="1"
nwords_dspy="1106"
nwords_sta="28"
nwords_cmap="36"
nwords_crules="106"
odyng="306"
osta="278"
odynamic="306"
oplot="1106"
ord="1106"
oes="1106"
okd="1106"
opc="58"
ostr="88"
ocmap="136"
ocrules="172"
style="solid"
fill="outline"
width="0"
clrmod="static"
vismod="static"
clrrule="alarm"
pv=""
cmap=""
}
"<<color map>>" {
ncolors="8"
dl_color {
r="255"
g="255"
b="255"
inten="255"
blink="off"
RISCpad="128"
}
dl_color {
r="0"
g="0"
b="0"
inten="0"
blink="off"
RISCpad="75"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="off"
RISCpad="-14684"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="on"
RISCpad="14744"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="off"
RISCpad="-16536"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="on"
RISCpad="-15536"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="off"
RISCpad="-28408"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="on"
RISCpad="0"
}
}
"<<color rules>>" {
nrules="1"
dl_color_rule {
name="alarm"
info[0] {
chan="$(C).SEVR"
value="MAJOR"
connector="use"
comparator="equals"
clr="2"
RISCpad="0"
}
info[1] {
chan="$(C).SEVR"
value="MINOR"
connector="use"
comparator="equals"
clr="4"
RISCpad="127"
}
info[2] {
chan="$(C).SEVR"
value="INFO"
connector="use"
comparator="equals"
clr="6"
RISCpad="44"
}
info[3] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-128"
}
info[4] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[5] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-104"
}
info[6] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[7] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="8"
}
info[8] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="120"
}
info[9] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="1"
}
info[10] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="7"
}
info[11] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="19"
}
info[12] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="48"
}
info[13] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="28"
}
info[14] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-88"
}
info[15] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="0"
}
fg_enable="on"
bg_enable="on"
default_fg="0"
default_bg="1"
}
}
"<<basic attribute>>" {
attr {
clr="0"
style="solid"
fill="outline"
width="0"
}
}
"text" {
object {
x="44"
y="16"
width="104"
height="14"
groupid="0"
}
textix="Sync"
align="horiz. left"
RISC_pad="0"
}
"text" {
object {
x="260"
y="13"
width="92"
height="17"
groupid="0"
}
textix="Async"
align="horiz. left"
RISC_pad="0"
}
"indicator" {
object {
x="15"
y="88"
width="170"
height="22"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="16"
y="133"
width="169"
height="17"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="43"
width="168"
height="26"
groupid="0"
}
control {
chan="fred"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="215"
y="81"
width="170"
height="30"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="216"
y="133"
width="171"
height="18"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="215"
y="43"
width="168"
height="28"
groupid="0"
}
control {
chan="freddy"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="16"
y="225"
width="171"
height="19"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="17"
y="259"
width="170"
height="20"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="187"
width="170"
height="19"
groupid="0"
}
control {
chan="jane"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="219"
y="218"
width="173"
height="23"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="220"
y="257"
width="174"
height="20"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="219"
y="188"
width="171"
height="21"
groupid="0"
}
control {
chan="janet"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
@@ -0,0 +1,80 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd
// Author: Jeff HIll (LANL)
//
//
#include <vxWorks.h>
#include <taskLib.h>
#include "exServer.h"
//
// so we can call this from the vxWorks shell
//
extern "C" {
exServer *pExampleCAS;
//
// excas ()
// (vxWorks example server entry point)
//
int excas (unsigned debugLevel, unsigned delaySec)
{
epicsTime begin(epicsTime::getCurrent());
exServer *pCAS;
pCAS = new exServer(32u,5u,500u);
if (!pCAS) {
return (-1);
}
pCAS->setDebugLevel(debugLevel);
pExampleCAS = pCAS;
if (delaySec==0u) {
//
// loop here forever
//
while (1) {
taskDelay(10);
}
}
else {
epicsTime total( ((float)delaySec) );
epicsTime delay(epicsTime::getCurrent() - begin);
//
// loop here untill the specified execution time
// expires
//
while (delay < total) {
taskDelay(10);
delay = epicsTime::getCurrent() - begin;
}
}
pCAS->show(debugLevel);
pExampleCAS = NULL;
delete pCAS;
return 0;
}
int excasShow(unsigned level)
{
if (pExampleCAS!=NULL) {
pExampleCAS->show(level);
}
return 0;
}
} // extern "C"
+29
View File
@@ -0,0 +1,29 @@
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif
+33
View File
@@ -0,0 +1,33 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building anyway if conflicts are found.
CHECK_RELEASE = YES
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</path/name/to/install/top>
# Set this when your IOC and the host use different paths
# to access the application. This will be needed to boot
# from a Microsoft FTP server or with some NFS mounts.
# You must rebuild in the iocBoot directory for this to
# take effect.
#IOCS_APPL_TOP = </IOC/path/to/application/top>
+8
View File
@@ -0,0 +1,8 @@
TOP=..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
include $(TOP)/configure/RULES
+32
View File
@@ -0,0 +1,32 @@
# RELEASE - Location of external support modules
#
# IF YOU MAKE ANY CHANGES to this file you must subsequently
# do a "gnumake rebuild" in this application's top level
# directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
#
# This file should ONLY define paths to other support modules,
# or include statements that pull in similar RELEASE files.
# Build settings that are NOT module paths should appear in a
# CONFIG_SITE file.
TEMPLATE_TOP=_TEMPLATE_TOP_
# If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
# EPICS_BASE usually appears last so other apps can override stuff:
EPICS_BASE=_EPICS_BASE_
# Set RULES here if you want to take build rules from somewhere
# other than EPICS_BASE:
#RULES=/path/to/epics/support/module/rules/x-y
+6
View File
@@ -0,0 +1,6 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile
+2
View File
@@ -0,0 +1,2 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc
+2
View File
@@ -0,0 +1,2 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS
+3
View File
@@ -0,0 +1,3 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP
@@ -0,0 +1,26 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#----------------------------------------------------
# Optimization of db files using dbst (DEFAULT: NO)
#DB_OPT = YES
#----------------------------------------------------
# Create and install (or just install)
# databases, templates, substitutions like this
DB += dbExample1.db
DB += dbExample2.db
DB += dbSubExample.db
DB += user.substitutions
DB += userHost.substitutions
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_TEMPLATE = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1,62 @@
record(ai, "$(user):aiExample")
{
field(DESC, "Analog input")
field(INP, "$(user):calcExample.VAL NPP NMS")
field(EGUF, "10")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(calc, "$(user):calcExample")
{
field(DESC, "Counter")
field(SCAN,"1 second")
field(FLNK, "$(user):aiExample")
field(CALC, "(A<B)?(A+C):D")
field(INPA, "$(user):calcExample.VAL NPP NMS")
field(INPB, "9")
field(INPC, "1")
field(INPD, "0")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(xxx, "$(user):xxxExample")
{
field(DESC, "xxx record")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(compress,"$(user):compressExample")
{
field(DESC, "Circular buffer")
field(INP,"$(user):aiExample.VAL CP NMS")
field(ALG,"Circular Buffer")
field(NSAM,"10")
field(HOPR,"10")
field(EGU,"Counts")
}
@@ -0,0 +1,40 @@
record(calc, "$(user):calcExample$(no)")
{
alias("$(user):calc$(no)")
field(DESC, "Counter No. $(no)")
field(SCAN,"$(scan)")
field(FLNK, "$(user):aiExample$(no)")
field(CALC, "(A<B)?(A+C):D")
field(INPA, "$(user):calcExample$(no).VAL NPP NMS")
field(INPB, "9")
field(INPC, "1")
field(INPD, "0")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(ai, "$(user):aiExample$(no)")
{
field(DESC, "Analog input No. $(no)")
field(INP, "$(user):calcExample$(no).VAL NPP NMS")
field(EGUF, "10")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
alias("$(user):aiExample$(no)","$(user):ai$(no)")
@@ -0,0 +1,13 @@
record(sub,"$(user):subExample")
{
field(INAM,"mySubInit")
field(SNAM,"mySubProcess")
}
record(aSub,"$(user):aSubExample")
{
field(INAM,"myAsubInit")
field(SNAM,"myAsubProcess")
field(FTA,"DOUBLE")
field(NOA,"10")
field(INPA,"$(user):compressExample CPP")
}
@@ -0,0 +1,12 @@
# Example substitutions file
file "db/dbExample1.db" {
{ user = "_USER_" }
}
file db/dbExample2.db {
pattern { user, no, scan }
{ "_USER_", 1, "1 second" }
{ "_USER_", 2, "2 second" }
{ "_USER_", 3, "5 second" }
}
@@ -0,0 +1,12 @@
# Example substitutions file
file "db/dbExample1.db" {
{ user = "_USER_Host" }
}
file db/dbExample2.db {
pattern { user, no, scan }
{ "_USER_Host", 1, "1 second" }
{ "_USER_Host", 2, "2 second" }
{ "_USER_Host", 3, "5 second" }
}
+8
View File
@@ -0,0 +1,8 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
include $(TOP)/configure/RULES_DIRS
@@ -0,0 +1,83 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
# Build the IOC support library
LIBRARY_IOC += _APPNAME_Support
# xxxRecord.h will be created from xxxRecord.dbd
DBDINC += xxxRecord
# Install devXxxSoft.dbd into <top>/dbd
DBD += xxxSupport.dbd
# Compile and add the code to the support library
_APPNAME_Support_SRCS += xxxRecord.c
_APPNAME_Support_SRCS += devXxxSoft.c
# Link locally-provided code into the support library,
# rather than directly into the IOC application.
_APPNAME_Support_SRCS += dbSubExample.c
_APPNAME_Support_SRCS += _APPNAME_Hello.c
_APPNAME_Support_SRCS += initTrace.c
_APPNAME_Support_LIBS += $(EPICS_BASE_IOC_LIBS)
#=============================
# Build the IOC application
PROD_IOC = _APPNAME_
# _APPNAME_.dbd will be created and installed
DBD += _APPNAME_.dbd
# _APPNAME_.dbd will be made up from these files:
_APPNAME__DBD += base.dbd
_APPNAME__DBD += xxxSupport.dbd
_APPNAME__DBD += dbSubExample.dbd
_APPNAME__DBD += _APPNAME_Hello.dbd
_APPNAME__DBD += initTrace.dbd
# _APPNAME__registerRecordDeviceDriver.cpp derives from _APPNAME_.dbd
_APPNAME__SRCS += _APPNAME__registerRecordDeviceDriver.cpp
# Build the main IOC entry point on workstation OSs.
_APPNAME__SRCS_DEFAULT += _APPNAME_Main.cpp
_APPNAME__SRCS_vxWorks += -nil-
# Add support from base/src/vxWorks if needed
#_APPNAME__OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
# Link in the code from the support library
_APPNAME__LIBS += _APPNAME_Support
# NOTE: To build SNL programs, SNCSEQ must be defined
# in the <top>/configure/RELEASE file
ifneq ($(SNCSEQ),)
# Build sncExample into _APPNAME_Support
sncExample_SNCFLAGS += +r
_APPNAME__DBD += sncExample.dbd
_APPNAME_Support_SRCS += sncExample.stt
_APPNAME_Support_LIBS += seq pv
_APPNAME__LIBS += seq pv
# Build sncProgram as a standalone program
PROD_HOST += sncProgram
sncProgram_SNCFLAGS += +m
sncProgram_SRCS += sncProgram.st
sncProgram_LIBS += seq pv
sncProgram_LIBS += $(EPICS_BASE_HOST_LIBS)
endif
# Finally link to the EPICS Base libraries
_APPNAME__LIBS += $(EPICS_BASE_IOC_LIBS)
#=============================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1,31 @@
/* Example showing how to register a new command with iocsh */
#include <stdio.h>
#include <epicsExport.h>
#include <iocsh.h>
/* This is the command, which the vxWorks shell will call directly */
void hello(const char *name) {
if (name) {
printf("Hello %s, from _APPNAME_\n", name);
} else {
puts("Hello from _APPNAME_");
}
}
/* Information needed by iocsh */
static const iocshArg helloArg0 = {"name", iocshArgString};
static const iocshArg *helloArgs[] = {&helloArg0};
static const iocshFuncDef helloFuncDef = {"hello", 1, helloArgs};
/* Wrapper called by iocsh, selects the argument types that hello needs */
static void helloCallFunc(const iocshArgBuf *args) {
hello(args[0].sval);
}
/* Registration routine, runs at startup */
static void helloRegister(void) {
iocshRegister(&helloFuncDef, helloCallFunc);
}
epicsExportRegistrar(helloRegister);
@@ -0,0 +1 @@
registrar(helloRegister)
@@ -0,0 +1,23 @@
/* _APPNAME_Main.cpp */
/* Author: Marty Kraimer Date: 17MAR2000 */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "epicsExit.h"
#include "epicsThread.h"
#include "iocsh.h"
int main(int argc,char *argv[])
{
if(argc>=2) {
iocsh(argv[1]);
epicsThreadSleep(.2);
}
iocsh(NULL);
epicsExit(0);
return(0);
}
@@ -0,0 +1,49 @@
#include <stdio.h>
#include <dbDefs.h>
#include <registryFunction.h>
#include <subRecord.h>
#include <aSubRecord.h>
#include <epicsExport.h>
int mySubDebug;
static long mySubInit(subRecord *precord)
{
if (mySubDebug)
printf("Record %s called mySubInit(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long mySubProcess(subRecord *precord)
{
if (mySubDebug)
printf("Record %s called mySubProcess(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long myAsubInit(aSubRecord *precord)
{
if (mySubDebug)
printf("Record %s called myAsubInit(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long myAsubProcess(aSubRecord *precord)
{
if (mySubDebug)
printf("Record %s called myAsubProcess(%p)\n",
precord->name, (void*) precord);
return 0;
}
/* Register these symbols for use by IOC code: */
epicsExportAddress(int, mySubDebug);
epicsRegisterFunction(mySubInit);
epicsRegisterFunction(mySubProcess);
epicsRegisterFunction(myAsubInit);
epicsRegisterFunction(myAsubProcess);
@@ -0,0 +1,5 @@
variable(mySubDebug)
function(mySubInit)
function(mySubProcess)
function(myAsubInit)
function(myAsubProcess)
@@ -0,0 +1,58 @@
/* devXxxSoft.c */
/* Example device support module */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "cvtTable.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "xxxRecord.h"
#include "epicsExport.h"
/*Create the dset for devXxxSoft */
static long init_record();
static long read_xxx();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_xxx;
}devXxxSoft={
5,
NULL,
NULL,
init_record,
NULL,
read_xxx,
};
epicsExportAddress(dset,devXxxSoft);
static long init_record(pxxx)
struct xxxRecord *pxxx;
{
if(recGblInitConstantLink(&pxxx->inp,DBF_DOUBLE,&pxxx->val))
pxxx->udf = FALSE;
return(0);
}
static long read_xxx(pxxx)
struct xxxRecord *pxxx;
{
long status;
status = dbGetLink(&(pxxx->inp),DBF_DOUBLE, &(pxxx->val),0,0);
/*If return was succesful then set undefined false*/
if(!status) pxxx->udf = FALSE;
return(0);
}
@@ -0,0 +1,39 @@
/* initTrace.c */
/*
* An initHook routine to trace the iocInit() process.
* Prints out the name of each state as it is reached.
*/
#include <stdio.h>
#include "initHooks.h"
#include "epicsExport.h"
#include "iocsh.h"
static void trace(initHookState state) {
printf("iocInit: Reached %s\n", initHookName(state));
}
int traceIocInit(void) {
static int done = 0;
if (done)
return -1;
done = 1;
initHookRegister(trace);
puts("iocInit will be traced");
return 0;
}
static const iocshFuncDef traceInitFuncDef = {"traceIocInit", 0, NULL};
static void traceInitFunc(const iocshArgBuf *args) {
traceIocInit();
}
static void initTraceRegister(void) {
iocshRegister(&traceInitFuncDef, traceInitFunc);
}
epicsExportRegistrar(initTraceRegister);
@@ -0,0 +1 @@
registrar(initTraceRegister)
@@ -0,0 +1 @@
registrar(sncExampleRegistrar)
@@ -0,0 +1,22 @@
program sncExample
double v;
assign v to "{user}:aiExample";
monitor v;
ss ss1 {
state init {
when (delay(10)) {
printf("sncExample: Startup delay over\n");
} state low
}
state low {
when (v > 5.0) {
printf("sncExample: Changing to high\n");
} state high
}
state high {
when (v <= 5.0) {
printf("sncExample: Changing to low\n");
} state low
}
}
@@ -0,0 +1 @@
#include "../sncExample.stt"
@@ -0,0 +1,273 @@
/* xxxRecord.c */
/* Example record support module */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "epicsMath.h"
#include "alarm.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "dbEvent.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "devSup.h"
#include "errMdef.h"
#include "recSup.h"
#include "special.h"
#define GEN_SIZE_OFFSET
#include "xxxRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Create RSET - Record Support Entry Table */
#define report NULL
#define initialize NULL
static long init_record();
static long process();
#define special NULL
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
static long get_units();
static long get_precision();
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double();
static long get_control_double();
static long get_alarm_double();
rset xxxRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,xxxRSET);
typedef struct xxxset { /* xxx input dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_xxx;
}xxxdset;
static void checkAlarms(xxxRecord *prec);
static void monitor(xxxRecord *prec);
static long init_record(void *precord,int pass)
{
xxxRecord *prec = (xxxRecord *)precord;
xxxdset *pdset;
long status;
if (pass==0) return(0);
if(!(pdset = (xxxdset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"xxx: init_record");
return(S_dev_noDSET);
}
/* must have read_xxx function defined */
if( (pdset->number < 5) || (pdset->read_xxx == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"xxx: init_record");
return(S_dev_missingSup);
}
if( pdset->init_record ) {
if((status=(*pdset->init_record)(prec))) return(status);
}
return(0);
}
static long process(void *precord)
{
xxxRecord *prec = (xxxRecord *)precord;
xxxdset *pdset = (xxxdset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
if( (pdset==NULL) || (pdset->read_xxx==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_xxx");
return(S_dev_missingSup);
}
/* pact must not be set until after calling device support */
status=(*pdset->read_xxx)(prec);
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
recGblGetTimeStamp(prec);
/* check for alarms */
checkAlarms(prec);
/* check event list */
monitor(prec);
/* process the forward scan link record */
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
}
static long get_units(DBADDR *paddr, char *units)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
return(0);
}
static long get_precision(DBADDR *paddr, long *precision)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
*precision = prec->prec;
if(paddr->pfield == (void *)&prec->val) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL
|| fieldIndex == xxxRecordHIHI
|| fieldIndex == xxxRecordHIGH
|| fieldIndex == xxxRecordLOW
|| fieldIndex == xxxRecordLOLO
|| fieldIndex == xxxRecordHOPR
|| fieldIndex == xxxRecordLOPR) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL
|| fieldIndex == xxxRecordHIHI
|| fieldIndex == xxxRecordHIGH
|| fieldIndex == xxxRecordLOW
|| fieldIndex == xxxRecordLOLO) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else recGblGetAlarmDouble(paddr,pad);
return(0);
}
static void checkAlarms(xxxRecord *prec)
{
double val;
float hyst, lalm, hihi, high, low, lolo;
unsigned short hhsv, llsv, hsv, lsv;
if(prec->udf == TRUE ){
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
return;
}
hihi = prec->hihi; lolo = prec->lolo; high = prec->high; low = prec->low;
hhsv = prec->hhsv; llsv = prec->llsv; hsv = prec->hsv; lsv = prec->lsv;
val = prec->val; hyst = prec->hyst; lalm = prec->lalm;
/* alarm condition hihi */
if (hhsv && (val >= hihi || ((lalm==hihi) && (val >= hihi-hyst)))){
if (recGblSetSevr(prec,HIHI_ALARM,prec->hhsv)) prec->lalm = hihi;
return;
}
/* alarm condition lolo */
if (llsv && (val <= lolo || ((lalm==lolo) && (val <= lolo+hyst)))){
if (recGblSetSevr(prec,LOLO_ALARM,prec->llsv)) prec->lalm = lolo;
return;
}
/* alarm condition high */
if (hsv && (val >= high || ((lalm==high) && (val >= high-hyst)))){
if (recGblSetSevr(prec,HIGH_ALARM,prec->hsv)) prec->lalm = high;
return;
}
/* alarm condition low */
if (lsv && (val <= low || ((lalm==low) && (val <= low+hyst)))){
if (recGblSetSevr(prec,LOW_ALARM,prec->lsv)) prec->lalm = low;
return;
}
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
}
static void monitor(xxxRecord *prec)
{
unsigned short monitor_mask;
double delta;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
delta = prec->mlst - prec->val;
if(delta<0.0) delta = -delta;
if (delta > prec->mdel) {
/* post events for value change */
monitor_mask |= DBE_VALUE;
/* update last value monitored */
prec->mlst = prec->val;
}
/* check for archive change */
delta = prec->alst - prec->val;
if(delta<0.0) delta = -delta;
if (delta > prec->adel) {
/* post events on value field for archive change */
monitor_mask |= DBE_LOG;
/* update last archive value monitored */
prec->alst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
return;
}
@@ -0,0 +1,117 @@
recordtype(xxx) {
include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Current EGU Value")
asl(ASL0)
pp(TRUE)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup(GUI_INPUTS)
special(SPC_NOMOD)
interest(1)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup(GUI_DISPLAY)
interest(1)
size(16)
}
field(HOPR,DBF_FLOAT) {
prompt("High Operating Range")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(LOPR,DBF_FLOAT) {
prompt("Low Operating Range")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(HIHI,DBF_FLOAT) {
prompt("Hihi Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(LOLO,DBF_FLOAT) {
prompt("Lolo Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(HIGH,DBF_FLOAT) {
prompt("High Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(LOW,DBF_FLOAT) {
prompt("Low Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(HHSV,DBF_MENU) {
prompt("Hihi Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(LLSV,DBF_MENU) {
prompt("Lolo Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(HSV,DBF_MENU) {
prompt("High Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(LSV,DBF_MENU) {
prompt("Low Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(HYST,DBF_DOUBLE) {
prompt("Alarm Deadband")
promptgroup(GUI_ALARMS)
interest(1)
}
field(ADEL,DBF_DOUBLE) {
prompt("Archive Deadband")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(MDEL,DBF_DOUBLE) {
prompt("Monitor Deadband")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(LALM,DBF_DOUBLE) {
prompt("Last Value Alarmed")
special(SPC_NOMOD)
interest(3)
}
field(ALST,DBF_DOUBLE) {
prompt("Last Value Archived")
special(SPC_NOMOD)
interest(3)
}
field(MLST,DBF_DOUBLE) {
prompt("Last Val Monitored")
special(SPC_NOMOD)
interest(3)
}
}
@@ -0,0 +1,2 @@
include "xxxRecord.dbd"
device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
+6
View File
@@ -0,0 +1,6 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS += $(wildcard *ioc*)
DIRS += $(wildcard as*)
include $(CONFIG)/RULES_DIRS
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = envPaths
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = cdCommands
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = envPaths dllPath.bat
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,9 @@
To start the ioc from this directory execute the command
../../bin/_ARCH_/<appname> st.cmd
Alternatively make the st.cmd file directly executable with
chmod +x st.cmd
and check the executable name on the first line of the st.cmd file
You may need to change the name of the .dbd file given in the
st.cmd's dbLoadDatabase() command before starting the ioc.
@@ -0,0 +1,6 @@
Copy the startup script (st.cmd) and top level db and dbd directories and
contents to
<<TFTP_ROOT>>/epics/<<IOC hostname>>/
Then load the executable into the IOC (floppy disk, network boot, debugger,
etc.) and start it.
@@ -0,0 +1,28 @@
#!../../bin/_ARCH_/_APPNAME_
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
< envPaths
cd ${TOP}
## Register all support components
dbLoadDatabase "dbd/_APPNAME_.dbd"
_CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
dbLoadTemplate "db/userHost.substitutions"
dbLoadRecords "db/dbSubExample.db", "user=_USER_Host"
## Set this to see messages from mySub
#var mySubDebug 1
## Run this to trace the stages of iocInit
#traceIocInit
cd ${TOP}/iocBoot/${IOC}
iocInit
## Start any sequence programs
#seq sncExample, "user=_USER_Host"
@@ -0,0 +1,25 @@
## Example RTEMS startup script
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
#< envPaths
## Register all support components
dbLoadDatabase("dbd/_APPNAME_.dbd")
_CSAFEAPPNAME__registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadTemplate("db/user.substitutions")
dbLoadRecords("db/dbSubExample.db", "user=_USER_")
## Set this to see messages from mySub
#var mySubDebug 1
## Run this to trace the stages of iocInit
#traceIocInit
iocInit
## Start any sequence programs
#seq(sncExample, "user=_USER_")
@@ -0,0 +1,35 @@
## Example vxWorks startup file
## The following is needed if your board support package doesn't at boot time
## automatically cd to the directory containing its startup script
#cd "_TOP_/iocBoot/_IOC_"
< cdCommands
#< ../nfsCommands
cd topbin
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
ld 0,0, "_APPNAME_.munch"
## Register all support components
cd top
dbLoadDatabase "dbd/_APPNAME_.dbd"
_CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
dbLoadTemplate "db/user.substitutions"
dbLoadRecords "db/dbSubExample.db", "user=_USER_"
## Set this to see messages from mySub
#mySubDebug = 1
## Run this to trace the stages of iocInit
#traceIocInit
cd startup
iocInit
## Start any sequence programs
#seq &sncExample, "user=_USER_"
@@ -0,0 +1,26 @@
#Instructions for creating and using a real nfsCommands file
#
# in order to use nfs do the following:
# 1) Create hostAdd and nfsMount commands for each nfs server
# 2) In each st.cmd file add the following two commands BEFORE any load commands
# ../nfs.cmd
# cd "<iocname>
#
# The hostAdd command has the form:
# hostAdd("<host>","xxx.xxx.xxx.xxx")
#
# You can also mount subdirectories as follows:
# nfsMount("<host>", "/xxx/xxx/xxx", "/xxx")
#
# For example assume
#
# host is mercury with inet address 155.77.2.56
# You want to mount the directory (which is a file system of mercury)
# /home/mercury5/iocinfo
# as
# /iocinfo
#
# The commands would be
#
# hostAdd("mercury","155.77.2.56")
# nfsMount("mercury","/home/mercury5/iocinfo","/iocinfo")
@@ -0,0 +1,29 @@
#Instructions for creating and using a real nfsCommands file
#
# in order to use nfs do the following:
# 1) Create hostAdd and nfsMount commands for each nfs server
# 2) In each st.cmd file add the following two commands BEFORE any load commands
# ../nfs.cmd
# cd "<iocname>
#
# The hostAdd command has the form:
# hostAdd("<host>","xxx.xxx.xxx.xxx")
#
# The nfsMount command has the form:
# nfsMount("<host>", "/xxx/xxx/xxx", "/xxx")
#
# You can also mount subdirectories as follows:
# nfsMountAll("<host>")
#
# For example assume
#
# host is mercury with inet address 155.77.2.56
# You want to mount the directory (which is a file system of mercury)
# /home/mercury5/iocinfo
# as
# /iocinfo
#
# The commands would be
#
# hostAdd("mercury","155.77.2.56")
# nfsMount("mercury","/home/mercury5/iocinfo","/iocinfo")
+22
View File
@@ -0,0 +1,22 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#----------------------------------------------------
# Optimization of db files using dbst (DEFAULT: NO)
#DB_OPT = YES
#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
#DB += xxx.db
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_template = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
+8
View File
@@ -0,0 +1,8 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
include $(TOP)/configure/RULES_DIRS
+42
View File
@@ -0,0 +1,42 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the IOC application
PROD_IOC = _APPNAME_
# _APPNAME_.dbd will be created and installed
DBD += _APPNAME_.dbd
# _APPNAME_.dbd will be made up from these files:
_APPNAME__DBD += base.dbd
# Include dbd files from all support applications:
#_APPNAME__DBD += xxx.dbd
# Add all the support libraries needed by this IOC
#_APPNAME__LIBS += xxx
# _APPNAME__registerRecordDeviceDriver.cpp derives from _APPNAME_.dbd
_APPNAME__SRCS += _APPNAME__registerRecordDeviceDriver.cpp
# Build the main IOC entry point on workstation OSs.
_APPNAME__SRCS_DEFAULT += _APPNAME_Main.cpp
_APPNAME__SRCS_vxWorks += -nil-
# Add support from base/src/vxWorks if needed
#_APPNAME__OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
# Finally link to the EPICS Base libraries
_APPNAME__LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1,23 @@
/* _APPNAME_Main.cpp */
/* Author: Marty Kraimer Date: 17MAR2000 */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "epicsExit.h"
#include "epicsThread.h"
#include "iocsh.h"
int main(int argc,char *argv[])
{
if(argc>=2) {
iocsh(argv[1]);
epicsThreadSleep(.2);
}
iocsh(NULL);
epicsExit(0);
return(0);
}
+6
View File
@@ -0,0 +1,6 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS += $(wildcard *ioc*)
DIRS += $(wildcard as*)
include $(CONFIG)/RULES_DIRS
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = envPaths
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = cdCommands
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,5 @@
TOP = ../..
include $(TOP)/configure/CONFIG
ARCH = _ARCH_
TARGETS = envPaths dllPath.bat
include $(TOP)/configure/RULES.ioc
@@ -0,0 +1,21 @@
#!../../bin/_ARCH_/_APPNAME_
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
< envPaths
cd ${TOP}
## Register all support components
dbLoadDatabase "dbd/_APPNAME_.dbd"
_CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadRecords("db/xxx.db","user=_USER_Host")
cd ${TOP}/iocBoot/${IOC}
iocInit
## Start any sequence programs
#seq sncxxx,"user=_USER_Host"
@@ -0,0 +1,18 @@
#!../../bin/_ARCH_/_APPNAME_
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
#< envPaths
## Register all support components
dbLoadDatabase("../../dbd/_APPNAME_.dbd",0,0)
_CSAFEAPPNAME__registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadRecords("../../db/_APPNAME_.db","user=_USER_")
iocInit()
## Start any sequence programs
#seq snc_APPNAME_,"user=_USER_"
@@ -0,0 +1,19 @@
## Example RTEMS startup script
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
#< envPaths
## Register all support components
dbLoadDatabase("dbd/_APPNAME_.dbd")
_CSAFEAPPNAME__registerRecordDeviceDriver(pdbbase)
## Load record instances
#dbLoadTemplate("db/_APPNAME_.substitutions")
#dbLoadRecords("db/_APPNAME_.db", "user=_USER_")
iocInit
## Start any sequence programs
#seq(sncxxx, "user=_USER_")
@@ -0,0 +1,29 @@
## Example vxWorks startup file
## The following is needed if your board support package doesn't at boot time
## automatically cd to the directory containing its startup script
#cd "_TOP_/iocBoot/_IOC_"
< cdCommands
#< ../nfsCommands
cd topbin
## You may have to change _APPNAME_ to something else
## everywhere it appears in this file
ld 0,0, "_APPNAME_.munch"
## Register all support components
cd top
dbLoadDatabase "dbd/_APPNAME_.dbd"
_CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadTemplate "db/_APPNAME_.substitutions"
#dbLoadRecords "db/_APPNAME_.db", "user=_USER_"
cd startup
iocInit
## Start any sequence programs
#seq &sncxxx, "user=_USER_"
@@ -0,0 +1,29 @@
#Instructions for creating and using a real nfsCommands file
#
# in order to use nfs do the following:
# 1) Create hostAdd and nfsMount commands for each nfs server
# 2) In each st.cmd file add the following two commands BEFORE any load commands
# ../nfs.cmd
# cd "<iocname>
#
# The hostAdd command has the form:
# hostAdd("<host>","xxx.xxx.xxx.xxx")
#
# The vxWorks nfsMount command has the form:
# nfsMount("<host>")
#
# You can also mount subdirectories as follows:
# nfsMount("<host>", "/xxx/xxx/xxx", "/xxx")
#
# For example assume
#
# host is mercury with inet address 155.77.2.56
# You want to mount the directory (which is a file system of mercury)
# /home/mercury5/iocinfo
# as
# /iocinfo
#
# The commands would be
#
# hostAdd("mercury","155.77.2.56")
# nfsMount("mercury","/home/mercury5/iocinfo","/iocinfo")
@@ -0,0 +1,29 @@
#Instructions for creating and using a real nfsCommands file
#
# in order to use nfs do the following:
# 1) Create hostAdd and nfsMount commands for each nfs server
# 2) In each st.cmd file add the following two commands BEFORE any load commands
# ../nfs.cmd
# cd "<iocname>
#
# The hostAdd command has the form:
# hostAdd("<host>","xxx.xxx.xxx.xxx")
#
# The vxWorks nfsMount command has the form:
# nfsMount("<host>")
#
# You can also mount subdirectories as follows:
# nfsMount("<host>", "/xxx/xxx/xxx", "/xxx")
#
# For example assume
#
# host is mercury with inet address 155.77.2.56
# You want to mount the directory (which is a file system of mercury)
# /home/mercury5/iocinfo
# as
# /iocinfo
#
# The commands would be
#
# hostAdd("mercury","155.77.2.56")
# nfsMount("mercury","/home/mercury5/iocinfo","/iocinfo")
@@ -0,0 +1,22 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#----------------------------------------------------
# Optimization of db files using dbst (DEFAULT: NO)
#DB_OPT = YES
#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
#DB += xxx.db
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_template = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
+7
View File
@@ -0,0 +1,7 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
include $(TOP)/configure/RULES_DIRS
@@ -0,0 +1,28 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#==================================================
# build a support library
LIBRARY_IOC += _APPNAME_
# xxxRecord.h will be created from xxxRecord.dbd
#DBDINC += xxxRecord
# install _APPNAME_.dbd into <top>/dbd
DBD += _APPNAME_.dbd
# specify all source files to be compiled and added to the library
#_APPNAME__SRCS += xxx
_APPNAME__LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1,6 @@
# provide definitions such as
#include "xxxRecord.dbd"
#device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
#driver(myDriver)
#registrar(myRegistrar)
#variable(myVariable)