next up previous
Next: 8. Index Up: No Title Previous: 6. Calibration objects

Subsections


   
7. More about plugins

OK. The latter the better. Here come the plugins ! The class diagram for plugins is the right part of figure 4. Plugin principles are quite general, but we will focus here on plugins managing emcFEMtuple objects. Adaptation to other kind of emcManageable should be trivial.

7.1 Advertising the plugin capabilities

The first duty of a plugin is to advertise what kind of objects it can read, write, collect or handle (handle=read OR write OR collect), i.e. it should implement the following methods (defined in the base emcObjectManager class and returning false by default) :

bool CanCollect(const emcManageable& object) ;
bool CanHandle(const emcManageable& object) ;
bool CanWrite(const emcManageable& object) ;
bool CanRead(const emcManageable& object) ;

By default, the CanHandle is defined as :

bool emcObjectManager::CanHandle(const emcManageable& object) {
    return 
      CanWrite(object) || 
      CanRead(object) || 
      CanCollect(object) ; 
}

A plugin that advertise Reading capability should be able to read a Manageable from DB and/or from file.

Here is a code sample on how you can do this. It's all about casting :

//___________________________________________________
bool emcOMGains::CanRead(const emcManageable& object)
{
  // we advertize here that we can only handle a given
  // number of object types, e.g. emcGains only.

  bool rv = false ;
  const emcManageable* object_ptr = &object ;
  const emcGains* test = dynamic_cast<const emcGains*>(object_ptr) ;

  if (test) {
    rv = true ;
  }
  return rv ;
}

In the above example, the plugin can read emcGains objects, whatever their source is. You might want to selectively announce reading capability from one given source. You could do this like that :

//___________________________________________________
bool emcOMGains::CanRead(const emcManageable& object)
{
  // we advertize here that we can only handle a given
  // number of object types, e.g. emcGains only.

  bool rv = false ;
  const emcManageable* object_ptr = &object ;
  const emcGains* test = dynamic_cast<const emcGains*>(object_ptr) ;

  if (test && object.GetSource()==emcManageable::kDB_Objy) {
    // can only read from Objy DB (not from files)
    rv = true ;
  }
  return rv ;
}

If the plugin announces Writing capability, it must be able to split the given emcFEMtuple into pieces spanning one FEM (=1 bank).

The CanCollect is usually equivalent to CanRead (i.e. if a plugin can Read, it should be able to Collect also).

7.2 The mother class emcOMFEMtuple

As many operations are common to all the calibration flavours, those operations have be gathered into the base plugin class emcOMFEMtuple. The Read,Write and Collect methods are defined there. Plugins deriving from this class must implement (assuming they can want to access Objy at all) :

They might also redefine the following :

A note on bankID : so far, the bankID internal value (which is an 4-bytes integer) is built from four characteristic values of the FEMs : absolute position, pin number, post-pre, tac-pre, as illustrated in figure 10.


  
Figure 10: bankID for FEMs
\includegraphics[width=11cm]{bankID.eps}

7.3 The Collect procedure

The emcOMFEMtuple class maintains an internal (pointer to) object of class emcFEMtuple (actual type depends on the flavour), figure 11.


  
Figure 11: emcOMFEMtuple class
\includegraphics[width=11cm]{emcOMFEMtuple.eps}

The first time the Collect is called (or after a Reset of the plugin), the pointer to the emcFEMtuple object is null. In that case the Collect is just a loop over the FEMs described in the configuration file. Each FEM is read from DB/File and then added to the internal emcFEMtuple object. Schematically :

emcManageable* emcOMFEMtuple::Collect(const emcManageable& object,
  const PHTimeStamp& when) {

...

emcRawDataAccessor* rda = emcRawDataAccessor::GetInstance() ;
int nSM = rda->GetDynamicData()->getnSM() ;
const SuperModule* SMMap = rda->GetDynamicData()->getSMMap() ;

// Create an emcFEMtuple object of the right type
fFEMs = emcFEMtupleFactory::Create(object.GetCategory()) ;

int ifem ; // fem index
int code ;
bool ok = true ;
emcFEMtuple* oneFEM ;

// Loop over FEMs

for ( ifem = 0 ; ifem < nSM && ok==true ; ifem++ ) {

  // Here some code to skip the monitoring crates 
  // (if any) for anything which is 
  // not Pedestals of HLRatios
  ...

  // Create the ``driver'' object of the right type
  // This object is only needed to give the type and
  // the data source.
  oneFEM = emcFEMtupleFactory::Create(object.GetCategory()) ;
  oneFEM->SetSource(object.GetSource()) ;

  // Build the code for the FEM.

  code = emcCalFEM::FEMCode(SMMap[ifem].absPosition,SMMap[ifem].femPin,
                             SMMap[ifem].post_pre,SMMap[ifem].tac_pre) ;


  // Read this FEM
  ok = Read((*oneFEM),when,code) ;
  
  // Add this FEM to fFEMs
  ok = fFEMs->Add((*oneFEM)) ;

  // The delete free the pointer, but not the internal of it (note 1)
  delete oneFEM ;
 }

Note 1 : remember that an emcFEMtuple is a list of emcCalFEM objects. When you create an emcFEMtuple, it is owner of this list. As soon as you add an emcFEMtuple to another one, it looses its ownership on its internal emcCalFEMs, thus a delete will not erase the emcCalFEM objects (it will be deleted, in the above example, when fFEMs is deleted).

Once the Collect has been done once, subsequent call to it will behave slightly differently. First, when entering the Collect method, we check if the fFEMs object is still valid at time when, in which case we just return it :

emcManageable* emcOMFEMtuple::Collect(const emcManageable& object,
  const PHTimeStamp& when)
{ 
  if (fFEMs) {
    // If what we have already is still valid, returns it.      
    if (fFEMs->IsValid(when)) return fFEMs ;
  }
}

Otherwise, we enter the loop as before, but we do some extra check (the assumption here is that only part of the emcCalFEMs might be out of the validity range) :

...
for ( ifem = 0 ; ifem < nSM && ok==true ; ifem++ ) {
...
  // fFEMs is already filled up, se we first check
  // that we really need to fetch new values for this FEM
  if ( ! fFEMs->IsValid(when,ifem) ) {
    ok = Read((*oneFEM),when,code) ;
    if (ok) {
      ok = fFEMs->ReplaceFEM(ifem,(*oneFEM)) ;
    }
  }
}

i.e. we only read FEMs which are not still valid. The ReplaceFEM will just exchange one pointer to another one (and delete the first one). Hope the explanation is clear...

OK. So far so good. The Read and Write methods are just trivially using pdbcal interfaces to access PdbCalBanks, and then the relevant To/FromPdbCalBank are called to fill actual emcCalFEM objects (see code for details).

7.4 Plugin trick

Before we end up, you should be aware on the mechanism used to convert a normal C++ class into a DataManager plugin. In the implementation file of your plugin, just call the following macro :

#include "emcObjectManagerRegister.h"
EMCALDM_REGISTER_OBJECTMANAGER(classname,title,comment)
// e.g. for Gains plugins :
EMCALDM_REGISTER_OBJECTMANAGER(emcOMGains,
  "emcOMGains",
  "Object to handle Gains and TofT0s objects")

Note that there is no trailing ; at the end of the macro call.

That's it. You should be able to debug or write a plugin by yourself now !


next up previous
Next: 8. Index Up: No Title Previous: 6. Calibration objects
Laurent APHECETCHE - 2000-07-28