(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 的數值
在這裏插入圖片描述

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