The addtcldriver command allows you to
add a Tcl command ensemble as a module which can then be
added to the -modules
list of modules read out
by a stack. In Tcl a command ensemble is
a command that has subcommands. The addtcldriver
command registers the base command of a command ensemble
as a module. In turn, the command ensemble is required to provide
at least two subcommands; Initialize and
addReadoutList which perform functions
analagous to methods with the same name in a C++ driver.
Possibly the simplest way to build command ensembles that can be re-used to support more than one module is to use a Tcl object oriented extension. When you do this, a driver is a class and instances of those classes are modules. Almost all Tcl object oriented extensions make objects (class instances) command ensembles where the base name is the object names and methods of the class are subcommands.
Driver modules will also need to access the VM-USB during
initialization and create lists of VME operations in their
addReadoutList
method. This
is accomplished by wrappgin the CVMUSB
and CVMUSBReadoutList
classes using the
Simplified Wrapper and Interface Generator or
SWIG. SWIG wrappers are provided as loadable Tcl modules in the
lib directory of the NSCLDAQ software
installation.
This chapter will look at two trivial drivers that put a marker in the buffer and, at initialization time, turn on the bottom yellow LED. One of these drivers is written using Incr-Tcl (itcl) the other using Snit Is Not Incr Tcl (snit). While trivial these examples illustrate most of the key concepts you need to understand when writing device support software in Tcl.
Finally, a configuration file fragment is shown that illustrates loading and using these two drivers.
The example below is a complete itcl driver class. When the run is initialized, it lights to bottom yellow LED of the VM-USB. For each event it inserts a programmable marker (literal) value in the event.
Example 69-9. Itcl VM-USB device driver
lappend auto_path /usr/opt/daq/10.1/lib package require Itcl package require cvmusb package require cvmusbreadoutlist itcl::class marker-itcl { public variable value 0 constructor args { eval configure $args } public method Initialize driverPtr { cvmusb::CVMUSB c -this $driverPtr; set leds [c readLEDSource] set leds [expr {$leds & 0xffff}] set leds [expr {$leds | 0x110000}] c writeLEDSource $leds (11) } public method addReadoutList list { (12) cvmusbreadoutlist::CVMUSBReadoutList l -this $list; (13) l addMarker $value (14) } }
CVMUSB
and
CVMUSBReadoutList
, the Tcl
variable auto_path
must be extended
to include the lib subdirectory
of the NSCLDAQ installation directory. In this case,
NSCLDAQ is installed in /usr/opt/daq/10.1.
You will need to check your installation and use
the appropriate value here.
CVMUSB
C++ class.
CVMUSBReadoutList
C++ class.
marker-itcl
is used to generate instances of the class.
As with all object oriented languages, classes wrap behavior and data into a single package.
This makes Incr-Tcl objects very much like Tk widgets.
The example below shows how you can set the
value
variable at both construction and configuration time:
This constructor does nothing except allow the use of configuration option settings when an object is constructed.
Initialize
implements
device initialization that is done at the start of the
run. The driverPtr
is a SWIG
pointer that represents the address
of the CVMUSB
object normally
passed to C++ Initialize
driver methods.
CVMUSB
object. The
-this
option tells SWIG to build its
wrapping around an existing SWIG pointer. The
end result of this line is that the object named
c is created that talks to the
same VM-USB as the object normally passed in to a
C++ device support class/object.
readLEDSource
method of the CVMUSB
object.
This reads the current value of the VM-USB LED source
register. The arithmetic that follows modifies the
bottom Yellow LED selector to use the inverse of the
Not Slot one state as the
source of the LED.
addReadoutList
method
is intended to provide a list of VME operations that
are executed in response to each event trigger.
The list
is a SWIG pointer to the
CVMUSBReadoutList
normally passed
to a C++ driver's addReadoutList
method.
The first command in this method wraps the list in a SWIG object named l so that it can be used from within Tcl to manipulate the list.
value
object instance variable.
As previously discussed, since this is a public variable
it is hooked to the -value
configuration
option for the object.
In general you will need to look at the reference information on the SWIG wrappers for CVMUSB CVMUSBReadoutList
Snit is a pure Tcl object oriented extension to Tcl. In this section we will look at an annotated sample Snit Tcl driver. The sample driver will just turn on the VM-USB's bottom yellow LED at initialization time and inserts a configurable marker into each event in response to a trigger.
While this driver is realtively trivial, it illustrates many of the key points you will need to understand to write Tcl drivers in snit. If you have looked at the Incr-Tcl driver in the previous section there will be very little that is new here other than Snit syntactical differences from Incr-Tcl.
Example 69-10. A Snit VM-USB driver.
lappend auto_path /usr/opt/daq/10.1/lib package require snit package require cvmusb package require cvmusbreadoutlist snit::type marker-snit { option -value 0; constructor args { $self configurelist $args } method Initialize driverPtr { cvmusb::CVMUSB v -this $driverPtr; set leds [v readLEDSource] set leds [expr {$leds & 0xf0ffffff}]; set leds [expr {$leds | 0x08000000}]; v writeLEDSource $leds (11) } method addReadoutList list { (12) cvmusbreadoutlist::CVMUSBReadoutList l -this $list; (13) l addMarker $options(-value) (14) } }
CVMUSB
and
CVMUSBReadoutList
you must
add the directory in which they are installed to the
auto_path
variable. This is the
lib directory below the top
level of your NSCLDAQ installation. You may need
to change the directory in the example script to match
your installation.
CVMUSB
class.
CVMUSBReadoutList
.
This line creates a new snit::type named marker-snit. Each instance of this class can be registered as a module allowing it to be included in a stack.
options
the indices
of this array are the option names, the values of the
array are the values of the options.
The purpose of the -value
option
is to hold the value of the marker that will be inserted
by this driver into each event.
self
is like the
C++ this
pointer).
The call to configurelist processes the parameters to the constructor as a set of option/value pairs. This allows objects to be constructed and configured in a single step (again like Tk widgets).
Initialize
method
of an object is called by the readout framework
when a run is being started. It is expected to
interact with the hardware to initialize the
device it manages in accordance with its configuration.
The driverPtr
is a
SWIG Pointer. Swig pointers
are text strings that provide a strongly typed pointer
to a C++ object.
driverPtr
.
The resulting object is called v
readLEDSource
method on the SWIG object v
.
That method reads the current value of the
LED Source register, a register internal to the VM-USB
that controls what makes the front panel LED's light.
The arithmetic that follows sets the field responsible for controlling the bottom yellow LED such that it will light on the inverse of the case when the VM-USB is not a slot one controller. This means that if the VM-USB is in slot one, it will have the bottom yellow LED lit.
list
is a SWIG pointer to a
CVMUSBReadoutList
. The method is
expected to add the entries to that list it needs to
execute for each event trigger.
list
parameter in a
SWIG object named l
in a mannner
analagous to what was done in Initialize
-value
configuration
option.
In general you will need to look at the reference information on the SWIG wrappers for CVMUSB CVMUSBReadoutList
This section assumes you are using a driver that has a generator of driver instances. The object oriented examples meet those criteria. To use a Tcl driver in a DAQ configuration file you must:
Incorporate the driver in the daqconfig file source code.
Create and configure an instance of the driver for the device(s) it manages in your physical configuration
Use the addtcldriver command to turn each driver instance into a module.
As with any module, incorporate it into a
stack's -modules
list.
Consider the drivers we described in the previous section. Suppose the source code for those driver files, tcldriver-itcl.tcl and tcldriver-snit.tcl are located in the same directory as the DAQ configuration file. The following configuration file fragment creates an instance of each and adds them to a stack containing other natively coded modules that is triggered on the NIM 1 input.
Example 69-11. USing a Tcl VM-USB driver.
source tcldriver-snit.tcl; # load a snit tcl driver.
marker-snit create snitmarker -value 0x5a5a; # Create an instance..
addtcldriver snitmarker; # Add it to the list of known modules.
source tcldriver-itcl.tcl; # load an incrtcl driver.
marker-itcl itclmarker -value 0xa5a5 # crate/configure an instance.
addtcldriver itclmarker # register it.
...
stack config event -modules [list test test2 test snitmarker itclmarker]
In the exmample above, the Tcl modules are highlighted in the stack configuration command.
Other approaches to packaging. If you rdriver is intended for re-use across several setups and even users, the method described above is not maintainable. In that case, it is better to stoere the driver sources in some central location, add package provide commands to each driver files and use pkg_mkIndex command to build a package index file.
If this is done, and the directory added to the Tcl search path, you could then use package require to load the driver file. Storing driver code centrally allows you to ensure that experiments are using up-to-date versions of your software.