NSCL DDAS  1.0
Support for XIA DDAS at the NSCL
 All Classes Namespaces Files Functions Variables Macros Pages
Author
Ron Fox
Date
3/18/2020

Overview

Note
This document applies to DDAS version 3.0-000 and later.

The libDSPParameters library provides a package for managing the Digital Signal Processing (DSP) Parameters of Pixie16 boards. It also provides utilities for managing crates of modules. Finally the toxxx package is built on top of this library.

To understand the library you need to understand the concept of Readers and Writers. A Reader gets the DSP Parameters for modules or crates from some source. That source might be the modules themselves, XIA .set files XML files or whatever other source you might add to the system.

There are two Reader base classes:

Conversely, writers write DSP settings to some sink. The sink might be the module, a .set file or a XML file. There are two writer base classes:

Readers

Readers take DSP parameters from some source and store them in an internal representation. The internal representations used are structs that are defined in the ModuleSettings.h header. There are two types of Readers. Readers that take settings from a single module worth of stuff and Readers that take settings from a Crate worth of stuff. The abstract base classes for both of these use the strategy pattern to provde the main logic in the base class while providing source dependent code in derived, concrete classes.

Let's look at the module readers first. Currently there are module readers for:

Let's have a look at the base class, DDAS::SettingsReader described in the header SettingsReader.h :

 namespace DDAS {
     class SettingsReader
     {
     public:
         virtual ~SettingsReader() {}
         virtual DDAS::ModuleSettings get() = 0; 
     };
 }

SettingsReader depends on the concrete class to implement an appropriate constructor and a get method that knows how to do the actual fetch. For more information on the concrete classes see:

Crate Readers

Crate readers are intended to read a collection of modules. The DDAS::CrateReader base class uses a strategy pattern to provide the main logic flow for reading a crate allowing the concrete subclasses to provide readers for individual modules. Here's the definition of DDAS::CrateReader from the header CrateReader.h:

 namespace DDAS {
    class CrateReader {
    protected:
        std::vector<unsigned short> m_slots;
        unsigned                    m_crateId;
    public:
        CrateReader() {}
        CrateReader(unsigned crate, const std::vector<unsigned short>& slots);
        virtual ~CrateReader();
    public:
        virtual Crate readCrate();
        virtual SettingsReader* createReader(unsigned short slot) = 0;
    };
 }

Only public and protected members are shown. m_slots is a vector of slot numbers that must be rea and m_crateId is the crate id to be given to the collection. This crate id overrides the crate id from the modules themselves. The pure virtual method: createReader must produce a DDAS::SettingsReader for the slot number provided. Note this is a slot number not a module id.

Concrete subclasses include:

Writers

The concept of Writers mirrors that of Readers. There is the DDAS::SettingsWriter class which writes a module's worth of data and DDAS::CrateWriter which writes a PXI crate worth of data.

Here's the class definition of DDAS::SettingsWriter from SettingsWriter.h

 namespace DDAS {
    class SettingsWriter
    {
    public:
        virtual ~SettingsWriter() {}
        virtual void write(const ModuleSettings& dspSettings) = 0;
    };
 }         

Constructing a concrete DDAS::SettingsWriter is supposed to connect it with its sink. The write method then writes DDAS::ModuleSettings to that module. This method is pure virtual and must be implemented in concrete classes. These include:

Similarly the DDAS::CrateWriter writes a collection of modules in a PXI crate. Modules can be selectively loaded. Here's the definition of DDAS::CrateWriter from CrateWriter.h:

 namespace DDAS {
    class SettingsWriter;
    class CrateWriter {
    protected:
        Crate                       m_settings;
    public:
        CrateWriter(const Crate& settings);
        virtual ~CrateWriter() {}
    public:
        virtual void write();
        virtual void startCrate(
            int id, const std::vector<unsigned short>& slots
        )  = 0;
        virtual void endCrate(
            int id, const std::vector<unsigned short>& slots
        )    = 0;
        virtual SettingsWriter* getWriter(unsigned short slotNum) = 0;
    };
 }

The m_settings attribute are the settings that will be loaded. Three pure virtual methods must be implemented by any concrete crate write:

Currently the following concrete DDAS::CrateWriter subclasses have been supplied:

Other support functions

The library contains a other useful functions and classes.

Set file reader

The header SetFile.h provides definitions that allow you to read set files. These are presented as a static methods for a class in the DDAS namespace. A set file is essentially a soup of uint32_t values (with one exception). The header defines this class:

 namespace DDAS {
    class SetFile {
    public:
        // Var definition files:
        static VarOffsetArray readVarFile(const char* filename);
        static VarMapByOffset createVarOffsetMap(const VarOffsetArray& offsets);
        static VarMapByName   createVarNameMap(const VarOffsetArray& offsets);
        // set files I/O and resource management:
        static std::pair<unsigned, uint32_t*> readSetFile(const char* filename);
        static void writeSetFile(
            const char* filename, unsigned nLongs, uint32_t* pVars
        );
        static void freeSetFile(uint32_t* pVars);
        static UnpackedSetFile populateSetFileArray(
            unsigned nLongs, const uint32_t* pVars,
            const VarOffsetArray& map
        );
        static SetFileByName populateSetFileMap(
            unsigned nLong, const  uint32_t* pVars,
            const VarOffsetArray& map
        );
        static SetFileByName populateSetFileMap(
            const UnpackedSetFile& vars
        );
   };
}

The class documentation will provide documentation for each of these methods, however a few important points:

Normally this set of methods is used as follows:

Crate manager class

The DDAS::CrateManager class provides a class that can manage a PXI crate that has Pixie16 digitizers. Here are the important featurs of that class (defined in CrateManager.h). See the class documentation for more:

namespace DDAS {
    class CrateManager {
        DAQ::DDAS::Configuration*    m_pConfiguration;
        std::vector<unsigned short>  m_slots;
    public:
        CrateManager(const std::vector<unsigned short>& slots);
        virtual ~CrateManager();
        // Slot translation
        unsigned short moduleId(unsigned short slot);
        unsigned short  slot(unsigned short id);
        // Configuration:
        void loadDSPAddressMap(unsigned short id);
        void fullBoot(unsigned short id);
        void fullBoot(unsigned short id, const char* setFile);
        static std::string getVarFile(unsigned short speed);
   };
}

A few notes:

Example of getVarFile and the Setfile class:

#include <CrateManager.h>
#include <SetFIle.h>
...
// I have a 250MHz module in slots 2 and 3 (ids 0,1)
// I want to read the set file parameters for both using the raw set file
// reader.  I'll put those into a map keyed by parameter name.
        std::string varFile       = DDAS::CrateManager::getVarFile(250);
        DDAS::VarOffsetArray vars = DDAS::SetFile::readVarFile(varFile.c_str());
  std::pair<unsigned, uint32_t*> sfDesc = DDAs::SetFile::readSetFile("mfile.set");
        uint32_t* p = sfDesc.second;
        unsigned  s = sfDesc.first;
        DDAS::SetFileByName slot2 =
                DDAS::SetFile::populateSetFileMap(s, p, vars);
        p += N_DSP_PAR;
        s -= N_DSP_PAR;
        DDAS::SetFileByName slot3 =
                DDAS::SetFile::populateSetFileMap(s, p, vars);
        DDAS::SetFile::freeSetFile(sfDesc.second);
        ...

XML used to describe DSP settings.

A new innovation with this library is the ability to store DSP settings in XML files that use units that are independent of the digitizers used. This allows you to:

What makes this work is that:

All of this comes at a cost, however and that is load speed. It takes about 20 seconds to load a module from its XML settings. This is dominated by the time to call the Pixie16WriteSglModPar and Pixie16WriteSglChanPar functions in the XIA API. XML file parsing is actually quite quick.

This section documents the form of the XML files that describe crates and modules.

First a bit about XML, in case you are not familiar with. XML is an acronym for eXtensible Markup Language. You can think of it as a descendent of HTML (HyperText Markup Language), the language used to specify web pages. An XML file also called a document, consists of a header, and tags.

Tags are of the form <tag>body</tag> where the body can contain other tags or text depending on what the document represents. In XML there is normally a single outer tag that is documents look like

<roottag>
   other stuff
</roottag>

Rather than

<tag1>
   nested stuff
</tag1>
<tag2>
   nested stuff
</tag2>

Tags can also have attributes an attribute is a string of the form key="value" or key='value' inside the tag specification. For example:

...
   <sometag attr1="value1" attr2="value2">
            contents.
         </sometag>
...

Finally, if a tag has no contents it can be expressed as: <tag>. Such tags can also have attributes.

With very superficial introduction to XML document structure, let's look at the structure of the two XML document types we have defined, crates and modules

Crate XML files

The purpose of a crate file is to specify which slots are occupied and the properties of each module in those occupied slots. Here's a sample crate definition file that describes a crate with one module:

<crate id="1">
  <slot number="2" evtlen="4" configfile="bimdev_Module_00.xml">
</crate>

As you can see there are two tags. The root tag is <crate> and it can contain as many <slot> tags are required The <crate> tag has one mandatory attribute, id which is the crate id that will be assigned to each module of that crate.

<slot> tags are empty tags. Slot tags have several mandatory attributes as well as some optional ones. The mandatory attributes are:

The optional attributes and their default values are:

Module XML files

Module XML files contain the settings for a single module. Depending on how they are written there may be a metadata tag in the front of the module XML file. Metadata tags are intended to give XML file processors clues about how the file should be processed. The metadata tag will look like

<?xml version="1.0"?>

and just indicates this file is compliant with the version 1.0 definition of XML.

A module file will look like (only one channel's settings are shown for brevity):

<Module>
    <csra value="1">
    <csrb value="81">
    <format value="0">
    <maxevents value="0">
    <synchwait value="false">
    <insynch value="true">
    <SlowFilterRange value="3">
    <FastFilterRange value="0">
    <BackplaneTriggerEnables value="0">
    <crateID value="1">
    <slotID value="2">
    <moduleId value="0">
    <trigConfig0 value="0">
    <trigConfig1 value="0">
    <trigConfig2 value="0">
    <trigConfig3 value="0">
    <HostRTPreset value="1203982208">
    <channel id="0">
        <TriggerRiseTime units="microseconds" value="0.4">
        <TriggerFlatTop units="microseconds" value="0.08">
        <TriggerThreshold units="adccounts" value="65">
        <EnergyRiseTime units="microseconds" value="4.8">
        <EnergyFlatTop units="microseconds" value="0.384">
        <Tau units="microseconds" value="50">
        <TraceLength units="microseconds" value="6">
        <TraceDelay units="microseconds" value="2">
        <VOffset units="volts" value="-0.283035">
        <XDT units="microseconds" value="0.06">
        <Baseline units="percent" value="10">
        <EMin units="none" value="0">
        <BinFactor units="none" value="1">
        <BaselineAverage units="none" value="4">
        <CSRA units="bitmask" value="36">
        <CSRB units="bitmask" value="0">
        <BlCut units="none" value="4">
        <Integrator units="none" value="0">
        <FastTriggerBacklen units="microseconds" value="0.24">
        <CFDDelay units="microseconds" value="0.064">
        <CFDScale units="none" value="0">
        <CFDThresh units="none" value="120">
        <QDCLen0 units="microseconds" value="0.12">
        <QDCLen1 units="microseconds" value="0.12">
        <QDCLen2 units="microseconds" value="0.004">
        <QDCLen3 units="microseconds" value="0.12">
        <QDCLen4 units="microseconds" value="0.004">
        <QDCLen5 units="microseconds" value="0.12">
        <QDCLen6 units="microseconds" value="0.004">
        <QDCLen7 units="microseconds" value="0.12">
        <ExtTrigStretch units="microseconds" value="0.8">
        <VetoStretch units="microseconds" value="0.24">
        <MultiplicityMasks low="0" high="0">
        <ExternDelayLen units="microseconds" value="0.64">
        <FTrigoutDelay units="microseconds" value="0.08">
        <ChanTrigStretch units="microseconds" value="0.8">
    </channel>
    <channel id="1">
                ....
                  </channel>
</Module>

The root tag is <Module> Directly beneath it are tags for module level parameters. After the module level parameters is one <channel> tag for each channel in the module. The <channel> id attribute is the channel number. Inside each <channel> tag are tags for the DSP parameters for the channel.

Parameter tags all have the same general form. The tag name (eg. csra) identifies the parameter and the mandatory value attribute provides the value for that parameter. The units attribute, which is optional but provided for documentation purposes provides the units of measure of the parameter. All module level parameters are unitless and therefore the units attribute is not used.

Note that the units of measure shown must be used. You cannot, for example specify units="nanoseconds" and provide a timing value in nanoseconds. The XML processor does not pay attention to the units attribute. The units attribute is documentation to tell you, if you edit the file by hand, the units you must specify the parameter value in.