EPICS
本文是有关在已经编译一个程序后如何运行以及自定义这个程序。它也解释了如何获取有关一个正在运行的程序实例的信息以及如何终止一个程序。
我们正在运行的示例是这个"demo"程序,你在源中路径example/demo下找到它。
examples/demo:
demo.adl demoInclude.dbd demo.st Makefile O.linux-x86_64
demo.db demoMain.c demo.stcmd O.Common runme.sh
命令语法
可以用不同方法调用在本文中讨论的命令。一种方式是直接从C代码调用它们。可以在头文件"seqCom.h"中找到相应C函数的原型,成功构建安装这个头文件到"include"目录。
但更一般是从某类命令shell调用它们,诸如EPICS IOC shell或者vxWorks C shell或者RTEMS cexp shell。在这样的情况中,语法稍微不同,但这不是讨论这些(有时细微)不同的地方。因而,为了简单,我将基本使用IOC shell语法,由一个前导的"epics> "shell提示表示(因而这不属于这个命令本身)。
在本文末尾的Shell Command Reference中列出了有关命令的细节。
启动一个程序
要启动一个SNL程序,用三个参数调用seq函数:
1) seqProgram结构体的地址。这是一个由SNL编译器产生的值;它与在program关键字后的标识符有相同名称。
2) 可选地一个包含参数定义的字符串,见下面部分。
3) 可选地一个栈大小。如果0(零),使用对应目标平台的一个合理默认值(epicsThreadStackSmall)。
例如,以下命令不带参数并且使用默认栈大小启动这个demo程序:
epics> seq demo
注意:IOC shell默认缺失的参数为0。也注意:当使用IOC shell时,程序以一个字符串被传递,而在C中,你必须像以下调用它:
seq(&demo,0,0);
如果要指定参数,这看起来像:
epics> seq demo "debug=0,prefix=demo"
这个sequencer用以下输出做响应:
Sequencer release 2.1.14, compiled Wed Sep 25 12:18:24 2013
Spawning sequencer program "demo", thread 0x98fe120: "demo"
在这里最有用的信息是(EPICS)线程ID0x98f2120,由于这可以在之后用于识别这个正在运行的程序。所有shell命令写它们的输出到stdout。
程序参数
参数是一种自定义一个SNL程序的方式。一个程序参数有一个名称(一个string)和一个值(也一个string)。参数名应该是一个有效的SNL标识符,而值可以是任何东西。
在两个位置指定(或定义)参数:当为执行调用一个程序时,使用seq过程或者在初始的program语句后一个程序内。在调用时指定的参数重写在这个程序中指定的那些参数。在两种情况中,实际格式的语法基本是:
"name1=value1,name2=value2,..."
注意:整个格式被嵌入在单个字符串中。单个定义由这个参数名称后个一个等号后跟它的值组成。多个参数定义是由逗号分隔。
不允许值包含一个逗号或者空白;值两边前导或者末尾的空白被忽略。正常的C/SNL串字符转义是可接受的,例如,嵌入双引号或者换行符,但不能用于回避这些限制。
特殊参数
以下内建参数对于这个sequencer有特殊含义:
debug = <level>
这当前只被PV子系统使用。级别1及以上开启调试信息。
name = <thread_name>
通常,线程名称是派生于这个程序名。此参数为这个状态集线程指定另一个基本名称。
priority = <task_priority>
这个参数指定初始线程优先级。这个值应该是一个介于0(最小)和99(最大)之间的整数,并且在这个状态集线程被创建时,将被传递epicsThreadCreate。
stack = <stack_size>
这个参数用字节指定栈尺寸。默认是epicsThreadGetStackSize(epicsThreadStackSmall)返回的任何东西。
使用参数
参数值在程序内通过内建过程macValueGet是可获取的。当在assign语句中指定PV名称时,它们也(自动)可用于参数展开。
检查一个程序
在运行时,你通过调用若干shell命令之一能够获取有关你程序的信息。它们都接受一个线程ID作为第一个参数来唯一地识别一个正在运行地程序实例。如果这个参数是0(即是:在IOC shell中被忽略),它们默认显示一个表格,它列出了所有正在运行的程序实例的所有状态集的线程IDs。
这是你可能对demo程序所获取的:
epics> seqShow
Program Name Thread ID Thread Name SS Name
------------ --------- ----------- -------
demo 0x88c1da8 demo light0xb6a1e160 demo_1 ramp0xb6a1e2b8 demo_2 limit
当用在这个表格中列出的线程IDs之一调用seqShow命令,它将给出有关这个运行程序的更加详尽的信息。
你可以通过用一个有效线程ID作为第一个参数调用seqChanShow获取与一个程序相关联的过程变量的更加详尽的信息。类似地,seqChanShow显示了有关monitor队列地信息。这是一些示例调用:
epics> seqChanShow 0x88c1da8 demo:lightOn
epics> seqChanShow 0x88c1da8 -
epics> seqChanShow 0x88c1da8 +
epics> seqQueueShow 0x88c1da8
传给seqChanShow或seqQueueShow的可选的第二个参数是一个通道名称,或-只显示被断开的那些通道,或+只显示那些被连接上的通道。这两个命令在显示第一个(或指定的)通道后都将提示输入:按回车或者一个有符号数值来查看更多通道或队列;按q退出。
停止一个程序
为了明确地关闭一个运行的程序,使用seqStop命令:
epics> seqStop 0x88c1da8
一个程序也可以终止它自己,见transistions。
Shell命令参考
这些是从IOC shell或者vxWorks shell被发送的命令。也能从C(或SNL)代码调用它们。
取决于在iocsh下运行还是在vxWorks shell下运行,这些例程中的一些行为略微不同。这最关注threadID参数:在iocsh下,这实际上可以是一个线程名称替代一个线程ID。注意,但如果你有相同程序的多个实例在运行,由于对于所有实例,线程名称是相同的,这是不可靠的。VxWorks shell版本直接接收一个epicsThreadID参数并且因而不识别线程名称。
void seq(seqProgram *program, const char *paramdefs, unsigned stacksize)
由指定的参数定义和栈大小设置启动指定程序。如果stacksize是0,或者被忽略,则使用一个默认值(EPICS "small"栈)。如果paramdefs是0,或者后两个参数被忽略,则不定义参数。否则paramdefs应该是一个字符串,它指定了在Program Parameters中详细的程序参数。
void seqShow()
void seqShow(epicsThreadId threadID)
第一种形式显示一个所有程序,程序实例和状态集,例如:
epics> seqShow
Program Name Thread ID Thread Name SS Name
------------ --------- ----------- -------
demo 0x807e628 demo light0x809fbc8 demo_1 ramp0x809fcd8 demo_2 limit
------------ --------- ----------- -------
demo 0x807fd98 demo light0xb7100470 demo_1 ramp0xb7100580 demo_2 limit
------------ --------- ----------- -------
demo 0x80814e0 demo light0x809fe68 demo_1 ramp0x809ff78 demo_2 limit
注意:在这个示例中,我们有名为"demo"的单个程序的三个运行实例,每个实例由在其自己线程中运行的三个状态集组成。
第二种形式显示一个运行的程序实例的内部状态。threadID参数必须是在以上表格中列出的程序状态机线程之一。例如,对于以上示例,我们得到:
epics> seqShow 0x807e628
State Program: "demo"thread priority = 50number of state sets = 3number of syncQ queues = 0number of channels = 6number of channels assigned = 6number of channels connected = 6number of channels monitored = 5options: async=0, debug=0, newef=1, reent=1, conn=1, main=0user variables: address = 0x807d158, length = 44State Set: "light"thread name = demo; Thread id = 0x807e628First state = "START"Current state = "LIGHT_OFF"Previous state = "START"Elapsed time since state was entered = 3.0 secondsGet in progress = [000000]Put in progress = [000000]Queued time delays:State Set: "ramp"thread name = demo_1; Thread id = 0x809fbc8First state = "START"Current state = "RAMP_UP"Previous state = "RAMP_UP"Elapsed time since state was entered = 0.1 secondsGet in progress = [000000]Put in progress = [000000]Queued time delays:delay[0]=0.100000State Set: "limit"thread name = demo_2; Thread id = 0x809fcd8First state = "START"Current state = "START"Previous state = ""Elapsed time since state was entered = 3.0 secondsGet in progress = [000000]Put in progress = [000000]Queued time delays:
void seqChanShow(epicsThreadId threadID)
void seqChanShow(epicsThreadId threadID, const char *)
显示由指定threadID指定的程序实例的通道信息。如果给出了第二个参数,它被解析成一个通道名部分。仅显示其名称包含指定字符串作为子串的通道。可以在名称前带一个"-"或"+"号,指定仅显示断开的("-")或连接的"+"的通道。
这个过程一次显示一个通道,从第一个匹配的通道开始,并且接着请求用户输入。此输入可以是:
1) 一个(有符号)整数:增加/减少当前通道编号指定量,接着显示当前通道
2) 负号("-"):与"-1"相同。
3) 正号("+"),空串(回车):与"+1"相同。
4) 任何其它:退出,即:返回这个shell
如果用户交互使得通道编号超出范围(即是:小于0,或者大于或等于通道数目),命令退出。
void seqQueueShow(epicsThreadId threadID)
显示有关排队通道的信息。例如:
epics> seqShow
Program Name Thread ID Thread Name SS Name
------------ --------- ----------- -------
syncqTest 0x8053e60 syncqTest get(nil) (no thread) get1(nil) (no thread) put(nil) (no thread) flush
epics> seqQueueShow 0x8053e60
State Program: "syncqTest"
Number of queues = 2Queue #0: numElems=5, used=0, elemSize=136
Next? (+/- skip count, q=quit)Queue #1: numElems=5, used=0, elemSize=56
Next? (+/- skip count, q=quit)
此命令是交互的并且接受与seqChanShow相同的输入。
void seqcar(int level)
名称代表"sequencer channel access report"。它显示了通道访问信息。如果level<=1,或者没有给出参数,只显示一概述行,例如:
Total programs=3, channels=18, connected=18, disconnected=0
对于level>1,为所有运行程序的所有通道显示连接信息。
epics> seqcar 2Program "demo"Variable "light" connected to PV "demo1:light"Variable "lightOn" connected to PV "demo1:lightOn"Variable "lightOff" connected to PV "demo1:lightOff"Variable "voltage" connected to PV "demo1:voltage"Variable "loLimit" connected to PV "demo1:loLimit"Variable "hiLimit" connected to PV "demo1:hiLimit"Program "demo"Variable "light" connected to PV "demo2:light"Variable "lightOn" connected to PV "demo2:lightOn"Variable "lightOff" connected to PV "demo2:lightOff"Variable "voltage" connected to PV "demo2:voltage"Variable "loLimit" connected to PV "demo2:loLimit"Variable "hiLimit" connected to PV "demo2:hiLimit"Program "demo"Variable "light" connected to PV "demo3:light"Variable "lightOn" connected to PV "demo3:lightOn"Variable "lightOff" connected to PV "demo3:lightOff"Variable "voltage" connected to PV "demo3:voltage"Variable "loLimit" connected to PV "demo3:loLimit"Variable "hiLimit" connected to PV "demo3:hiLimit"
Total programs=3, channels=18, connected=18, disconnected=0
void seqStop(epicsThreadId threadID)
启动一个干净的程序退出。运行的状态转变被结束,接着所有状态集线程退出,所有通道被断开,并且最终分配的资源被释放。