Running SNL Programs¶
This chapter is about how to run and customize a program, once it has been compiled. It also explains how to get information about a running program instance and how to stop a program.
Our running example is the “demo” program which you find under the path
examples/demo
in the source tree.
Command Syntax¶
The commands discussed in this chapter can be invoked in different ways. One way is to call them directly from C code. Prototypes for the corresponding C functions can be found in the header file “seqCom.h” which a successful build installs into the “include” directory.
More typical, however, is to call them from some kind of command shell, such as the EPICS IOC shell, or the VxWorks C shell, or the RTEMS cexp shell. In each case the syntax is slightly different, but this is not the place to discuss all these (sometimes subtle) differences. Thus, for simplicity, I will mostly use the IOC shell syntax, indicated by a leading “epics> ” shell prompt (so this does not belong to the command itself).
Details about the commands are listed in the Shell Command Reference at the end of this chapter.
Starting a Program¶
To start an SNL program, the seq
function is called with three
parameters:
The address of the
seqProgram
structure. This is a value that is generated by the SNL compiler; it has the same name as the identifier after theprogram
keyword.Optionally a string containing parameter definitions, see next section.
Optionally a stack size. If
0
(zero), a reasonable default for the target platform is used (epicsThreadStackSmall
).
For instance, the following command starts the demo program with no parameters and teh default stack size:
epics> seq demo
Note that the IOC shell defaults missing arguments to zero. Also note that the program gets passed as a string when using the IOC shell, whereas in C you would have to call it like:
seq(&demo,0,0);
If parameters are to be specified (see next section), this would instead look like
epics> seq demo "debug=0,prefix=demo"
The sequencer responds with the following output:
Sequencer release 2.1.14, compiled Wed Sep 25 12:18:24 2013
Spawning sequencer program "demo", thread 0x98fe120: "demo"
The most useful information here is the (EPICS) thread ID 0x98fe120
,
since this can be used later on to identify the running program.
BTW, all shell commands write their output to stdout
.
Program Parameters¶
Parameters are a way to customize an SNL program. A program parameter has a name (a string) and a value (also a string). The parameter name should be a valid SNL identifier, while the value can be anything.
Parameters are specified (or defined) in two places: when invoking a
program for execution, using the seq
procedure, or from inside
a program after the initial program
clause. Parameters specified
on invocation override those specified in the program. In both cases, the
syntax of the actual specification is, roughly:
"name1=value1,name2=value2,..."
Note that the whole specification is embedded in a single string. A single definition consists of the parameter name, followed by an equal sign, followed by the value. Multiple parameter definitions are separated by comma.
The value is not allowed to contain a comma, or spaces; leading or trailing spaces around the value are ignored. Normal C/SNL string character escaping is admissable, e.g. to embed double quotes or line breaks, but cannot be used to circumvent these limitations.
Special Parameters¶
The following built-in parameters have special meaning to the sequencer.
debug = <level>
This is currently only used by the PV subsystem. A level of 1 or greater turns on debug messages.
name = <thread_name>
Normally the thread names are derived from the program name. This parameter specifies an alternative base name for the state set threads.
priority = <task_priority>
This parameter specifies initial thread priorities. The value should be an integer between 0 (lowest) and 99 (highest) and will be passed epicsThreadCreate when teh state set threads are created.
stack = <stack_size>
This parameter specifies the stack size in bytes. The default is
whatever epicsThreadGetStackSize(epicsThreadStackSmall)
returns.
Using Parameters¶
Parameter values are available inside the program via the built-in
procedure macValueGet
. They are also (automatically)
available for parameter expansion when specifying PV names in
assign
clauses.
Examining a Program¶
You can get information about your program at runtime by calling one of several shell commands. They all take a thread ID as first argument to uniquely identify the a running program instance. If this argument is zero (i.e. omitted in the IOC shell), they default to displaying a table that lists the thread IDs of all state sets of all running program instances.
Here is what you might get for the demo program:
epics> seqShow
Program Name Thread ID Thread Name SS Name
------------ --------- ----------- -------
demo 0x88c1da8 demo light
0xb6a1e160 demo_1 ramp
0xb6a1e2b8 demo_2 limit
When the seqShow
command is called with one of the thread IDs
listed in the table it will give you more detailed information about the
running program.
You can get detailed information about the process variables associated
with a program by calling seqChanShow
with a valid thread ID
as the first argument. Similarly, seqChanShow
displays
information about monitor queues. Here are some example invocations:
epics> seqChanShow 0x88c1da8 demo:lightOn
epics> seqChanShow 0x88c1da8 -
epics> seqChanShow 0x88c1da8 +
epics> seqQueueShow 0x88c1da8
The optional second parameter to seqChanShow or seqQueueShow is
a channel name, or -
to show only those channels which
are disconnected, or +
to show only those channels which are
connected. Both will prompt for input after showing the first
(or the specified) channel: hit Enter or a signed number to view
more channels or queues; enter q
to quit.
Stopping a Program¶
In order to cleanly shut down a running program, use the seqStop
command:
epics> seqStop 0x88c1da8
A program can also terminate itself, see transitions
.
Shell Command Reference¶
These are commands to be issued from the IOC shell or VxWorks shell. They can also be called from C (and therefore SNL) code.
Some of these routines behave slightly different depending on whether
run under iocsh or a VxWorks shell. This mostly concerns the
threadID
argument: under iocsh, this can in fact be a thread
name instead of a thread ID. Note, however, that this is
unreliable if you have more than one instance of the same program
running, since the thread names are identical for all instances. The
VxWorks shell version directly takes an epicsThreadID argument and
thus does not recognize thread names.
-
void seq(seqProgram *program, const char *paramdefs, unsigned stacksize)¶
Start the given program with the given set of parameter definitions and
stack size. If `stacksize
is zero or is omitted, then use a default
(EPICS “small” stack). If paramdefs
is zero or the last two arguments
are omitted, then no parameters are defined. Otherwise paramdefs
should
be a string that specifies program parameters as detailed in Program Parameters. See also program_param
.
-
void seqShow()¶
-
void seqShow(epicsThreadId threadID)
The first form shows a table of all programs, program instances, and state sets, e.g.
epics> seqShow
Program Name Thread ID Thread Name SS Name
------------ --------- ----------- -------
demo 0x807e628 demo light
0x809fbc8 demo_1 ramp
0x809fcd8 demo_2 limit
------------ --------- ----------- -------
demo 0x807fd98 demo light
0xb7100470 demo_1 ramp
0xb7100580 demo_2 limit
------------ --------- ----------- -------
demo 0x80814e0 demo light
0x809fe68 demo_1 ramp
0x809ff78 demo_2 limit
Note that in this example we have three running instances of a single program named ‘demo’, each of which consists of three state sets running in its own thread.
The second form displays the internal state of a running program instance. The threadID parameter must be one of the program’s state set thread IDs as listed in the above table.
For instance, for the above example we might get
epics> seqShow 0x807e628
State Program: "demo"
thread priority = 50
number of state sets = 3
number of syncQ queues = 0
number of channels = 6
number of channels assigned = 6
number of channels connected = 6
number of channels monitored = 5
options: async=0, debug=0, newef=1, reent=1, conn=1, main=0
user variables: address = 0x807d158, length = 44
State Set: "light"
thread name = demo; Thread id = 0x807e628
First state = "START"
Current state = "LIGHT_OFF"
Previous state = "START"
Elapsed time since state was entered = 3.0 seconds
Get in progress = [000000]
Put in progress = [000000]
Queued time delays:
State Set: "ramp"
thread name = demo_1; Thread id = 0x809fbc8
First state = "START"
Current state = "RAMP_UP"
Previous state = "RAMP_UP"
Elapsed time since state was entered = 0.1 seconds
Get in progress = [000000]
Put in progress = [000000]
Queued time delays:
delay[0]=0.100000
State Set: "limit"
thread name = demo_2; Thread id = 0x809fcd8
First state = "START"
Current state = "START"
Previous state = ""
Elapsed time since state was entered = 3.0 seconds
Get in progress = [000000]
Put in progress = [000000]
Queued time delays:
-
void seqChanShow(epicsThreadId threadID)¶
-
void seqChanShow(epicsThreadId threadID, const char*)
Display channel information for the program instance specified by the given threadID. If a second argument is given, it is interpreted as part of a channel name. Only channels whose name contains the given string as substring are displayed. The name can be preceded by a single “-” or “+” sign, signifying that only disconnected (“-”) or connected (“+”) channels should be displayed.
The procedure displays one channel at a time, starting with the first matching one, and then asks the user for input. This input can be
- a (signed) integer:
increase / decrease current channel number by the given amount, then display the current channel
- minus sign (“-“):
same as “-1”
- plus sign (“+”), empty string (return):
same as “+1”
- anything else:
quit, i.e. back to the shell
If user interaction causes the channel number to leave the range (i.e. less than zero, greater or equal to number of channels), the command quits, too.
-
void seqQueueShow(epicsThreadId threadID)¶
Display information about queued channels. For example
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 = 2
Queue #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)
The command is interactive and accepts the same inputs as
seqChanShow
.
-
void seqcar(int level)¶
The name stands for “sequencer channel access report”. It displays channel connection information. If level <= 1, or no level argument is given, only a summary line is displayed, for example
Total programs=3, channels=18, connected=18, disconnected=0
For level > 1, connection information is displayed for all channels of all running programs. For instance
epics> seqcar 2
Program "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)¶
Initiate a clean program exit. Running state transitions
are
completed, then all state set threads exit, all channels are
disconnected, and finally allocated resources are freed.