#!/bin/sh
#
# iocMakeApp
#
# Author: Marty Kraimer
#
#set -xv
SAVEDIR=$PWD
EXAMPLES=""
Cleanup() {
cd $SAVEDIR
rtncode=$1
shift 1
for MESSAGE
do
echo "$MESSAGE"
done
exit $rtncode
}
USAGE="Usage: iocMakeApp -r release -e appname ... "
if [ "$PWD" = "$HOME" ]; then Cleanup 1 "In Home Directory" "$USAGE"; fi;
#look for options (Currently only -r release and -e)
RELEASE=
while getopts r:e OPT
do
case $OPT in
r) RELEASE=$OPTARG
;;
e) EXAMPLES=TRUE
;;
\?)
Cleanup 1 "$USAGE"
;;
esac
done
shift `expr $OPTIND - 1`
#if user did not specify release and none exists error
if [ -z "$RELEASE" -a ! -f EPICS_BASE ]; then
Cleanup 1 "No release " "$USAGE"
fi
if [ ! -z "$RELEASE" ]; then
${RELEASE}/bin/${HOST_ARCH}/getrel ${RELEASE}
if [ ! -f EPICS_BASE ]; then
Cleanup 1 "Did not detect successful getrel" "$USAGE"
fi
fi
EPICS_BASE=`sed -e "s%EPICS_BASE=%%" < EPICS_BASE`
if [ ! -f Makefile ]; then
cat > Makefile <<-\END
TOP = .
include $(TOP)/config/CONFIG_APP
#add directories as follows
#DIRS +=
include $(EPICS_BASE)/config/RULES_TOP
END
fi
if [ ! -d config ]; then
mkdir config
cat > config/CONFIG <<-\END
# Add any changes to make rules here
END
cat > config/CONFIG_APP <<-\END
#CONFIG_APP DO NOT EDIT THIS FILE
include $(TOP)/EPICS_BASE
include $(EPICS_BASE)/config/CONFIG
include $(TOP)/config/CONFIG
END
cat > config/RULES.Unix <<-\END
include $(EPICS_BASE)/config/RULES.Unix
END
cat > config/RULES.Vx <<-\END
include $(EPICS_BASE)/config/RULES.Vx
END
cat > config/RULES_DIRS <<-\END
include $(EPICS_BASE)/config/RULES_DIRS
END
fi
if [ $# = 0 ]; then Cleanup 0; fi;
for APPNAME
do
if [ -d "${APPNAME}" ]; then continue; fi
mkdir ${APPNAME}
if [ $? -ne 0 ]; then Cleanup 1 "$USAGE"; fi
cd ${APPNAME}
cat > Makefile <<-\END
TOP = ..
include $(TOP)/config/CONFIG_APP
DIRS = src
include $(EPICS_BASE)/config/RULES_DIRS
END
mkdir db
if [ -n "${EXAMPLES}" ]; then
#if source starts with blank tab replace by tab
sed -e "s/ / /" > db/dbExample.db <<-\END
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 src/Makefile <<-\END
TOP=../..
include $(TOP)/config/CONFIG_APP
include $(EPICS_BASE)/config/RULES_ARCHS
END
sed -e "s/APPNAME/${APPNAME}/" > src/Makefile.Vx <<-\END
# Makefile.Vx
TOP = ../../..
include $(TOP)/config/CONFIG_APP
INSTALL_LOCATION = $(TOP)
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
END
if [ -n "${EXAMPLES}" ]; then
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Vx <<-\END
RECTYPES += xxxRecord.h
USR_INCLUDES += -I$(EPICS_BASE)/include
USER_DBDFLAGS += -I .. -I $(EPICS_BASE)/dbd
DBDEXPAND = APPNAMEInclude.dbd
DBDNAME = APPNAME.dbd
include ../baseLIBOBJS
LIBOBJS += xxxRecord.o
LIBOBJS += devXxxSoft.o
LIBOBJS += sncExample.o
LIBNAME = APPNAMESupport
SCRIPTS += st.APPNAME
SCRIPTS += vxWorks vxWorks.sym iocCore seq
END
else
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Vx <<-\END
#RECTYPES += xxxRecord.h
USR_INCLUDES += -I$(EPICS_BASE)/include
USER_DBDFLAGS += -I .. -I $(EPICS_BASE)/dbd
#DBDEXPAND = APPNAMEInclude.dbd
#DBDNAME = APPNAME.dbd
#include ../baseLIBOBJS
#LIBOBJS += xxx.o
#LIBNAME = APPNAMESupport
#SCRIPTS += st.APPNAME
#SCRIPTS += vxWorks vxWorks.sym iocCore seq
END
fi
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Vx <<-\END
include $(TOP)/config/RULES.Vx
#----------------------------------------
# ADD RULES AFTER THIS LINE
$(LIBNAME): ../baseLIBOBJS
$(DBDNAME): ../base.dbd ../APPNAMEInclude.dbd
$(DBDNAME): $(RECTYPES:%.h=%.dbd)
END
cat > src/Makefile.Unix <<-\END
# Makefile.Unix
TOP = ../../..
include $(TOP)/config/CONFIG_APP
INSTALL_LOCATION = $(TOP)
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#USR_CFLAGS +=
USR_INCLUDES += -I$(EPICS_BASE)/include
DEPLIBS += $(EPICS_BASE_LIB)/libca.a
DEPLIBS += $(EPICS_BASE_LIB)/libCom.a
USR_LDFLAGS = -L$(EPICS_BASE_LIB)
USR_LDLIBS = -lca -lDb -lCom
END
if [ -n "${EXAMPLES}" ]; then
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Unix <<-\END
OBJS += caExample.o
PROD += caExample
END
else
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Unix <<-\END
#OBJS += xxx.o
#PROD += xxx
END
fi
sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Unix <<-\END
include $(TOP)/config/RULES.Unix
#----------------------------------------
# ADD RULES AFTER THIS LINE
END
if [ -n "${EXAMPLES}" ]; then
cat > src/${APPNAME}Include.dbd <<-\END
include "base.dbd"
include "xxxRecord.dbd"
device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
END
else
cat > src/${APPNAME}Include.dbd <<-\END
include "base.dbd"
#private database definitions go here
#device(xxx,CONSTANT,devXxxSoft,"SoftChannel")
END
fi
cp ${EPICS_BASE}/dbd/base.dbd src/base.dbd
cp ${EPICS_BASE}/dbd/baseLIBOBJS src/baseLIBOBJS
sed -e "s/USER/${USER}/" \
-e "s/APPNAME/${APPNAME}/" > src/st.${APPNAME} <<-\END
# Example vxWorks startup file
#Following must be added for many board support packages
#cd
ld < iocCore
ld < seq
ld < APPNAMESupport
dbLoadDatabase("../../dbd/APPNAME.dbd")
END
if [ -n "${EXAMPLES}" ]; then
sed -e "s/USER/${USER}/" \
-e "s/APPNAME/${APPNAME}/" >> src/st.${APPNAME} <<-\END
dbLoadRecords("../../APPNAME/db/dbExample.db","user=USER")
iocInit
seq &snctest
END
else
sed -e "s/USER/${USER}/" \
-e "s/APPNAME/${APPNAME}/" >> src/st.${APPNAME} <<-\END
#dbLoadRecords("../../APPNAME/db/xxx.db","user=USER")
iocInit
#start sequence programs
#seq &sncxxx
END
fi
if [ -z "${EXAMPLES}" ]; then Cleanup 0; fi;
#if source starts with blank tab replace by tab
sed -e "s/ / /" > src/caExample.c <<-\END
/*caExample.c*/
#include
#include
#include
#include
#include
main(int argc,char **argv)
{
double data;
int status;
chid mychid;
if(argc != 2) {
fprintf(stderr,"usage: caExample pvname\n");
exit(1);
}
SEVCHK(ca_task_initialize(),"ca_task_initialize");
SEVCHK(ca_search(argv[1],&mychid),"ca_search 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);
}
END
#if source starts with blank tab replace by tab
sed -e "s/ / /" > src/xxxRecord.c <<-\END
/* recXxx.c */
/* Example record support module */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GEN_SIZE_OFFSET
#include
#undef GEN_SIZE_OFFSET
/* 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();
struct 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};
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 alarm(xxxRecord *pxxx);
static void convert(xxxRecord *pxxx);
static void monitor(xxxRecord *pxxx);
static long init_record(void *precord,int pass)
{
xxxRecord *pxxx = (xxxRecord *)precord;
xxxdset *pdset;
long status;
if (pass==0) return(0);
if(!(pdset = (xxxdset *)(pxxx->dset))) {
recGblRecordError(S_dev_noDSET,(void *)pxxx,"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 *)pxxx,"xxx: init_record");
return(S_dev_missingSup);
}
if( pdset->init_record ) {
if((status=(*pdset->init_record)(pxxx))) return(status);
}
return(0);
}
static long process(void *precord)
{
xxxRecord *pxxx = (xxxRecord *)precord;
xxxdset *pdset = (xxxdset *)(pxxx->dset);
long status;
unsigned char pact=pxxx->pact;
if( (pdset==NULL) || (pdset->read_xxx==NULL) ) {
pxxx->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)pxxx,"read_xxx");
return(S_dev_missingSup);
}
/* pact must not be set until after calling device support */
status=(*pdset->read_xxx)(pxxx);
/* check if device support set pact */
if ( !pact && pxxx->pact ) return(0);
pxxx->pact = TRUE;
recGblGetTimeStamp(pxxx);
/* check for alarms */
alarm(pxxx);
/* check event list */
monitor(pxxx);
/* process the forward scan link record */
recGblFwdLink(pxxx);
pxxx->pact=FALSE;
return(status);
}
static long get_units(DBADDR *paddr, char *units)
{
xxxRecord *pxxx=(xxxRecord *)paddr->precord;
strncpy(units,pxxx->egu,DB_UNITS_SIZE);
return(0);
}
static long get_precision(DBADDR *paddr, long *precision)
{
xxxRecord *pxxx=(xxxRecord *)paddr->precord;
*precision = pxxx->prec;
if(paddr->pfield == (void *)&pxxx->val) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
xxxRecord *pxxx=(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 = pxxx->hopr;
pgd->lower_disp_limit = pxxx->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
xxxRecord *pxxx=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL
|| fieldIndex == xxxRecordHIHI
|| fieldIndex == xxxRecordHIGH
|| fieldIndex == xxxRecordLOW
|| fieldIndex == xxxRecordLOLO) {
pcd->upper_ctrl_limit = pxxx->hopr;
pcd->lower_ctrl_limit = pxxx->lopr;
} else recGblGetControlDouble(paddr,pcd);
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
xxxRecord *pxxx=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL) {
pad->upper_alarm_limit = pxxx->hihi;
pad->upper_warning_limit = pxxx->high;
pad->lower_warning_limit = pxxx->low;
pad->lower_alarm_limit = pxxx->lolo;
} else recGblGetAlarmDouble(paddr,pad);
return(0);
}
static void alarm(xxxRecord *pxxx)
{
double val;
float hyst, lalm, hihi, high, low, lolo;
unsigned short hhsv, llsv, hsv, lsv;
if(pxxx->udf == TRUE ){
recGblSetSevr(pxxx,UDF_ALARM,INVALID_ALARM);
return;
}
hihi = pxxx->hihi; lolo = pxxx->lolo; high = pxxx->high; low = pxxx->low;
hhsv = pxxx->hhsv; llsv = pxxx->llsv; hsv = pxxx->hsv; lsv = pxxx->lsv;
val = pxxx->val; hyst = pxxx->hyst; lalm = pxxx->lalm;
/* alarm condition hihi */
if (hhsv && (val >= hihi || ((lalm==hihi) && (val >= hihi-hyst)))){
if (recGblSetSevr(pxxx,HIHI_ALARM,pxxx->hhsv)) pxxx->lalm = hihi;
return;
}
/* alarm condition lolo */
if (llsv && (val <= lolo || ((lalm==lolo) && (val <= lolo+hyst)))){
if (recGblSetSevr(pxxx,LOLO_ALARM,pxxx->llsv)) pxxx->lalm = lolo;
return;
}
/* alarm condition high */
if (hsv && (val >= high || ((lalm==high) && (val >= high-hyst)))){
if (recGblSetSevr(pxxx,HIGH_ALARM,pxxx->hsv)) pxxx->lalm = high;
return;
}
/* alarm condition low */
if (lsv && (val <= low || ((lalm==low) && (val <= low+hyst)))){
if (recGblSetSevr(pxxx,LOW_ALARM,pxxx->lsv)) pxxx->lalm = low;
return;
}
/* we get here only if val is out of alarm by at least hyst */
pxxx->lalm = val;
return;
}
static void monitor(xxxRecord *pxxx)
{
unsigned short monitor_mask;
double delta;
monitor_mask = recGblResetAlarms(pxxx);
/* check for value change */
delta = pxxx->mlst - pxxx->val;
if(delta<0.0) delta = -delta;
if (delta > pxxx->mdel) {
/* post events for value change */
monitor_mask |= DBE_VALUE;
/* update last value monitored */
pxxx->mlst = pxxx->val;
}
/* check for archive change */
delta = pxxx->alst - pxxx->val;
if(delta<0.0) delta = -delta;
if (delta > pxxx->adel) {
/* post events on value field for archive change */
monitor_mask |= DBE_LOG;
/* update last archive value monitored */
pxxx->alst = pxxx->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(pxxx,&pxxx->val,monitor_mask);
}
return;
}
END
#if source starts with blank tab replace by tab
sed -e "s/ / /" > src/xxxRecord.dbd <<-\END
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)
}
}
END
#if source starts with blank tab replace by tab
sed -e "s/ / /" > src/devXxxSoft.c <<-\END
/* devXxxSoft.c */
/* Example device support module */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Added for Channel Access Links */
long dbCaAddInlink();
long dbCaGetLink();
/*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,
};
static long init_record(pxxx)
struct xxxRecord *pxxx;
{
long status;
/* xxx.inp must be a CONSTANT or a PV_LINK or a DB_LINK or a CA_LINK*/
switch (pxxx->inp.type) {
case (CONSTANT) :
if(recGblInitConstantLink(&pxxx->inp,DBF_DOUBLE,&pxxx->val))
pxxx->udf = FALSE;
break;
case (PV_LINK) :
case (CA_LINK) :
case (DB_LINK) :
break;
default :
recGblRecordError(S_db_badField, (void *)pxxx,
"devXxxSoft (init_record) Illegal INP field");
return(S_db_badField);
}
return(0);
}
static long read_xxx(pxxx)
struct xxxRecord *pxxx;
{
long status;
status = dbGetLink(&(pxxx->inp),DBF_DOUBLE, &(pxxx->val),0,0);
if (RTN_SUCCESS(status))
pxxx->udf = FALSE;
return(0);
}
END
#if source starts with blank tab replace by tab
sed -e "s/USER/${USER}/" \
-e "s/ / /" > src/sncExample.st <<-\END
program snctest
float v;
assign v to "USER:xxxExample";
monitor v;
ss ss1
{
state low
{
when(v>5.0)
{
printf("changing to high\n");
} state high
when(delay(.1))
{
} state low
}
state high
{
when(v<=5.0)
{
printf("changing to low\n");
} state low
when(delay(.1))
{
} state high
}
}
END
cd ..
echo "add line to Makefile DIRS+=$APPNAME "
done
Cleanup 0