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 can also be found in
section :ref:`Shell Commands` of the SNL language reference.

Starting a Program
------------------

To start an SNL program, the :c:func:`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 the :token:`program` 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``.


.. _run time parameters:

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 :c:func:`seq` procedure, or from inside
a program after the initial :token:`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 :c:func:`macValueGet`. They are also (automatically)
available for parameter expansion when specifying PV names in
:token:`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 :c:func:`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 :c:func:`seqChanShow` with a valid thread ID
as the first argument. Similarly, :c:func:`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 the State Program Tasks:

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 :ref:`Transitions`.
