(9) waveform数据拆解举例 以及 event触发举例

注释:文中红色为遗留问题,蓝色为关键点,绿色为因人而异的命名或路径,橙色为可执行的命令。

1 概述

在EPICS中,可以利用支持subroutine的记录来处理waveform数据(或其他数组数据)。支持subroutine的记录有:sub[base]、asub[base]、gensub[OSL]等。asub支持21路数组(或标量)输入和21路数组(或标量)输出,同时asub还支持subroutine,下面利用asub记录实现对waveform数据拆分并分别送入其它ai记录中。
完成数据拆分功能的数据库设计如下图所示,waveform从底层设备或虚拟设备中获取数据,asub对来自waveform的数组数据进行拆分,然后将数组的前四个数分别送入Ai1、Ai2、Ai3、Ai4中。
在这里插入图片描述

在继续以下步骤前,确保linux系统已经正确的安装epics base并建立一个IOC实例,这里建立一个命名为ioc2t的ioc实例。

2 waveform数据拆解步骤

2.1 创建相关记录

方案一

在/testApp/Db文件夹中的dbSubExample.db文件里修改asub记录,然后在dbExample1.db文件里添加一个waveform记录和3个ai记录,代码如下所示,修改完成后对Db文件夹进行编译(make)。(新建一个db文件把这些record添加进去应该也是可以的,不是必须写在上述db文件中的。)

方案二

新建一个myasubsimulate.db文件,这个时候几个地方需要加入对该文件的引入:
(1) ioc2App/db/makefile 中加入: DB += myasubsimulate.db
在这里插入图片描述
(2) iocBoot/ioc2/st.cmd中加入load 该db文件
在这里插入图片描述

2.1.1 asub记录

record(aSub, “KaTeX parse error: Expected '}', got '#' at position 86: …AsubProcess") #̲这个函数需要在2.2节中进行修…(user):wavedouble”)
field(FLNK, “$(user):wai1”)
field(FTVA, “DOUBLE”)
field(FTVB, “DOUBLE”)
field(FTVC, “DOUBLE”)
field(FTVD, “DOUBLE”)
}

2.1.2 waveform记录和ai记录

record(compress, “KaTeX parse error: Expected '}', got 'EOF' at end of input: … field(INP, "(user):aiExample.VAL CP NMS”)
field(NSAM, “10”)
field(HOPR, “10”)
field(EGU, “Counts”)
}

record(waveform, “KaTeX parse error: Expected '}', got 'EOF' at end of input: … field(FLNK, "(user):myasubexample”)
field(INP, “KaTeX parse error: Expected 'EOF', got '#' at position 27: …ressexample") #̲ compressexampl…(user):wai1”) {
field(DESC, “Analog input 1”)
field(FLNK, “(user):wai2")field(INP,"(user):wai2") field(INP, "(user):aSubExample.VALA NPP NMS”)
}
record(ai, “KaTeX parse error: Expected '}', got 'EOF' at end of input: … field(FLNK, "(user):wai3”)
field(INP, “KaTeX parse error: Expected 'EOF', got '}' at position 35: …VALB NPP NMS") }̲ record(ai, "(user):wai3”) {
field(DESC, “Analog input 3”)
field(FLNK, “(user):wai4")field(INP,"(user):wai4") field(INP, "(user):aSubExample.VALC NPP NMS”)
}
record(ai, “KaTeX parse error: Expected '}', got 'EOF' at end of input: … field(INP, "(user):aSubExample.VALD NPP NMS”)
}

总结一下 myasubsimulate.db文件中的内容

#! Generated by VisualDCT v2.8.2
#! DBDSTART
#! DBDEND


record(aSub, "$(user):myasubexample") {
  field(INAM, "myAsubInit")
  field(SNAM, "myAsubProcess")
  field(NOA, "10")
  field(INPA, "$(user):wavedouble")
  field(FLNK, "$(user):wai1")
}

record(compress, "$(user):compressexample") {
  field(DESC, "Circle buffer")
  field(ASG, "CIrclee Buffer")
  field(INP, "$(user):aiExample.VAL CP NMS")
  field(NSAM, "10")
  field(HOPR, "10")
  field(EGU, "Counts")
}

record(waveform, "$(user):wavedouble") {
  field(DESC, "test")
  field(SCAN, "1 second")
  field(FLNK, "$(user):myasubexample")
  field(INP, "$(user):compressexample")
  field(NELM, "10")
  field(FTVL, "DOUBLE")
}

record(ai, "$(user):wai1") {
  field(DESC, "Analog input 1")
  field(FLNK, "$(user):wai2")
  field(INP, "$(user):myasubexample.VALA NPP NMS")
}

record(ai, "$(user):wai2") {
  field(DESC, "Analog input 2")
  field(FLNK, "$(user):wai3")
  field(INP, "$(user):myasubexample.VALB NPP NMS")
}

record(ai, "$(user):wai3") {
  field(DESC, "Analog input 3")
  field(FLNK, "$(user):wai4")
  field(INP, "$(user):myasubexample.VALC NPP NMS")
}

record(ai, "$(user):wai4") {
  field(DESC, "Analog input 4")
  field(INP, "$(user):myasubexample.VALD NPP NMS")
}

#! Further lines contain data used by VisualDCT
#! View(-185,-92,0.8)
#! Record("$(user):myasubexample",520,493,0,0,"$(user):myasubexample")
#! Field("$(user):myasubexample.INPA",16777215,0,"$(user):myasubexample.INPA")
#! Link("$(user):myasubexample.INPA","$(user):wavedouble.VAL")
#! Field("$(user):myasubexample.FLNK",16777215,1,"$(user):myasubexample.FLNK")
#! Link("$(user):myasubexample.FLNK","$(user):wai1")
#! Field("$(user):myasubexample.VALA",16777215,1,"$(user):myasubexample.VALA")
#! Field("$(user):myasubexample.VALB",16777215,1,"$(user):myasubexample.VALB")
#! Field("$(user):myasubexample.VALC",16777215,1,"$(user):myasubexample.VALC")
#! Field("$(user):myasubexample.VALD",16777215,1,"$(user):myasubexample.VALD")
#! Record("$(user):compressexample",0,419,0,1,"$(user):compressexample")
#! Field("$(user):compressexample.INP",16777215,1,"$(user):compressexample.INP")
#! Field("$(user):compressexample.VAL",16777215,0,"$(user):compressexample.VAL")
#! Record("$(user):wavedouble",220,399,0,1,"$(user):wavedouble")
#! Field("$(user):wavedouble.FLNK",16777215,1,"$(user):wavedouble.FLNK")
#! Link("$(user):wavedouble.FLNK","$(user):myasubexample")
#! Field("$(user):wavedouble.INP",16777215,0,"$(user):wavedouble.INP")
#! Link("$(user):wavedouble.INP","$(user):compressexample.VAL")
#! Field("$(user):wavedouble.VAL",16777215,1,"$(user):wavedouble.VAL")
#! Record("$(user):wai1",860,542,0,0,"$(user):wai1")
#! Field("$(user):wai1.FLNK",16777215,1,"$(user):wai1.FLNK")
#! Link("$(user):wai1.FLNK","$(user):wai2")
#! Field("$(user):wai1.INP",16777215,0,"$(user):wai1.INP")
#! Link("$(user):wai1.INP","$(user):myasubexample.VALA")
#! Record("$(user):wai2",1100,562,0,1,"$(user):wai2")
#! Field("$(user):wai2.FLNK",16777215,1,"$(user):wai2.FLNK")
#! Link("$(user):wai2.FLNK","$(user):wai3")
#! Field("$(user):wai2.INP",16777215,0,"$(user):wai2.INP")
#! Link("$(user):wai2.INP","$(user):myasubexample.VALB")
#! Record("$(user):wai3",1380,582,0,0,"$(user):wai3")
#! Field("$(user):wai3.FLNK",16777215,1,"$(user):wai3.FLNK")
#! Link("$(user):wai3.FLNK","$(user):wai4")
#! Field("$(user):wai3.INP",16777215,0,"$(user):wai3.INP")
#! Link("$(user):wai3.INP","$(user):myasubexample.VALC")
#! Record("$(user):wai4",1640,635,0,0,"$(user):wai4")
#! Field("$(user):wai4.INP",16777215,0,"$(user):wai4.INP")
#! Link("$(user):wai4.INP","$(user):myasubexample.VALD")

2.2 修改myAsubProcess函数

2.2.1 修改过程

由于在asub记录里调用了两个subroutine,分别是“myAsubInit”和“myAsubProcess”,需要修改myAsubProcess函数。(“myAsubInit”负责记录初始化,这个暂时不用管。)
在/testApp/src中,找到dbSubExample.c函数文件,“myAsubProcess”和“myAsubInit”的都定义在此文件中。修改其中的“myAsubProcess”函数,如下所示。(修改完成后要对src文件夹编译(make)。)(也可以新建其他subroutine函数,但要注意前边asub记录里面SNAM应一致;新建方法在2.2.2小节中介绍。)
static long myAsubProcess(aSubRecord *precord)
{
double *indata;
double *p1;
double *p2;
double *p3;
double *p4;
indata = (double *)precord->a;
p1 = (double *)precord->vala;
p2 = (double *)precord->valb;
p3 = (double *)precord->valc;
p4 = (double *)precord->vald;
*p1 = indata[0];
*p2 = indata[1];
*p3 = indata[2];
*p4 = indata[3];

if (mySubDebug)
    printf("Record %s called myAsubProcess(%p)\n",
           precord->name, (void*) precord);
return 0;

}

2.2.2 新建subroutine方法

注意:如果想新增一个subroutine函数,例如myFunction,一定要在dbSubExample.c文件的最下方添加 “epicsRegisterFunction(myFunction);”,然后在src文件夹的dbSubExample.dbd中添加“function(myFunction)”,再对src文件夹进行编译(make),方能生效。(我尝试过.c和.dbd文件也新建,但是失败了,make时显示缺少.o文件。)

2.3 运行结果

在这里插入图片描述

至此已经完成了对数据库的设计和编译,运行IOC就可以获得相关的功能。

3 实现event 触发

3.1 利用event record 发布event

新建myenventsimulate.db

在这里插入图片描述
具体db文件如下:

record(event, "$(user):myevent11") {
  field(SCAN, "1 second")
}
record(event, "$(user):myevent12") {
  field(SCAN, "1 second")
  field(INP, "$(user):calcExample")
}
record(ai, "$(user):myai1") {
  field(SCAN, "Event")
  field(INP, "$(user):wai4") 

myEvent11 手动i发布该事件

应注意,刚刚启动的该ioc 时,这个事件是没有具体的val的,也就是没有具体的触发标号,因此,我们需要手动设定该事件扫描的之后,应该出发的事件号是多少.运行结果如下图所示。myEvent11的值手动输入,为1时发布事件号与myAi1的EVNT设置值相同,则myAi1会被触发,数据更新,与它的INP("$(user):wai4")一致;当修改myEvent11的值≠1时,myAi1不会被触发,因此它的值保持不变。
在这里插入图片描述

myevent12 采用自动触发的情况下发布该事件

yEvent12的INP为calcExample,每隔1s循环发布0~9自然数,每次发布事件号为1时myAi1被触发。(由于myAi1的INP设置原因,每次myEvent12发布事件号为1时,myAi1的值都为一固定值,由于时间问题偶尔有变化,因此难以观察。)(而且它发布事件号可能会扰乱其他event,暂时觉得不太好用。)

利用subroutine 发布event

新增两个record

在这里插入图片描述

record(sub, "$(user):myeventsub") {
  field(INAM, "mySubInit")
  field(SNAM, "myEventSub")  
  field(SCAN, "1 second")  
  field(INPA, "$(user):calcExample")
}
record(ai, "$(user):myAi2") {
  field(SCAN, "Event")
  field(INP, "$(user):calcExample")
  field(EVNT, "2")
}

这个方法的重点是调用Database Access函数,编写c脚本来提供灵活的自定义event控制。在EPICS/IOC2/testApp/src文件夹下的dbSubExample.c文件中添加如下函数:

/////////////////////////////////////////////////////////
//using for user defined event trigger by wangsai
#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 <special.h>
#include <calcRecord.h>
#include <errMdef.h>
#include <recSup.h>
int myEventSub(){
  struct dbAddr paddr;
  dbNameToAddr("scottar:calcExample",&paddr);
  calcRecord    *prec=(calcRecord *)(&paddr)->precord;
  if (prec->val>=5)
  {
    post_event(2);
  }
  return 0;
}
///////////////////////////////////////////

同时还要在这个文件的最后面新增:

epicsRegisterFunction(myEventSub); #新增subroutine函数时需要添加这一句

同时还要在另外的一个文件中即新增subroutine函数时还要在dbSubExample.dbd文件中添加:
function(myEventSub)

都修改完毕后记得在src文件夹下make。

运行结果

在这里插入图片描述

执行camonitor 来检测 calcExample 和 myai2的变化,可以看到当大于5的时候myai2才会被触发,然后接收来自calcExample 的数值
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章