#!/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: makeBaseApp [-e] appname ... " if [ "$PWD" = "$HOME" ]; then Cleanup 1 "In Home Directory" "$USAGE"; fi; #Find EPICS_BASE from path portion of command DIR=`echo $0 | sed -n -e "/bin/s/.*/bin/p"` if [ -z "$DIR" ]; then DIR=`echo $0 | sed -n -e "/src/s/.*/src/p"` fi if [ -z "$DIR" ]; then Cleanup 1 "Cant find epics base. Use full path " "${USAGE}" fi EPICS_BASE=`echo $0 | sed -e "s%\(.*\)/${DIR}.*%\1%"` #look for options (Currently only and -e) while getopts e OPT do case $OPT in e) EXAMPLES=TRUE ;; \?) Cleanup 1 "$USAGE" ;; esac done shift `expr $OPTIND - 1` if [ ! -f Makefile ]; then cat > Makefile <<-\END TOP = . include $(TOP)/config/CONFIG_APP DIRS += $(wildcard *App) DIRS += iocBoot include $(TOP)/config/RULES_TOP END fi if [ ! -d config ]; then mkdir config cat > config/CONFIG <<-\END #CONFIG # Add any changes to make rules here #CROSS_COMPILER_TARGET_ARCHS = mv167 END cat > config/CONFIG_APP <<-\END #CONFIG_APP DO NOT EDIT THIS FILE include $(TOP)/config/RELEASE ifndef T_A T_A = $(HOST_ARCH) endif include $(EPICS_BASE)/config/CONFIG ifdef SHARE USR_INCLUDES += -I$(SHARE)/include SHARE_BIN = $(SHARE)/bin/$(T_A) endif ifdef MASTER_IOCAPPS USR_INCLUDES += -I$(MASTER_IOCAPPS)/include MASTER_IOCAPPS_BIN = $(MASTER_IOCAPPS)/bin/$(T_A) endif include $(TOP)/config/CONFIG END cat > config/RELEASE <<-END #RELEASE Location of external products EPICS_BASE=${EPICS_BASE} #SHARE= #MASTER_IOCAPPS= END cat > config/RULES.Db <<-\END #RULES.Db include $(EPICS_BASE)/config/RULES.Db END cat > config/RULES.Host <<-\END #RULES.Host include $(EPICS_BASE)/config/RULES.Host END cat > config/RULES.Vx <<-\END #RULES.Vx include $(EPICS_BASE)/config/RULES.Vx inc:: $(INSTALL_INCREC) END cat > config/RULES.ioc <<-\END #RULES.ioc include $(EPICS_BASE)/config/RULES.ioc END cat > config/RULES_ARCHS <<-\END #RULES_ARCHS include $(EPICS_BASE)/config/RULES_ARCHS END cat > config/RULES_DIRS <<-\END #RULES_DIRS include $(EPICS_BASE)/config/RULES_DIRS END cat > config/RULES_TOP <<\END #RULES_TOP include $(EPICS_BASE)/config/RULES_TOP ifdef MASTER_IOCAPPS inc: softlinks buildInstall: softlinks softlinks: @echo "softlinks" ; if [ "$(MASTER_IOCAPPS)" ]; then \ for DIR in bin lib dbd include man ; do \ $(SHARE)/config/makeSoftLinks $(MASTER_IOCAPPS) $${DIR} ;\ done; fi .PHONY :: softlinks endif END fi if [ $# = 0 ]; then Cleanup 0; fi; for APPNAME do if [ -d "${APPNAME}App" ]; then continue; fi mkdir ${APPNAME}App if [ $? -ne 0 ]; then Cleanup 1 "$USAGE"; fi cd ${APPNAME}App cat > Makefile <<-\END TOP = .. include $(TOP)/config/CONFIG_APP DIRS += $(wildcard *src*) DIRS += $(wildcard *Db*) include $(TOP)/config/RULES_DIRS END mkdir Db cat > Db/Makefile <<-\END TOP = ../.. include $(TOP)/config/CONFIG_APP include $(TOP)/config/RULES.Db END 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 $(TOP)/config/RULES_ARCHS END sed -e "s/APPNAME/${APPNAME}/" > src/Makefile.Vx <<-\END # Makefile.Vx TOP = ../../.. include $(TOP)/config/CONFIG_APP #---------------------------------------- # ADD MACRO DEFINITIONS AFTER THIS LINE END if [ -n "${EXAMPLES}" ]; then sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Vx <<-\END RECTYPES += xxxRecord.h USER_DBDFLAGS += -I .. -I $(EPICS_BASE)/dbd DBDEXPAND = APPNAMEInclude.dbd DBDNAME = APPNAMEApp.dbd SRCS.c += ../xxxRecord.c SRCS.c += ../devXxxSoft.c include ../baseLIBOBJS LIBOBJS += xxxRecord.o LIBOBJS += devXxxSoft.o LIBOBJS += sncExample.o LIBNAME = APPNAMELib INSTALLS += vxWorks vxWorks.sym iocCore seq END else sed -e "s/APPNAME/${APPNAME}/" >> src/Makefile.Vx <<-\END #RECTYPES += anyRecord.h USER_DBDFLAGS += -I .. -I $(EPICS_BASE)/dbd #DBDEXPAND = APPNAMEInclude.dbd #DBDNAME = APPNAMEApp.dbd #SRCS.c += ../anysource.c #include ../baseLIBOBJS #LIBOBJS += anysource.o #LIBNAME = APPNAMELib #INSTALLS += vxWorks vxWorks.sym iocCore seq END fi cat >> src/Makefile.Vx <<-\END #Note that the command line that builds the #library $(LIBNAME) may be HUGE (>3kB) # include $(TOP)/config/RULES.Vx #---------------------------------------- # ADD RULES AFTER THIS LINE END cat > src/Makefile.Host <<-\END # Makefile.Host TOP = ../../.. include $(TOP)/config/CONFIG_APP #---------------------------------------- # ADD MACRO DEFINITIONS AFTER THIS LINE #USR_CFLAGS += PROD_LIBS_DEFAULT += m PROD_LIBS_WIN32 := -nil- PROD_LIBS += ca PROD_LIBS += Db PROD_LIBS += Com END if [ -n "${EXAMPLES}" ]; then cat >> src/Makefile.Host <<-\END PROD += caExample END else cat >> src/Makefile.Host <<-\END #PROD += xxx END fi cat >> src/Makefile.Host <<-\END include $(TOP)/config/RULES.Host #---------------------------------------- # 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 if [ -f ${EPICS_BASE}/dbd/base.dbd ]; then cp ${EPICS_BASE}/dbd/base.dbd src/base.dbd else echo "${EPICS_BASE}/dbd/base.dbd does not exist" fi if [ -f ${EPICS_BASE}/dbd/baseLIBOBJS ]; then cp ${EPICS_BASE}/dbd/baseLIBOBJS src/baseLIBOBJS else echo "${EPICS_BASE}/dbd/baseLIBOBJS does not exist" fi if [ -n "${EXAMPLES}" ]; then #if source starts with blank tab replace by tab sed -e "s/ / /" > src/caExample.c <<-\END /*caExample.c*/ #include #include #include #include #include "cadef.h" 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 /* xxxRecord.c */ /* Example record support module */ #include #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 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 /*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; { 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); } 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 fi cd .. if [ ! -d iocBoot ]; then mkdir iocBoot; cat > iocBoot/Makefile <<-\END TOP = .. include $(TOP)/config/CONFIG_APP DIRS += $(wildcard *ioc*) include $(TOP)/config/RULES_DIRS END fi if [ -d iocBoot/ioc${APPNAME} ]; then continue; fi mkdir iocBoot/ioc${APPNAME} cd iocBoot/ioc${APPNAME} cat > Makefile <<-\END TOP = ../.. include $(TOP)/config/CONFIG_APP ARCH = ??? include $(TOP)/config/RULES.ioc END sed -e "s/USER/${USER}/" \ -e "s/APPNAME/${APPNAME}/" > st.cmd <<-\END # Example vxWorks startup file #Following must be added for many board support packages #cd ld < bin/iocCore ld < bin/seq ld < bin/APPNAMELib dbLoadDatabase("dbd/APPNAMEApp.dbd") END if [ -n "${EXAMPLES}" ]; then sed -e "s/USER/${USER}/" \ -e "s/APPNAME/${APPNAME}/" >> st.cmd <<-\END dbLoadRecords("APPNAMEApp/Db/dbExample.db","user=USER") iocInit seq &snctest END else sed -e "s/USER/${USER}/" \ -e "s/APPNAME/${APPNAME}/" >> st.cmd <<-\END #dbLoadRecords("APPNAMEApp/Db/xxx.db","user=USER") iocInit #start sequence programs #seq &sncxxx END fi cd ../.. done Cleanup 0