这个subroutine记录用于调用一个C初始化程序和一个重复出现的扫描程序。没有设备支持对应这个记录。
参数字段
在以下描述记录专用字段,按功能分组。
扫描参数
subroutine记录有用于指定这个记录在什么情况下将被运行的标准字段。
读取字段
subroutine记录有12格输入记录(INPA-INPL),每个输入链接有一个对应的值字段(A-L)。这些字段用于此记录调用获取和存储能够被传递给这个subroutine的值。
输入链接可以时通道访问或数据库链接或常数。当常数时,用这个常数值初始化对应这个链接的相应值字段,并且在运行时通过dbPuts可以更改这个字段的值。否则,当运行这个记录时从输入链接为(A-F)获取值。
subroutine连接
这些字段用于连接到C子程序。在SNAM字段中应该输入这个子程序的名称。
操作显示参数
这些参数用于向操作显示有意思数据。它们以文本地或图形地显示这个subroutine的值或其它参数。EGU是最长16个字符的字符串,它描述这个subroutine记录使用的任何单位。通过get_units记录支持程序获取它。
HOPR和LOPR字段是用于VAL, A-L, LA-LL, HIHI, LOLO, LOW和HIGH字段的上下显示限制。get_graphic_double和get_control_double记录支持程序都获取这些字段。
PREC字段决定了用什么浮点精度显示VAL。当调用get_precision记录支持时,使用它。
警报参数
对于subroutine记录的可能警报情况是SCAN,READ,limit警报以及如果subroutine返回一个负值能被触发的警报。SCAN和READ警报是被记录或设备支持程序调用。限制的警报是由用户使用数值在HIHI,LOLO,HIGH和LOW字段中配置的。它们应用于VAL字段。对于这些字段中每一个字段,有一个相应的严重性字段,其可以是NO_ALARM, MINOR或MAJOR。
BRSV字段是在这个routine返回一个负值时用户能够设置警报严重性的地方。
警报的字段类列出了与所有记录类型都共有的警报关联。
用于监视的参数
这些参数用于决定何时发出放置于VAL字段上的监视。当VAL不同于在ALST和MLST运行时字段中的值时,调用合适的监视,即是:当VAL的值变化超过了在这些字段中指定的死区时。ADEL和MEDL字段指定在调用值变化监视前这个变化必须超过的最小差值。如果这些字段有一个0值,每次值变化,将触发一个监视;如果它们有一个-1值,每次记录运行,触发监视。ADEL字段被存档监视使用,MDEL字段用于所有其它类型的监视。
运行时参数
这些参数被运行时代码使用,用于运行这个subroutine记录。不能使用数据库配置工具配置它们。它们代表这个记录的当前状态。它们中很多被记录processing程序或监视使用。
VAL字段应该被subroutine设置。SADR保存这个subroutine地址并且由这个记录processing程序设置。
余下字段LALM,ALST,MLST和LA-LL用于实现监视。例如,当LA不等于A,调用对应那个字段的值变化监视。
记录支持
记录支持程序
1) init_record
long (*init_record)(struct dbCommon *precord, int pass)
对于每个常数输入链接,用这个常数值初始化相应的值字段。对于为类型PV_LINK的每个输入链接,创建一个通道访问。如果定义了一个初始化subroutine,找到并且调用它。进行处理的subroutine被找到并且其地址存储在SADR中。
2) process
long (*init_record)(struct dbCommon *precord, int pass)
见以下"记录运行""
3) get_units
long (*get_units)(struct dbAddr *paddr, char *units)
4) get_precsion
long (*get_precision)(const struct dbAddr *paddr, long *precision)
当VAL时被引用的字段时,获取PREC。否则,调用recGblGetPrec()。
5) get_graphic_double
long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p)
为一个字段设置上显示和下显示限制。如果字段是VAL,A-L,LA-LL,HIHI,HIGH,LOW或LOLO,这些限制被设置成HOPR和LOPR,另外如果字段有定义的上和下限制,将使用它们,否则将使用对应这个字段类型的上和下最大值。
6) get_control_double
为一个字段设置上显示和下控制限制。如果字段是VAL,A-L,LA-LL,HIHI,HIGH,LOW或LOLO,这些限制被设置成HOPR和LOPR,另外如果字段有定义的上和下限制,将使用它们,否则将使用对应这个字段类型的上和下最大值。
long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p)
7) get_alarm_double
long (*get_alarm_double)(struct dbAddr *paddr, struct dbr_alDouble *p)
设置以下值:
upper_alarm_limit = HIHI
upper_warning_limit = HIGH
lower_warning_limit = LOW
lower_alarm_limit = LOLO
记录运行
程序Process实现以下算法:
1) 如果PACT为FALSE,则获取所有参数。
2) 调用这个subroutine并且检查返回值。
- 调用subroutine
- 设置PACT为TRUE
- 如果返回值是1,返回
3) 检查警报。这个routine检查新的VAL是否引起警报状态和严重性变化。如果发生了,设置NSEV,NSTA和LALM。它也遵守警报回滞因子(HYST)。因而,在警报状态和验证性被降低前,这个值必须变化超过HYST。
4) 检查是否应该调用监视
- 如果警报状态或严重性发生变化,调用警报监视
- 如果ADEL和MDEL条件满足了,调用存档和值变化监视
- 如果A-L的值变化了,调用对应A-L的监视
- 重置NSEV和NSTA回0
5) 如果需要,扫描forward链接。设置PACT为FALSE并且返回。
示例同步subroutine
这是一个在每次调用process时仅对VAL加1的示例subroutine。
在blctrl用户家目录中的exer目录下创建一个子目录exer2,并且使用makeBaseApp.pl产生一个应用程序目录和一个IOC启动目录:
[blctrl@main-machine ~]$ mkdir exer/exer2
[blctrl@main-machine ~]$ cd exer/exer2
[blctrl@main-machine exer2]$ /usr/local/EPICS/base/bin/linux-x86_64/makeBaseApp.pl -t ioc exer2
[blctrl@main-machine exer2]$ /usr/local/EPICS/base/bin/linux-x86_64/makeBaseApp.pl -i -t ioc exer2
Using target architecture linux-x86_64 (only one available)
The following applications are available:
exer2
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name?
[blctrl@main-machine exer2]$ ls
configure exer2App iocBoot Makefile
进入exer2App/src路径下,编写两个文件 subRecordExample.c和subRecordExample.dbd,其内容如下:
subRecordExample.c:
#include <stdio.h>
#include <dbDefs.h>
#include <registryFunction.h>
#include <subRecord.h>
#include <epicsExport.h>
int mySubDebug = 0;
static long mySubInit(struct subRecord *precord)
{
if (mySubDebug)
{
printf("Record %s called mySubInit(%p)\n", precord->name, (void *)precord);
}
printf("subInit was called\n");
return 0;
}
static long mySubProcess(struct subRecord * precord)
{
if(mySubDebug)
{
printf("Record %s called mySubProcess(%p)\n", precord->name,(void *)precord);
}
precord->val++;
return 0;
}
epicsExportAddress(int, mySubDebug);
epicsRegisterFunction(mySubInit);
epicsRegisterFunction(mySubProcess);
subRecordExample.dbd:
variable(mySubDebug)
function(mySubInit)
function(mySubProcess)
为在与以上两个文件相同路径下的Makefile文件添加以下两行:
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the IOC application
PROD_IOC = exer2
# exer2.dbd will be created and installed
DBD += exer2.dbd
# exer2.dbd will be made up from these files:
exer2_DBD += base.dbd
# Include dbd files from all support applications:
#exer2_DBD += xxx.dbd
exer2_DBD += subRecordExample.dbd # 添加行1
exer2_SRCS += subRecordExample.c # 添加行2
# Add all the support libraries needed by this IOC
#exer2_LIBS += xxx
# exer2_registerRecordDeviceDriver.cpp derives from exer2.dbd
exer2_SRCS += exer2_registerRecordDeviceDriver.cpp
# Build the main IOC entry point on workstation OSs.
exer2_SRCS_DEFAULT += exer2Main.cpp
exer2_SRCS_vxWorks += -nil-
# Add support from base/src/vxWorks if needed
#exer2_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
# Finally link to the EPICS Base libraries
exer2_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
进入到路径exer2/exer2App/Db路径下,添加以下一个文件dbSubExample.db,内容如下:
record(sub,"$(user):subExample")
{
field(INAM,"mySubInit")
field(SNAM,"mySubProcess")
}
并且在与上面文件相同路径下的Makefile中添加如下一行:
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
#DB += xxx.db
DB += dbSubExample.db # 添加这一行
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_template = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
然后切换到这个程序的顶层路径,执行make:
[blctrl@telecom exer2]$ make
make -C ./configure install
make[1]: Entering directory `/home/blctrl/exer/exer2/configure'
perl -CSD /usr/local/EPICS/base/bin/linux-x86_64/makeMakefile.pl O.linux-x86_64 ../..
...
make[2]: Leaving directory `/home/blctrl/exer/exer2/iocBoot/iocexer2'
make[1]: Leaving directory `/home/blctrl/exer/exer2/iocBoot'
接着切换到iocBoot/iocexer2路径下,编辑st.cmd文件:
#!../../bin/linux-x86_64/exer2
#- You may have to change exer2 to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/exer2.dbd"
exer2_registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadRecords("db/xxx.db","user=blctrl")
dbLoadRecords("db/dbSubExample.db","user=TEST") # 添加这一行,加载记录
cd "${TOP}/iocBoot/${IOC}"
iocInit
用以下命令启动这个IOC程序:
[blctrl@telecom iocexer2]$ ../../bin/linux-x86_64/exer2 st.cmd
#!../../bin/linux-x86_64/exer2
< envPaths
epicsEnvSet("IOC","iocexer2")
epicsEnvSet("TOP","/home/blctrl/exer/exer2")
epicsEnvSet("EPICS_BASE","/usr/local/EPICS/base")
cd "/home/blctrl/exer/exer2"
## Register all support components
dbLoadDatabase "dbd/exer2.dbd"
exer2_registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadRecords("db/xxx.db","user=blctrl")
dbLoadRecords("db/dbSubExample.db","user=TEST")
cd "/home/blctrl/exer/exer2/iocBoot/iocexer2"
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.3.1
## EPICS Base built Aug 28 2022
############################################################################
subInit was called
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=blctrl"
epics>
测试这个IOC下是否加载了指定的记录:
epics> dbl
TEST:subExample
再开一个命令行终端,测试这个加载的记录:
[root@telecom ~]# caget TEST:subExample
TEST:subExample 0
[root@telecom ~]# cainfo TEST:subExample
TEST:subExample
State: connected
Host: localhost:5064
Access: read, write
Native data type: DBF_DOUBLE
Request type: DBR_DOUBLE
Element count: 1
[root@telecom ~]# caput TEST:subExample.PROC 1
Old : TEST:subExample.PROC 0
New : TEST:subExample.PROC 1
[root@telecom ~]# caget TEST:subExample
TEST:subExample 1