This section describes how to write a device support module. Device support modules are built into shared object libraries that can be dynamically loaded into the readout software via the load command.
The device support package is provided as a template driver source file and a Makefile that builds the shared object. If the DAQ software is installed in $DAQROOT, the following commands copy the template driver and its makefile:
Example 5-4. Obtaining the ccusb driver development kit
cp $DAQROOT/ccusbdriver/drivertemplate.cpp . cp $DAQROOT/ccusbdriver/Makefile .
The example below shows how to load a user written driver and use the driver that is created by an unmodified driver template:
Example 5-5. Using a user written CCUSB driver
set here [file nativename [file dirname [info script]]] load [file join $here libtemplatedriver.so] changeme create testing -value 0x1234
The example assumes that you have built the driver in the same directory as your configuration file. The first example line computes the full file path to the configuration file's directory. The second loads the driver, joining that path to the name of the shared object created by the Makefile. Note that you typically will need to provide a full path to the driver shared object or the load command will claim the file cannot be located. The final command creates and configures a device instance named testing using the changeme command the unmodified driver creates.
Let's look at the template driver you copied.
The template consists of two main chunks. The first chunk is a
class derived from CReadoutHardware
that is
responsible for managing the driver itself. You will normally
need to modify the onAttach
,
Initialize
and addReadoutList
methods of this class, as well as changing the class name to something
more reasonable than CTemplateDriver
.
The second chunk is a Tcl package initialization function that must define the Tcl command that is associated twith the driver.
While the driver template is heavily commented, and modification points are indicated, the next few sections are a guided tour of the main sections you will need to modify.
Each driver instance has a configuration database attached to it when it is created. The configuration database holds configuration parameter definitions and their current values. The framework takes care of managing the values for you, however you must define the set of configuration parameters supported by your driver.
The template driver's code is (comments removed for brevity:
void CTemplateDriver::onAttach(CReadoutModule& configuration) { m_pConfiguration = &configuration; m_pConfiguration->addIntegerParameter("-slot", 1, 23, 1); m_pConfiguration->addIntegerParameter("-value"); // default is 0. }
onAttach
needs to be able
to access its configuration in other methods.
The configuration
parameter is
a reference to that configuration. This line
saves a pointer to that configuration in the
m_pConfiguration
member variable.
Note that a CReadoutModule
is derived from a CConfigurableObject
and that base class holds the configuration.
This code is provided by the driver template.
addIntegerParameter
call).
This code is provided by the driver template.
This line is provided by the template driver but normally is removed as you edit the code to define the configuration options you actually need.
Normally the onAttach
method is simply
defining the set of configuration parameters it needs to know
how to initialize and read the device it manages. Configuration
parameters are named items (by convention the names start with the
dash character) and are strongly typed. Integer, real, string,
enumerated, and boolean simple parameters are supported. In
addtion collection (Tcl lists) are supported.
Parameter values can have constraints placed on them (the
range of -slot
parameter values e.g.) which
are checked by the configuration subsystem without any intervention
by you. Several pre-defined constraint checkers are available,
as are convenience functions for defining configuration parameters.
You can also define custom constraint checkers and register them
with the configuration subsystem.
See CConfigurableObject(3ccusb) for detailed information about how to define configuration parameters.
The Initialize
method of each
device instance that has been put in a stack is called
after the configuration file is processed prior to loading
the stack and prior to turning on data taking mode in the
CC-USB.
Typically in Initialize
you must:
Fetch the configuration parameters you need to know how to initialize the device and prepare it for data taking.
Issue method calls to the controller
CCCUSB
object passed in to the
method. Note that if your device requires a lot of
initialization, you can speed up that process
by creating CCCUSBReadoutList
objects, which are lists of instructions, using
its methods to create a list of operatinos and then
asking the controller to execute that list.
For detailed information about the methods supported by
the CCCUSB
and CCCUSBReadoutList
,
see CCCUSB(3ccusb) and CCCUSBReadoutList(3ccusb)
The template driver provides the following code (most comments removed for brevity).
void CTemplateDriver::Initialize(CCCUSB& controller) { int slot = m_pConfiguration->getIntegerParameter("-slot"); /* MODIFY ME HERE */ /* END MODIFICATIONS */ }
-slot
configuration parameter
from the configuration database for this module.
controller
object to manipulate the CAMAC crate. If initialization
requires a large number of CAMAC operations you could
also create a CCCUSBReadoutList
,
manipulate it to store a set of operatiuons and then
use controller.executeList(3ccusb)
to
execute that list.
addReadoutList
is called as a run is
being intialized. This method is expected to contribute items
to the CCCUSBRedoutList
that will be
loaded into either a scaler or event stack. Usuall this is done
by fetching the set of configuration parameters that are required
to know how to read the device and then invoking appropriate
methods on the list
parameter to
add CAMAC operations to the stack.
The template driver implements a marker 'device'. The marker
device ignores its -slot
configuration parameter
(a production quality marker driver would probably not define
a -slot
parameter). It adds an instrution
to the list
that inserts a literal
value into the event. The value inserted is determined by
the -value
parameter.
Here's the sample driver code for the addReadoutList
method:
void CTemplateDriver::addReadoutList(CCCUSBReadoutList& list) { int slot = m_pConfiguration->getIntegerParameter("-slot"); /* MODIFY ME HERE */ int value = m_pConfiguration->getIntegerParameter("-value"); list.addMarker(value); // This is a longword marker. /* END MODIFICATIONS */ }
-value
cofiguration parameter. This is the value
that we are going to insert into the event buffer
addMarker
method adds
the CCUSB instructions to insert a literal value in the
output buffer to the list being built up. This
therefore instructs the CCUSB that the readout of this
'device' consists of inserting the value of the
-value
configuration parameter.
Naturally a real device would add NAF instructions or
Q-Stop/C-Scan operations to the list via other
CCCUSBReadoutList
methods.
The Tcl load command searches the shared object for a specific function entry point that it will call to initialize the library. The initialization function must follow the correct naming conventions or Tcl will complain about not being able to find the library's initialization function.
The initialization entry point must be the name of the
resulting library with the lib prefix stripped
off and the first letter capitalized suffixed by _Init.
Thus if you are building
libmydriver.so, the initialation function
must be called Mydriver_Init
.
The template driver provides the following code:
extern "C" { int Templatedriver_Init(Tcl_Interp* pInterp) { Tcl_PkgProvide(pInterp, "Templatedriver", "1.0"); CUserCommand::addDriver("changeme", new CTemplateDriver); return TCL_OK; } }
CUserCommand
::addDriver
function associates a template device driver object
with its Tcl command ensemble name. The template device driver
object is cloned for each create subcommand
issued for this driver in the configuration script.
You should change both the name of the driver command
from changeme and you should have
previously changted the class name of the
driver class from CTemplateDriverM