Module GseosSequencer
Previous  Top  Next

The GseosSequencer module allows you to run and control test sequences. Using the GseosSequencer module it is easy to write test scripts for closed-loop instrument control. You can command the instrument and verify that certain values are met within a certain time. Depending on the outcome you can issue further commands to log the success or failure in a test procedure log. This allows you to set up test sequences that can be run to autonomously verify the proper performance of the system which is especially useful as a regression testing tool. Although it may seem that the Monitor and Sequencer modules have overlapping functionality they have an entirely different focus and concept. The Sequencer module allows you to write synchronous test control sequences, meaning that you can write down a sequential test procedure whereas the Monitor module works asynchronous (event driven) and makes it therefore hard to write a sequential control script. The central functionality of the Sequencer is provided by the Wait() function. You provide a list of blocks (events), a condition and an optional timeout value. Your condition is evaluated whenever one of the blocks in the list arrives. If your condition evaluates to true the Wait() returns otherwise the condition will be reevaluated with the next block arrival. There are two possible scenarious that have the Wait() function return before your condition returns true. If you specify a timeout value and the timeout timer expires before your condition returns true the Wait() function raises a TSeqTimeoutError exception. If you stop the Sequencer the Wait() function will raise a TSeqAbortError exception. For trivial condition functions (one liners) you can make use of the lambda function of Python.
Each sequencer is run in it's own thread of execution and you have to be aware of threading issues when accessing shared resources. Especially if you plan to generate GSEOS blocks from a sequencer you have to make sure to use thread safe block access if any other thread might write to the same block. Please refer to the GseosBlocks.TThreadSafeBlock documentation for more details on how to access GSEOS blocks in a thread safe manner.

Let's just start with a simple example to demostrate the use of the Sequencer:

import GseosSequencer

# A Sequencer script turning on the heater circuit, waiting for the temperature to
# rise to 20 and turn the heater off.
def fWarmUp(oSeq):
  """
  It is always a good idea to document your Sequencer scripts. These document strings
  are also accessible from the Sequencer user interface. Here we go:
  Fire up the heater, wait until we reach 20C and turn the heater off.
  """
  # Start the heater with our heater command
  fStartHeater()

  # Wait until we reach 20C
  oSeq.Wait(HK, lambda: HK.Temp == 20)

  # Stop the heater
  fStopHeater()

# Start the Sequencer
GseosSequencer.TSequencer('Heater Control 1', fWarmUp)

This simple Sequencer turns on a heater circuit, waits for the temperature to rise (the heater presumably changes the temperature which is reflected in the HK.Temp item) to a desired value and stops the heater.
Well, this script is far from perfect, for example if the temperature is higher than 20 at the beginning or we don't get a block with HK.Temp equal to 20 with we will never exit the Wait().
Your sequencer function (fWarmUp() in the above sample) gets the sequencer object passed as the first parameter. Additional parameters can be added when the sequencer object is created and are passed through to your sequencer function.
The last line then finally starts the Sequencer. To start the Sequencer you have to provide a unique name, the Sequencer function, optional arguments as a tuple, and an optional flag that indicates if you want to create the Sequencer in the stopped state. By default the Sequencer starts running as soon as you create it. The Sequencer runs in it's own thread (in the background) and the call to create the Sequencer returns immediately. Now let's assume we have three similar heaters and we want to control all of them. Instead of defining three Sequencer scripts we can parameterize the sequencer function fWarmUp(). When we start a Sequencer we can pass an optional argument which then in turn is passed to the sequencer function. Here our example for multiple heaters:

import GseosSequencer

# Parameterized heater script. Pass two arguments, the heater number and the
# destination temperature.
def fWarmUp(oSeq, wHeater, wDestTemp):
  "Heater Control 2. Takes the heater number and the destination temp."

  # Start the heater with our heater command
  fStartHeater(wHeater)

  # Wait until we reach our destination temperature
  oSeq.Wait(HK, lambda Heater=wHeater, Temp=wDestTemp: HK.Temp[Heater] == Temp)

  # Stop the heater
  fStopHeater(wHeater)

# Fire up the Sequencer for heater 2 and 30C.
GseosSequencer.TSequencer('Heater Control 2', fWarmUp, (2, 30))

# Fire up the Sequencer for heater 3 and 25C.
GseosSequencer.TSequencer('Heater Control 3', fWarmUp, (3, 25))

# Fire up the Sequencer for heater 4 and 45C.
GseosSequencer.TSequencer('Heater Control 4', fWarmUp, (4, 45))

The above script expects two additional parameters besides the Sequencer reference that is passed in as the first parameter. In our case we pass the heater number and the destination temperature. When we invoke the Sequencer we have to provide the parameters as the third parameter of the TSequencer() constructor. Now we can start as many Sequencers as needed (three in the above example) using just one sequencer function.
The above examples both terminate when the desired temperature is reached. To restart them we can just call the Start() function of the Sequencer. (This can easily be done from the GSEOS Explorer).
In order to programmatically restart the Sequencer we of course have to keep a reference of the Sequencer when we create it. Here is how you would do it:

# Create a Sequencer
oHeaterCtrl = GseosSequencer.TSequencer('Heater Control 5', fWarmUp, (5, 10))
...
# At some later point restart the Sequencer to bring
# the heater 5 back up to it's temperature.
oHeaterCtrl.Start()

The other functions of interest are Stop() to stop a running Sequencer, and Delete() to delete it. Besides the Wait() function there are three other functions the Sequencer provides: MessageBox(), InputDialog(), and Sleep(). Let's look at one more example which simulates a two-point control for the temperature:

# The Sequencer script of the two-point heater control
def fTwoPointHeater(oSeq, wLowTemp, wHighTemp):
  "Heater Control. A two-point heater control."

  # Control our heater circuit until we get terminated
  while 1:
    if HK.Temp >= wHighTemp:
      fStopHeater()
      oSeq.Wait(HK, lambda wTemp=wLowTemp: HK.Temp <= wTemp)

    elif HK.Temp <= wLowTemp:
      fStartHeater()
      oSeq.Wait(HK, lambda wTemp=wHighTemp: HK.Temp >= wTemp)

    # If we are in the right range just wait for a while 
    else:
      oSeq.Sleep(300)

# Fire up the two-point controller.
GseosSequencer.TSequencer('Two-point controller', fTwoPointHeater, (20, 30))

Although this functionality could also be implemented with a Monitor it demonstrates some of the Sequencer functions.

Now that we know how to use the Sequencer from a script let's have a brief look at the Sequencers in the GSEOS Explorer. You will find the Sequencers beneath the GSEOS main node:


explorersequencers

The Explorer lists all Sequencers in existence and their respective status. The docstring of the selected Sequencer function is displayed in the left pane (it is always a good idea to provide a short description). If you right-click on the Sequencer you get a menu that allows you to Start/Stop/Delete the Sequencer. You can also highlight multiple sequencers and right-click on the selection to invoke the operation for a number of sequencers at once. The Start/Stop button allows you to start or stop the selected Sequencer(s). You can also delete the Sequencer from the control dialog.

The sequencer module implements the TSequencer class which exports the following methods:
TSequencer
Start
Stop
Delete
Wait
Sleep
MessageBox
InputDialog
GetStatus


Most of the above functions also have a doc string which you can access with: GseosSequencer.function.__doc__