Sequencer: Difference between revisions

From MidasWiki
Jump to navigation Jump to search
No edit summary
 
(85 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Pagelinks}}


A new sequencer for starting and stopping runs was implemented in Jun 2011. Since then development has continued, with more commands being added, and the option of using a Midas Script Language (MSL) for commands, in addition to the XML language.
= Links =
<div style="column-count:3;-moz-column-count:3;-webkit-column-count:3">
* [[/Sequencer ODB tree]]
* [[Sequencer Page]]
* [[mhttpd]]
</div>


The sequencer runs inside mhttpd, and creates a new ODB subdirectory [[/Sequencer ODB Tree|Sequencer Tree]]. Pressing the Sequencer button (if shown) on the mhttpd main status page will display the Sequencer page. The sequencer runs scripts in XML or MSL (Midas Script Language) format, which reside on the server (where mhttpd is running).
= Introduction =
A Sequencer for starting and stopping runs is part of the MIDAS distribution. It uses a simple Midas Script Language (MSL) for commands.


The sequencer is stateless, meaning that even if mhttpd is stopped and restarted, it resumes operation from where it has been stopped.
The sequencer runs as a separate process and must be started before running a sequence via the command '''msequencer'''. The first time  the  {{Button|name=Sequencer}} button on the [[Status Page]] is pressed, the ODB [[/Sequencer ODB tree|Sequencer Tree]] is created. If the Sequencer button is not present on the [[Status Page]], it may have been [[Status Page#page-switch-buttons|suppressed]].


== [[Sequencer Commands|Sequencer Commands]] ==
The sequencer runs scripts in MSL (Midas Script Language) format, which reside on the server (where {{Utility|name=mhttpd}} is running). The sequencer state is completely stored in the ODB, meaning that even if  {{Utility|name=mhttpd}} or the sequencer is stopped and restarted, the active sequence operation continues exactly where it has been stopped.
The following commands are implemented in the MIDAS sequencer. The upper syntax is for the XML file, the lower for the MSL (Midas Script Language).
 
Refer to the [[/Sequencer ODB tree]] for more details on its organization.
 
For instructions on '''getting started with the sequencer''', see [[Sequencer Page]]
 
= Controlling the sequencer from custom pages =
 
The normal interface is the "Sequencer" status page in MIDAS. In addition, the sequencer can be controlled by other means. The ODB contains a directory '''/Sequencer/Command''', which contains the currently loaded filename and three switches. To load new file and compile it, set the '''Load filename''' and the '''Load new file''' to '''yes'''.
 
  modbset(['/Sequencer/Command/Load filename',
          '/Sequencer/Command/Load new file',
          ['test.msl', 'Yes'])
 
After a script has been loaded, all '''PARAM''' values are extracted and placed under '''/Sequencer/Param/Defaults'''. Before a script is actually started, the default values may be modified and must be placed under '''/Sequencer/Param/Value''' before the sequencer is started. To start the script, set '''Start script''' to '''yes'''. This can be done in a combined way on a custom page via
 
  modbset(['/Sequencer/Param/Value/First parameter',
          '/Sequencer/Param/Value/Other parameter',
          '/Sequencer/Command/Start script'],
          ['123', '456', 'Yes'])
 
The parameter names of course have to be adjusted to the current script.
 
The starting of the script via above '''modbset''' can be put in the '''onclick=...''' method of a button, or even into a side menu via an alias by putting an ODB key into '''/Alias/xxx''' and setting it to '''javascript:modbset(...)'''.
 
= Sequencer Commands =
The following commands are implemented in the MIDAS Sequencer. The left syntax is for the XML file, the right for the MSL (Midas Script Language).


Variable names are indicated in italic, options are enclosed in [brackets].
Variable names are indicated in italic, options are enclosed in [brackets].


{| class="wikitable" style="text-align: left; color: black; style="background-color: #ccffff; color: black;"
{| class="wikitable" style="text-align: left; color: black; tr:nth-child(even) {background-color: #F0F0F0};"  
|style="width: 30%;" |< !DOCTYPE RunSequence[< !ENTITY name SYSTEM "name.xml" >]> &name;
!style="width: 20%;background-color:#C0C0C0;"|MSL format
|style="width: 20%;"|INCLUDE name
!style="width: 60%;background-color:#C0C0C0;"|Description
|style="width: 60%;' | Include another XML file
|-
|- style="background-color: #ffffcc; color: black;"
||INCLUDE ''name''
|style="width: 30%; | <Call name="<i>name</i>"> a,b,c...</Call>
||Include another MSL file ''name''.msl
|style="width: 20%;" |CALL name, a, b, c, ...
|-
|style="width: 60%;" |Call a subroutine. Optional parameters a,b,c... are passed to the subroutine, where they can be referenced via $1, $2, $3, etc. The subroutine can either reside in the current file, or in a library file which is included.
||BREAK
|-style="background-color: #ccffff; color: black;"
||Break (finish prematurely) a loop. This is usually used together with an IF statement to abort a loop like
|style="width: 30%;" |<Cat name="<i>name</i>"> a,b,c... </Set>
<pre>
|style="width: 20%;"|CAT name, a, b, c, ...
LOOP 10
|concatenates the strings a,b,c,... into a single variable name . Can be referenced with $name. If a string must contain a comma, it can be enclosed in quotes such as in <Cat name="title">Run $run, ",", $n events</Cat> <ODBSet path="/Experiment/Run parameters/Title">$title</ODBSet>
  IF ($x > 0)
|- style="background-color: #ffffcc; color: black;"
    BREAK
|style="width: 30%;" |<Comment> comment </Comment>
  ENDIF
|style="width: 20%;"|COMMENT comment
ENDLOOP
|a comment for this XML file, for information only. This comment is shown when one clicks on the XML file in the browser inside the web page and can be used to show some information about an XML file. This can be helpful if one has many XML files and the file name only is not enough to supply enough information.
</pre>
|-
||CALL ''name'', ''a'', ''b'', ''c'', ...
||Call a subroutine. Optional parameters ''a'',''b'',''c''... are passed to the subroutine, where they can be referenced via $1, $2, $3, etc. The subroutine can either reside in the current file, or in a library file which is included.
|-
||CAT ''name'', ''a'', ''b'', ''c'', ...
||Concatenates the strings ''a'',''b'',''c'',... into a single variable name. Can be referenced with $''name''. If a string must contain a comma, it can be enclosed in quotes such as in '''CAT title, $run, ", ", $n_events'''
|-
||COMMENT ''comment''
||A comment for this XML file, for information only. This comment is shown in the title bar next to the file name if one runs a script. This can be helpful if one has many XML files and the file name only is not enough to supply enough information.
|-
|-
|style="width: 30%;" |<Goto line="n" / >
||EXIT
|style="width: 10%;"|GOTO n
||Exit script immediately
|Jump to line n in scrip
|-
|- style="background-color: #ffffcc; color: black;"
||GOTO ''n''
|style="width: 30%;" |<If condition="con" >...</if>
||Jump to line ''n'' in script
|IF con ... ENDIF
|-
|Statements between <if> and </if> are only executed if condition con is true. The condition can use variables via $name and/or constants together with operators "<", "<=", ">", ">=", "==", "!=", "&" (bitwise AND).
||IF ''con''  <br>or<br>IF (''con'')<br>
... <br>
ELSE <br>
... <br>
ENDIF
||Statements between "IF" and "ENDIF" are only executed if condition "con" is true, otherwise the statements between the optional "ELSE" and "ENDIF" are executed. The condition can use any math expression using variables via $name together with operators "<", "<=", ">", ">=", "==", "!=", "&" (bitwise AND). Up to four nested IF statements are possible. An example would be "IF ($x+3 > $y*4+$z^2)".
|-  
|-  
|style="width: 30%;" | <Library name="name" >...</Library>
||LIBRARY ''name''
|style="width: 10%;"|LIBRARY name
||Indicates that the current file is a library (which can be included by other files). A library usually consists of a set of subroutines.
|Indicates that the current file is a library (which can be included by other files). A library usually consists of a set of subroutines.
 
|-style="background-color: #ffffcc; color: black;"
|-
|style="width: 30%;" |<Loop [n="n"] [var="name" values="a,b,c,..."]> ... </Loop>
||LOOP [''name'' ,] ''n'' ... ENDLOOP
|style="width: 10%;"|LOOP n | a, b, c, ... ... ENDLOOP
||To execute a loop ''n'' times. For infinite loops, "infinite" can be specified as ''n''. Optionally, the loop variable running from 1...''n'' can be accessed inside the loop via $''name''.
|to execute a loop n times. For infinite loops, "infinite" can be specified as n. Alternatively, a list of values can be specified. In this case, the loop is executed once for each value, which is stored into the variable name so it can be accessed inside the loop via $name.
 
|-
||LOOP ''name'',  ''a'', ''b'', ''c'', ... ... ENDLOOP
||Loop though a list of values. The loop is executed once for each value, which is stored into the variable ''name'' so it can be accessed inside the loop via $''name''.
 
|-
||MESSAGE ''message'' [,1]
||Opens a message box in the browser containing the text message. If wait="1", then the sequencer waits until the box is closed by the user before continuing.
|-
||MSG ''message'' [,<type>]
||Produces a midas message going into the message buffer. The optional <type> can be any of ERROR, INFO, DEBUG, LOG, TALK. If no type is given, INFO is used.
|-
||ODBCREATE ''path'', ''type'' [, ''size'']
||Create an ODB key of type ''type'' and optional size ''size'' (for arrays). ''type'' can be ''UNIT8'', ''INT8'', ''UNIT16'', ''INT16'', ''UNIT32'', ''INT32'', ''BOOL'', ''FLOAT'', ''DOUBLE'', ''STRING''
|-
||ODBDELETE ''path''
||Delete an ODB key. If ''path'' points to a ODB subdirectory, delete the whole subdirectory.
|-
||ODBGET ''path'', ''name''
||To get a value from a variable ''name''. The variable can then be referenced with $''name''. If the ODB value is an array, the index can be specified like via a constant or expression:<br>
<pre>
ODBGET "/Path/key[15]", v
ODBGET "/Path/key[$i + 15]", v
</pre>
|-
||ODBINC ''path'' [, ''delta'']
||To increment a value in the ODB. ''delta'' can be positive or negative. If no "delta" is given, 1 is used.
|-
||ODBLOOKUP ''path'', ''string'', ''name''
||Lookup a ''string'' in a string array in the ODB given by ''path'' and return its index in ''name''. If we have an array
<pre>
/Examples/Names
  [0] Hello
  [1] Test
  [2] Other
</pre>
and do a
<pre>
ODBLOOKUP "/Examples/Names", "Test", index
</pre>
we get a index equal ''1''. If a value is not found, the resulting index is set to "not found" which can be tested.
If the ODB key does not exist, the sequencer aborts.
|-
||ODBSET ''path'', ''value'' [, 0|1]
||To set a value in the ODB. ''value'' can be any math expression containing variables (preceded by a '$'). ''path'' can also contain variables (preceded by a '$'), but no math expressions.<br>
If the ODB key referenced by ''path'' is an array, the index can be specified such as<br>
<pre>
ODBSET "/Path/value[3]", 1    # individual value
ODBSET "/Path/value[3-5]", 2  # index range 3,4,5
ODBSET "/Path/value[*]", 0    # all values of array
</pre>
The path value can match multiple keys using the '?' and '*' wildcard (one or any number of characters respectively). This is useful to set the same sub-path on multiple folders:<br>
<pre>
ODBSET "/Path/to/somewhere/folder0/value", "1"
ODBSET "/Path/to/somewhere/folder1/value", "1"
ODBSET "/Path/to/somewhere/folder2/value", "1"
</pre>
can be shortened as:<br>
<pre>
ODBSET "/Path/to/somewhere/folder*/value", "1"
</pre>
The notify flag specifies if possible hot-links to this ODB value are notified. This can be useful if a front-end program has many parameters, which must be set for a specific run. The front-end usually has a hot-link to its parameters, so on each modification a callback function in the front-end is called which usually modifies some hardware. If there are many ODBSet statements for all parameters, the callback would be executed on each ODBSet, so the hardware would be reconfigured many times slowing down the startup of a run. In order to prevent this, notify="0" can be specified for all ODBSet statements except the last one which contains notify="1", so the callback function is called only once at the end.
|-
||ODBLOAD ''file'' [, ''path'']
||Load an external file into the ODB.<br>
JSON, XML and ODB file format are supported with the value inferred by the content of the file.
The optional path marks the position where to load the given file into the ODB, if no position is given the file is loaded from ODB root.<br>
For the input file several options are supported: if the filename starts with "/" is is assumed to be an absolute path, if it starts with a "$" the path starts from the Sequencer root folder stored in the ODB at /Sequencer/Path. In all other cases it is intended as a relative path to the local MSL file.
|-
||ODBSAVE ''path'', ''file''
||Save part of the ODB to an external file.<br>
The file extension is used to determine the format. Possible values are ".json", ".xml" and ".odb".
The path can point to an individual value in the ODB or to a whole subtree.<br>
For the output file several options are supported: if the filename starts with "/" is is assumed to be an absolute path, if it starts with a "%" the path starts from the Sequencer root folder stored in the ODB at /Sequencer/Path. In all other cases it is intended as a relative path to the local MSL file. If the file name contains a variable (starting with '$') it gets evaluated before saving.
|-
||ODBSUBDIR ''path'' ...ENDODBSUBDIR
||If one wants to se several ODB values in the same directory, the ODBSet commands can be rather long if the path is long. Using this command, the subdir can be specified for all commands between the opening and ending tags. So instead of writing <br>
<pre>
ODBSET /Very/long/path/into/the/odb/value1, 1
ODBSET /Very/long/path/into/the/odb/value2, 1
ODBSET /Very/long/path/into/the/odb/value3, 1
ODBSET /Very/long/path/into/the/odb/value4, 1
</pre>
one can write <br>
<pre>
ODBSUBDIR /Very/long/path/into/the/odb
ODBSET value1, 1
ODBSET value2, 1
ODBSET value3, 1
ODBSET value4, 1
ENDODBSUBDIR
</pre>
|-
||PARAM ''name'', ''comment'', [''default''], [''a'',''b'',''c'' | bool]
||When starting a script, a start page is shown where one can enter additional parameters for the script. Parameters can be defined either centrally for all scripts in the ODB under /Experiment/Edit on sequence. This subdirectory in the ODB can contain links to ODB values, which are queried at the start page. In addition, each script can define additional parameters appended to this list. They will be stored under /Sequencer/Variables and can be referenced inside the script via $name, where name can be any variable name specified in the parameter statement. The optional "comment" is shown on the start page below the parameter name. An optional "default" value can be specified for each parameter. If the "default" value starts with a "/" it is interpreted as an ODB path and the default value is fetched from the ODB such as "/Logger/Write data".
If only certain options are possible for the parameter, they can be defined via the options list. The web page will then contain a drop-down list showing the options. In case of type="bool", a checkbox will be shown.
|-
|-
|style="width: 30%;" |<Message [wait="1"]>message </Message>
||RUNDESCRIPTION ''description''
|style="width: 10%;"|MESSAGE message [,1]
||a run description which is stored under /Experiment/Run Parameters/Run Description .
|Opens a message box in the browser containing the text message. If wait="1", then the sequencer waits until the box is closed by the user before continuing.
|-style="background-color: #ffffcc; color: black;"
|style="width: 30%;" |<ODBInc path="path" > delta </ODBInc>
|style="width: 10%;"|ODBINC path, delta
|to increment a value in the ODB.
|-
|-
|style="width: 30%;" |<ODBSet [notify="0|1"] path="path" > value </ODBSet>
||SCRIPT ''script'' [, a, b, c, ...]
|style="width: 10%;"|ODBSET path, value [, 0|1]
||To call a script on the server side. Optionally, pass parameters to the script. Any ASCII result from the script is stored as a string in the MSL variable $SCRIPT_RESULT. The ''script'' can be a direct command to be executed on the shell level, or can be a shell script which then gets executed, or can be an executable. If one has to pass several variables back to the MSL script, one can use the trick to store them into an ODB file (ASCII, XML or JSON format) and then use the <code>ODBLOAD</code> command to put the values into the ODB. Try the <code>ODBSAVE</code> command to see how the ODB format should look like.<p>
|to set a value in the ODB. The notify flag specifies if possible hot-links to this ODB value are notified. This can be useful if a front-end program has many parameters, which must be set for a specific run. The front-end usually has a hot-link to its parameters, so on each modification a callback function in the front-end is called which usually modifies some hardware. If there are many ODBSet statements for all parameters, the callback would be executed on each ODBSet, so the hardware would be reconfigured many times slowing down the startup of a run. In order to prevent this, notify="0" can be specified for all ODBSet statements except the last one which contains notify="1", so the callback function is called only once at the end.
The PATH environment is inherited from the place when the <code>msequencer</code> program is started. It can be checked with a simple shell script <code>echo $PATH</code> and then displaying the result with the MSL script command <code>message $SCRIPT_RESULT, 1<code>.
|-style="background-color: #ffffcc; color: black;"
|style="width: 30%;" |<ODBSubdir [notify="0/1"] path="path" >...</ODBSubdir>
|style="width: 10%;"|ODBSUBDIR path [,1] ...ENDODBSUBDIR
|If one wants to se several ODB values in the same directory, the ODBSet commands can be rather long if thepath is long. Using this command, the subdir can be specified for all commands between the opening and ending tags. So instead of writing
<ODBSet path="/Very/long/path/into/the/odb/value1">1</ODBSet>  
<ODBSet path="/Very/long/path/into/the/odb/value2">1</ODBSet>  
<ODBSet path="/Very/long/path/into/the/odb/value3">1</ODBSet>  
<ODBSet path="/Very/long/path/into/the/odb/value4">1</ODBSet>
one can write
<ODBSubdir path="/Very/long/path/into/the/odb">
<ODBSet path="value1">1</ODBSet>  
<ODBSet path="value2">1</ODBSet>  
<ODBSet path="value3">1</ODBSet>
<ODBSet path="value4">1</ODBSet>
</ODBSubdir>
|-
|-
|style="width: 30%;" |<Param name="name" [comment="comment"][options="a,b,c,..."] [type="bool"] />
||SET ''name'', ''value''<br>
|style="width: 10%;"|PARAM name, comment, [a,b,c | bool]
or<br>
| When starting a script, a start page is shown where one can enter additional parameters for the script. Parameters can be defined either centrally for all scripts in the ODB under /Experiment/Edit on sequence. This subdirectory in the ODB can contain links to ODB values, which are queried at the start page. In addition, each script can define additional parameters appended to this list. They will be stored under /Sequencer/Variables and can be referenced inside the script via $name, where name can be any variable name specified in the parameter statement. The optional "comment" is shown on the start page below the parameter name. If only certain options are possible for the parameter, they can be defined via the options list. The web page will then contain a drop-down list showing the options. In case of type="bool", a checkbox will be shown.
''name'' = ''value''
|-style="background-color: #ffffcc; color: black;"
||Sets the variable ''name'' to "value". The variable can then be referenced later in the script by putting a "$" in front of the name like $"name". ''value'' can be a simple number or a complex expression containing other variables (preceded by a ''$'') and calculations such as ''$v + 3*$x * sin($t)''. Following functions are available: ''abs, acos, asin, atan, atan2, ceil, cos. cosh, e, exp, fac, floor, ln, log, pi, pow, sin, sinh, sqrt, tan, tanh''. A variable can be an array by using square brackets, like "a[10] = 5" or "x = $a[10]".
|style="width: 30%;" |<RunDescription> Description </RunDescription>
|style="width: 10%;"|RUNDESCRIPTION description
|a run description which is stored under /Experiment/Run Parameters/Run Description .
|-
|-
|style="width: 30%;" |<Script [params="a,b,c,..."]> Script </Script>
||SUBROUTINE ''name'' ... ENDSUBROUTINE
|style="width: 10%;" |SCRIPT script [, a, b, c, ...]
||Declares a subroutine which can be called via CALL.
|to call a script on the server side. Optionally, pass parameters to the script.
|-style="background-color: #ffffcc; color: black;"
|style="width: 30%;" |<Set name="name"> value </Set>
|style="width: 10%;"|SET name, value
|sets the variable name to value. Can be referenced with $name.
|-
|-
|style="width: 30%;" |<Subroutine name="name">...</Subroutine>
||TRANSITION start | stop | pause | resume
|style="width: 10%;"|SUBROUTINE name ... ENDSUBROUTINE
||To start, stop, pause or resume a run
|Declares a subroutine which can be called via <Call>.
|-style="background-color: #ffffcc; color: black;"
|style="width: 30%;" |<Transition>Start | Stop</Transition>
|style="width: 10%;"|TRANSITION start | stop | pause | resume
|to start, stop, pause or resume a run
|-
|-
|style="width: 30%;" |<Wait for="events | ODBvalue | seconds" [path="ODB path"] [op=">=/>/<=/</==/!="]> value </Wait>
||WAIT events | ODBvalue | seconds, [''ODB path''], [''op''], [''value'']
|style="width: 10%;"|WAIT events | ODBvalue | seconds, [ODB path], [op], [value]
||Wait until a number of events is acquired (testing /Equipment/Trigger/Statistics/Events sent), or until a value in the ODB exceeds value, or wait for ''value'' seconds. If the operand ''op'' is given, the ODB value is compared with value using this operand. So one could wait until an ODB value is equal to value or becomes smaller than value. Here is an example of such a statement which waits until some high voltage is below 100 V.  
|wait until a number of events is acquired (testing /Equipment/Trigger/Statistics/Events sent), or until a value in the ODB exceeds value, or wait for value seconds. If the operand op is given, the ODB value is compared with value using this operand. So one could wait until an ODB value is equal to value or becomes smaller than value. Here is an example of such a statement which waits until some high voltage is below 100 V.  
<pre>
WAIT ODBvalue, /Equipment/HV/Variables/Measured[3], <, 100
WAIT ODBvalue, /Equipment/HV/Variables/Measured[3], <, 100
</pre>
|}
|}


== [[MSL Example|MSL Example]] ==
= MSL Examples =
The following example is a simple script, which asks for a number of runs, then executes the runs, each lasting ten seconds.
The following example is a simple script, which writes a run description to the ODB, asks for a number of runs, then executes the runs, each running for 60 seconds.


<pre>
<pre>
comment "This is the MSL test file"
COMMENT "This is a MSL test file"
param runs
RUNDESCRIPTION "Test run"
PARAM runs
 
LOOP $runs
LOOP $runs
     TRANSITION START
     TRANSITION START
     WAIT 10
     WAIT Seconds, 60
     TRANSITION STOP
     TRANSITION STOP
ENDLOOP
ENDLOOP
</pre>
</pre>


== [[XML Example|XML Example]] ==
The following script is a more complex example, which measures a I-V curve (e.g. of a SiPM detector) and stores it in the ODB. It assumes a power supply operated by a front-end and linked to /Equipment/KEYTHLEY/. The I-V curve in the ODB can be plotted with a midas custom page.
Attached is a simple script which can be used as a starting point.
 
<pre>
<pre>
<?xml version="1.0" encoding="ISO-8859-1"?>
#
<RunSequence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="">
# I-V-Curve test with parameter specification at startup
<Comment>This is the XML test file</Comment>
#


<ODBSet path="/Experiment/Run Parameters/Comment">Test comment</ODBSet>
PARAM start_voltage, "Starting voltage"
<RunDescription>Test Run</RunDescription>
PARAM stop_voltage, "Stop voltage"
PARAM num_steps, "Number of steps"


<!-- do 10 runs -->
# Calculate step size
<Loop n="10">
num_steps = $num_steps + 1 # add one step for stop_voltage
  <!-- increment high voltage and wait for some time to settle -->
step_size = ($stop_voltage-$start_voltage) / ($num_steps-1)
  <ODBInc path="/Equipment/HV/Variables/Demand[0]">10</ODBInc>
  <Wait for="seconds">10</Wait>


  <!-- start a run, acquire 3000 events -->
# Initialize measurement arrays at startup
  <Transition>Start</Transition>
ODBCREATE /Equipment/Test/Variables/Voltage, FLOAT, $num_steps
  <Wait for="events">3000</Wait>
ODBCREATE /Equipment/Test/Variables/Current, FLOAT, $num_steps
  <Transition>Stop</Transition> -->
ODBCREATE /Equipment/Test/Variables/V, FLOAT
</Loop>
 
</RunSequence>
# Erase any previously stored array
ODBSET /Equipment/Test/Variables/Voltage[*], 0
ODBSET /Equipment/Test/Variables/Current[*], 0
 
v = $start_voltage
ODBSET /Equipment/Test/Variables/V, $v
 
current = 0
 
# Turn on Keithley
ODBSET /Equipment/KEITHLEY/Variables/Set State, 1
# Wait to turn on
WAIT SECONDS, 2
 
 
# Looping starts at 1
LOOP i, $num_steps
    # Store voltage in array and in variable
    ODBSET /Equipment/Test/Variables/Voltage[$i-1], $v
    ODBSET /Equipment/Test/Variables/V, $v
 
    # Set voltage and measure
    ODBSET /Equipment/KEITHLEY/Variables/Demand Voltage, $v
    # Wait for measurement to be stored in Current
    WAIT SECONDS, 10
    ODBGET /Equipment/KEITHLEY/Variables/Current, current
   
    # Outputting current to ODB array
    ODBSET /Equipment/Test/Variables/Current[$i-1], $current
 
    # increment voltage
    v = $v + $step_size
ENDLOOP
 
# Turn off Keithley
ODBSET /Equipment/KEITHLEY/Variables/Set State, 0
 
# Wait to turn off
WAIT SECONDS, 1
</pre>
</pre>
[[Category:Sequencer]]

Latest revision as of 01:31, 18 November 2024


Links

Introduction

A Sequencer for starting and stopping runs is part of the MIDAS distribution. It uses a simple Midas Script Language (MSL) for commands.

The sequencer runs as a separate process and must be started before running a sequence via the command msequencer. The first time the Sequencer button on the Status Page is pressed, the ODB Sequencer Tree is created. If the Sequencer button is not present on the Status Page, it may have been suppressed.

The sequencer runs scripts in MSL (Midas Script Language) format, which reside on the server (where mhttpd is running). The sequencer state is completely stored in the ODB, meaning that even if mhttpd or the sequencer is stopped and restarted, the active sequence operation continues exactly where it has been stopped.

Refer to the /Sequencer ODB tree for more details on its organization.

For instructions on getting started with the sequencer, see Sequencer Page

Controlling the sequencer from custom pages

The normal interface is the "Sequencer" status page in MIDAS. In addition, the sequencer can be controlled by other means. The ODB contains a directory /Sequencer/Command, which contains the currently loaded filename and three switches. To load new file and compile it, set the Load filename and the Load new file to yes.

 modbset(['/Sequencer/Command/Load filename',
          '/Sequencer/Command/Load new file',
         ['test.msl', 'Yes'])

After a script has been loaded, all PARAM values are extracted and placed under /Sequencer/Param/Defaults. Before a script is actually started, the default values may be modified and must be placed under /Sequencer/Param/Value before the sequencer is started. To start the script, set Start script to yes. This can be done in a combined way on a custom page via

 modbset(['/Sequencer/Param/Value/First parameter',
          '/Sequencer/Param/Value/Other parameter',
          '/Sequencer/Command/Start script'],
         ['123', '456', 'Yes'])

The parameter names of course have to be adjusted to the current script.

The starting of the script via above modbset can be put in the onclick=... method of a button, or even into a side menu via an alias by putting an ODB key into /Alias/xxx and setting it to javascript:modbset(...).

Sequencer Commands

The following commands are implemented in the MIDAS Sequencer. The left syntax is for the XML file, the right for the MSL (Midas Script Language).

Variable names are indicated in italic, options are enclosed in [brackets].

MSL format Description
INCLUDE name Include another MSL file name.msl
BREAK Break (finish prematurely) a loop. This is usually used together with an IF statement to abort a loop like
LOOP 10
  IF ($x > 0)
    BREAK
  ENDIF
ENDLOOP
CALL name, a, b, c, ... Call a subroutine. Optional parameters a,b,c... are passed to the subroutine, where they can be referenced via $1, $2, $3, etc. The subroutine can either reside in the current file, or in a library file which is included.
CAT name, a, b, c, ... Concatenates the strings a,b,c,... into a single variable name. Can be referenced with $name. If a string must contain a comma, it can be enclosed in quotes such as in CAT title, $run, ", ", $n_events
COMMENT comment A comment for this XML file, for information only. This comment is shown in the title bar next to the file name if one runs a script. This can be helpful if one has many XML files and the file name only is not enough to supply enough information.
EXIT Exit script immediately
GOTO n Jump to line n in script
IF con
or
IF (con)

...
ELSE
...
ENDIF

Statements between "IF" and "ENDIF" are only executed if condition "con" is true, otherwise the statements between the optional "ELSE" and "ENDIF" are executed. The condition can use any math expression using variables via $name together with operators "<", "<=", ">", ">=", "==", "!=", "&" (bitwise AND). Up to four nested IF statements are possible. An example would be "IF ($x+3 > $y*4+$z^2)".
LIBRARY name Indicates that the current file is a library (which can be included by other files). A library usually consists of a set of subroutines.
LOOP [name ,] n ... ENDLOOP To execute a loop n times. For infinite loops, "infinite" can be specified as n. Optionally, the loop variable running from 1...n can be accessed inside the loop via $name.
LOOP name, a, b, c, ... ... ENDLOOP Loop though a list of values. The loop is executed once for each value, which is stored into the variable name so it can be accessed inside the loop via $name.
MESSAGE message [,1] Opens a message box in the browser containing the text message. If wait="1", then the sequencer waits until the box is closed by the user before continuing.
MSG message [,<type>] Produces a midas message going into the message buffer. The optional <type> can be any of ERROR, INFO, DEBUG, LOG, TALK. If no type is given, INFO is used.
ODBCREATE path, type [, size] Create an ODB key of type type and optional size size (for arrays). type can be UNIT8, INT8, UNIT16, INT16, UNIT32, INT32, BOOL, FLOAT, DOUBLE, STRING
ODBDELETE path Delete an ODB key. If path points to a ODB subdirectory, delete the whole subdirectory.
ODBGET path, name To get a value from a variable name. The variable can then be referenced with $name. If the ODB value is an array, the index can be specified like via a constant or expression:
ODBGET "/Path/key[15]", v
ODBGET "/Path/key[$i + 15]", v
ODBINC path [, delta] To increment a value in the ODB. delta can be positive or negative. If no "delta" is given, 1 is used.
ODBLOOKUP path, string, name Lookup a string in a string array in the ODB given by path and return its index in name. If we have an array
/Examples/Names
   [0] Hello
   [1] Test
   [2] Other

and do a

 
ODBLOOKUP "/Examples/Names", "Test", index

we get a index equal 1. If a value is not found, the resulting index is set to "not found" which can be tested. If the ODB key does not exist, the sequencer aborts.

ODBSET path, value [, 0|1] To set a value in the ODB. value can be any math expression containing variables (preceded by a '$'). path can also contain variables (preceded by a '$'), but no math expressions.

If the ODB key referenced by path is an array, the index can be specified such as

ODBSET "/Path/value[3]", 1     # individual value
ODBSET "/Path/value[3-5]", 2   # index range 3,4,5
ODBSET "/Path/value[*]", 0     # all values of array

The path value can match multiple keys using the '?' and '*' wildcard (one or any number of characters respectively). This is useful to set the same sub-path on multiple folders:

ODBSET "/Path/to/somewhere/folder0/value", "1"
ODBSET "/Path/to/somewhere/folder1/value", "1" 
ODBSET "/Path/to/somewhere/folder2/value", "1"

can be shortened as:

ODBSET "/Path/to/somewhere/folder*/value", "1"

The notify flag specifies if possible hot-links to this ODB value are notified. This can be useful if a front-end program has many parameters, which must be set for a specific run. The front-end usually has a hot-link to its parameters, so on each modification a callback function in the front-end is called which usually modifies some hardware. If there are many ODBSet statements for all parameters, the callback would be executed on each ODBSet, so the hardware would be reconfigured many times slowing down the startup of a run. In order to prevent this, notify="0" can be specified for all ODBSet statements except the last one which contains notify="1", so the callback function is called only once at the end.

ODBLOAD file [, path] Load an external file into the ODB.

JSON, XML and ODB file format are supported with the value inferred by the content of the file. The optional path marks the position where to load the given file into the ODB, if no position is given the file is loaded from ODB root.
For the input file several options are supported: if the filename starts with "/" is is assumed to be an absolute path, if it starts with a "$" the path starts from the Sequencer root folder stored in the ODB at /Sequencer/Path. In all other cases it is intended as a relative path to the local MSL file.

ODBSAVE path, file Save part of the ODB to an external file.

The file extension is used to determine the format. Possible values are ".json", ".xml" and ".odb". The path can point to an individual value in the ODB or to a whole subtree.
For the output file several options are supported: if the filename starts with "/" is is assumed to be an absolute path, if it starts with a "%" the path starts from the Sequencer root folder stored in the ODB at /Sequencer/Path. In all other cases it is intended as a relative path to the local MSL file. If the file name contains a variable (starting with '$') it gets evaluated before saving.

ODBSUBDIR path ...ENDODBSUBDIR If one wants to se several ODB values in the same directory, the ODBSet commands can be rather long if the path is long. Using this command, the subdir can be specified for all commands between the opening and ending tags. So instead of writing
ODBSET /Very/long/path/into/the/odb/value1, 1
ODBSET /Very/long/path/into/the/odb/value2, 1
ODBSET /Very/long/path/into/the/odb/value3, 1
ODBSET /Very/long/path/into/the/odb/value4, 1

one can write

ODBSUBDIR /Very/long/path/into/the/odb
ODBSET value1, 1
ODBSET value2, 1
ODBSET value3, 1
ODBSET value4, 1
ENDODBSUBDIR
PARAM name, comment, [default], [a,b,c | bool] When starting a script, a start page is shown where one can enter additional parameters for the script. Parameters can be defined either centrally for all scripts in the ODB under /Experiment/Edit on sequence. This subdirectory in the ODB can contain links to ODB values, which are queried at the start page. In addition, each script can define additional parameters appended to this list. They will be stored under /Sequencer/Variables and can be referenced inside the script via $name, where name can be any variable name specified in the parameter statement. The optional "comment" is shown on the start page below the parameter name. An optional "default" value can be specified for each parameter. If the "default" value starts with a "/" it is interpreted as an ODB path and the default value is fetched from the ODB such as "/Logger/Write data".

If only certain options are possible for the parameter, they can be defined via the options list. The web page will then contain a drop-down list showing the options. In case of type="bool", a checkbox will be shown.

RUNDESCRIPTION description a run description which is stored under /Experiment/Run Parameters/Run Description .
SCRIPT script [, a, b, c, ...] To call a script on the server side. Optionally, pass parameters to the script. Any ASCII result from the script is stored as a string in the MSL variable $SCRIPT_RESULT. The script can be a direct command to be executed on the shell level, or can be a shell script which then gets executed, or can be an executable. If one has to pass several variables back to the MSL script, one can use the trick to store them into an ODB file (ASCII, XML or JSON format) and then use the ODBLOAD command to put the values into the ODB. Try the ODBSAVE command to see how the ODB format should look like.

The PATH environment is inherited from the place when the msequencer program is started. It can be checked with a simple shell script echo $PATH and then displaying the result with the MSL script command message $SCRIPT_RESULT, 1.

SET name, value

or
name = value

Sets the variable name to "value". The variable can then be referenced later in the script by putting a "$" in front of the name like $"name". value can be a simple number or a complex expression containing other variables (preceded by a $) and calculations such as $v + 3*$x * sin($t). Following functions are available: abs, acos, asin, atan, atan2, ceil, cos. cosh, e, exp, fac, floor, ln, log, pi, pow, sin, sinh, sqrt, tan, tanh. A variable can be an array by using square brackets, like "a[10] = 5" or "x = $a[10]".
SUBROUTINE name ... ENDSUBROUTINE Declares a subroutine which can be called via CALL.
TRANSITION start | stop | pause | resume To start, stop, pause or resume a run
WAIT events | ODBvalue | seconds, [ODB path], [op], [value] Wait until a number of events is acquired (testing /Equipment/Trigger/Statistics/Events sent), or until a value in the ODB exceeds value, or wait for value seconds. If the operand op is given, the ODB value is compared with value using this operand. So one could wait until an ODB value is equal to value or becomes smaller than value. Here is an example of such a statement which waits until some high voltage is below 100 V.
WAIT ODBvalue, /Equipment/HV/Variables/Measured[3], <, 100

MSL Examples

The following example is a simple script, which writes a run description to the ODB, asks for a number of runs, then executes the runs, each running for 60 seconds.

COMMENT "This is a MSL test file"
RUNDESCRIPTION "Test run"
PARAM runs

LOOP $runs
     TRANSITION START
     WAIT Seconds, 60
     TRANSITION STOP
ENDLOOP

The following script is a more complex example, which measures a I-V curve (e.g. of a SiPM detector) and stores it in the ODB. It assumes a power supply operated by a front-end and linked to /Equipment/KEYTHLEY/. The I-V curve in the ODB can be plotted with a midas custom page.

#
# I-V-Curve test with parameter specification at startup
#

PARAM start_voltage, "Starting voltage"
PARAM stop_voltage, "Stop voltage"
PARAM num_steps, "Number of steps"

# Calculate step size
num_steps = $num_steps + 1 # add one step for stop_voltage
step_size = ($stop_voltage-$start_voltage) / ($num_steps-1)

# Initialize measurement arrays at startup
ODBCREATE /Equipment/Test/Variables/Voltage, FLOAT, $num_steps
ODBCREATE /Equipment/Test/Variables/Current, FLOAT, $num_steps
ODBCREATE /Equipment/Test/Variables/V, FLOAT

# Erase any previously stored array
ODBSET /Equipment/Test/Variables/Voltage[*], 0
ODBSET /Equipment/Test/Variables/Current[*], 0

v = $start_voltage
ODBSET /Equipment/Test/Variables/V, $v

current = 0

# Turn on Keithley
ODBSET /Equipment/KEITHLEY/Variables/Set State, 1
# Wait to turn on
WAIT SECONDS, 2


# Looping starts at 1
LOOP i, $num_steps
    # Store voltage in array and in variable
    ODBSET /Equipment/Test/Variables/Voltage[$i-1], $v
    ODBSET /Equipment/Test/Variables/V, $v

    # Set voltage and measure
    ODBSET /Equipment/KEITHLEY/Variables/Demand Voltage, $v
    # Wait for measurement to be stored in Current
    WAIT SECONDS, 10
    ODBGET /Equipment/KEITHLEY/Variables/Current, current
    
    # Outputting current to ODB array
    ODBSET /Equipment/Test/Variables/Current[$i-1], $current

    # increment voltage
    v = $v + $step_size
ENDLOOP

# Turn off Keithley
ODBSET /Equipment/KEITHLEY/Variables/Set State, 0

# Wait to turn off
WAIT SECONDS, 1