EPICS简单实例2 -- subroutine记录(sub)介绍与使用

这个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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值