Transient Recorder Framework
Public Member Functions | Protected Member Functions | Friends | List of all members
TRBaseDriver Class Referenceabstract

Central class of the Transient Recorder framework for transient recorders (digitizers). More...

#include <TRBaseDriver.h>

Inheritance diagram for TRBaseDriver:

Public Member Functions

 TRBaseDriver (TRBaseConfig const &cfg)
 Constructor for TRBaseDriver, to be used from constructors of derived classes. More...
 
template<typename ValueType , typename EffectiveValueType >
void initConfigParam (TRConfigParam< ValueType, EffectiveValueType > &param, char const *base_name, EffectiveValueType invalid_value=EffectiveValueType())
 Initialize a configuration parameter. More...
 
template<typename ValueType , typename EffectiveValueType >
void initInternalParam (TRConfigParam< ValueType, EffectiveValueType > &param, char const *base_name, EffectiveValueType invalid_value=EffectiveValueType())
 Initialize an internal configration parameter. More...
 
void completeInit ()
 Complete initialization of the class. More...
 
TRChannelsDrivergetChannelsDriver ()
 Return a reference to the channels driver. More...
 
void setDigitizerName (char const *name)
 Set the name of the digitizer, which will appear as the value of the "name" PV. More...
 
double getRequestedSampleRate ()
 Returns the requested sample rate. More...
 
void setAchievableSampleRate (double value)
 Sets the achievable sample rate corresponding to the requested sample rate. More...
 
int getNumBurstsSnapshot ()
 Returns the snapshot value of the number of bursts to capture. More...
 
int getNumPostSamplesSnapshot ()
 Returns the snapshot value of the number of post-trigger samples per event. More...
 
int getNumPrePostSamplesSnapshot ()
 Returns the snapshot value for the total number of samples per event (counting pre-trigger and post-trigger samples). More...
 
double getRequestedSampleRateSnapshot ()
 Returns the snapshot value of the requested sample rate. More...
 
double getAchievableSampleRateSnapshot ()
 Returns the snapshot value of the achievable sample rate. More...
 
void requestDisarmingFromDriver ()
 Request disarming of acquisition. More...
 
void publishBurstMetaInfo (TRBurstMetaInfo const &info)
 Publish meta-information about a burst. More...
 
void maybeSleepForTesting ()
 Possibly sleep for testing if enabled. More...
 
bool isArmed ()
 Check if acquisition is currently armed. More...
 
virtual asynStatus writeInt32 (asynUser *pasynUser, epicsInt32 value)
 Overridden asyn parameter write handler. More...
 
virtual asynStatus writeFloat64 (asynUser *pasynUser, epicsFloat64 value)
 Overridden asyn parameter write handler. More...
 

Protected Member Functions

virtual TRChannelsDrivercreateChannelsDriver ()
 Create the channels driver. More...
 
virtual void requestedSampleRateChanged ()
 Reports that the requested sample rate has changed. More...
 
virtual bool waitForPreconditions ()
 Wait for preconditions for arming to be satisifed. More...
 
virtual bool checkSettings (TRArmInfo &arm_info)=0
 Check preconditions for arming and report the sample freq rate for display. More...
 
virtual bool startAcquisition (bool overflow)=0
 Configure the hardware to start acquisition. More...
 
virtual bool readBurst ()
 This is called in a loop to wait for and read a burst of data. More...
 
virtual bool checkOverflow (bool *had_overflow, int *num_buffer_bursts)
 Check if there has been a buffer overlow. More...
 
virtual bool processBurstData ()
 Process the read that has just been read by readBurst. More...
 
virtual void interruptReading ()
 Interrupt reading of data. More...
 
virtual void stopAcquisition ()=0
 Configure the hardware to stop acquisition. More...
 
virtual void onDisarmed ()
 Called when isArmed() changes from true to false. More...
 

Friends

template<typename , typename >
class TRConfigParam
 
class TRChannelsDriver
 
class TRChannelDataSubmit
 

Detailed Description

Central class of the Transient Recorder framework for transient recorders (digitizers).

Digitizer drivers use this class by inheriting it, constructing it with the appropriate parameters and implementing various virtual functions.

The major features provided by this class are:

Constructor & Destructor Documentation

TRBaseDriver::TRBaseDriver ( TRBaseConfig const &  cfg)

Constructor for TRBaseDriver, to be used from constructors of derived classes.

The function completeInit MUST be called just after the entire object is constructed.

Parameters
cfgParameters for construction as a struct. See TRChannelDataSubmit for an example of how to initialize the parameters in an expression.

Member Function Documentation

template<typename ValueType , typename EffectiveValueType >
void TRBaseDriver::initConfigParam ( TRConfigParam< ValueType, EffectiveValueType > &  param,
char const *  base_name,
EffectiveValueType  invalid_value = EffectiveValueType() 
)
inline

Initialize a configuration parameter.

This should be called in the constructor of derived classes for all configuration parameters (ConfigParam) defined by the driver, excluding internal configuration parameters (those should be initialized using initInternalParam).

Parameters
paramThe configuration parameter to be initialized.
base_nameThe base name of the configuration parameter. The prefixes DESIRED_ and EFFECTIVE_ will be added to form the asyn parameter names.
invalid_valueThe invalid value for the effective-value parameter, which is its value when the device is not armed or the parameter is irrelevant due to other configuration.
template<typename ValueType , typename EffectiveValueType >
void TRBaseDriver::initInternalParam ( TRConfigParam< ValueType, EffectiveValueType > &  param,
char const *  base_name,
EffectiveValueType  invalid_value = EffectiveValueType() 
)
inline

Initialize an internal configration parameter.

An internal parameter differs from a regular configuration parameter in that its desired value is not set though the external (EPICS) interface but by the driver, using TRConfigParam::setDesired.

Parameters
paramThe configuration parameter to be initialized.
base_nameThe base name of the configuration parameter. The prefixes DESIRED_ and EFFECTIVE_ will be added to form the asyn parameter names.
invalid_valueThe invalid value for the effective-value parameter, which is its value when the device is not armed or the parameter is irrelevant due to other configuration.
void TRBaseDriver::completeInit ( )

Complete initialization of the class.

This MUST be called immediately after the entire object is constructed including derived objects. It performs initialization which could not be performed in the constructor.

Notably, it creates the channels driver, which involves calling the virtual function createChannelsDriver.

TRChannelsDriver& TRBaseDriver::getChannelsDriver ( )
inline

Return a reference to the channels driver.

This MUST NOT be called before completeInit is completed, as the channels driver is constructed in completeInit.

Returns
Reference to the channels driver.
void TRBaseDriver::setDigitizerName ( char const *  name)

Set the name of the digitizer, which will appear as the value of the "name" PV.

The default name is the asyn port name.

This function MUST be called with the port locked, except if called before EPICS could interact with the asyn port such as from the driver's constructor.

Parameters
nameDigitizer name (pointer is not used after return). Must not be NULL.
double TRBaseDriver::getRequestedSampleRate ( )

Returns the requested sample rate.

Note that it is allowed for the driver to use special sample rate values such as negative ones, e.g. to use an external clock source. But otherwise the value should be in Hz.

This function MUST be called with the port locked.

Returns
The requested sample rate.
void TRBaseDriver::setAchievableSampleRate ( double  value)

Sets the achievable sample rate corresponding to the requested sample rate.

As in getRequestedSampleRate, it is allowed for the driver to use special sample rate values. But otherwise the value should be in Hz.

This function MUST be called with the port locked.

Parameters
valueThe achievable sample rate.
int TRBaseDriver::getNumBurstsSnapshot ( )
inline

Returns the snapshot value of the number of bursts to capture.

This will be either positive (for a specific number of bursts) or 0 (for an unlimited number of bursts).

This function is meant to be used by drivers which do not use the framework's read loop so that they can initiate disarming when the requested number of bursts have been captured.

See checkSettings for limitations regarding reading snapshot values.

Returns
The snapshot number of bursts.
int TRBaseDriver::getNumPostSamplesSnapshot ( )
inline

Returns the snapshot value of the number of post-trigger samples per event.

This will be non-negative. If the driver does not declare support for pre-trigger samples (TRBaseConfig::supports_pre_samples is false), then this is also guaranteed to be positive. Otherwise, see getNumPrePostSamplesSnapshot for additional guarantees.

See checkSettings for limitations regarding reading snapshot values.

Returns
The snapshot number of post-samples.
int TRBaseDriver::getNumPrePostSamplesSnapshot ( )
inline

Returns the snapshot value for the total number of samples per event (counting pre-trigger and post-trigger samples).

This will always be positive and will be greater than or equal to getNumPostSamplesSnapshot. Equality means that no pre-trigger samples are desired.

See checkSettings for limitations regarding reading snapshot values.

Returns
The snapshot number of pre-post-samples.
double TRBaseDriver::getRequestedSampleRateSnapshot ( )
inline

Returns the snapshot value of the requested sample rate.

This will be the value of getRequestedSampleRate at the time the snapshot was made.

See checkSettings for limitations regarding reading snapshot values.

Returns
The snapshot requested sample rate.
double TRBaseDriver::getAchievableSampleRateSnapshot ( )
inline

Returns the snapshot value of the achievable sample rate.

This will be the last value set using setAchievableSampleRate at the time the snapshot was made.

See checkSettings for limitations regarding reading snapshot values.

Returns
The snapshot achievable sample rate.
void TRBaseDriver::requestDisarmingFromDriver ( )

Request disarming of acquisition.

This allows the driver itself to initiate disarming as if a disarm request was received. If acquisition is currently disarmed, nothing will be done.

This function MUST be called with the port lock held.

This function may sychronously call the interruptReading driver function. That must be considered when the driver has overridden interruptReading (that should be the case in any driver that uses the framework's read loop).

There are two use cases for this:

  • When the driver does not use the framework's read loop (leaves default implementations of readBurst, processBurstData, checkOverflow and interruptReading), in order to indicate to the framework that the requested number of bursts have been read.
  • To indicate to the framework that a driver-specific condition to automatically disarm has been detected (whether or not the driver uses the framework's read loop).

If the driver uses the read loop and does not support any driver-specific conditions to automatically disarm, there is no reason to call this; the framework will itself automatically disarm after the desired number of bursts have been read.

void TRBaseDriver::publishBurstMetaInfo ( TRBurstMetaInfo const &  info)

Publish meta-information about a burst.

This function should be called after data for a burst has been submitted (using TRChannelDataSubmit). If the driver uses the framework's read loop, this should be from the function processBurstData.

The driver should call asynPortDriver::updateTimeStamp on this driver (not the channels driver) for each burst before calling this function. This is because the framework will report the time of the last burst based on the current timestamp in the driver. It is expected that most drivers will use the timestamp obtained by updateTimeStamp as the timestamp of channel data arrays of all channels involved in the burst (the epics_ts argument to TRChannelDataSubmit::submit).

This function MUST be called with the port unlocked.

Parameters
infoMeta-information about the burst.
void TRBaseDriver::maybeSleepForTesting ( )

Possibly sleep for testing if enabled.

The framework implements a feature to optionally sleep after reading a burst, for testing purposes, especially testing of buffer overflow handling .

If the driver uses the framework's read loop, this function is automatically called after (successful) processBurstData. Otherwise, the driver may call this at the appropriate time to gain the capability to sleep after reading a burst (or generally wherever it wishes).

This function MUST be called with the port unlocked.

bool TRBaseDriver::isArmed ( )

Check if acquisition is currently armed.

For the purposes of this function, acquisition becomes armed when waitForPreconditions is started and becomes not armed after stopAcquisition returns, or if there was an error before startAcquisition then immediately after the error.

This function MUST be called with the port locked.

Returns
True if disarmed, false if not.
virtual TRChannelsDriver* TRBaseDriver::createChannelsDriver ( )
protectedvirtual

Create the channels driver.

This function allows the driver to use its own derived class of TRChannelsDriver for the channels port.

If this function is overridden, it MUST create an instance (using new) of a TRChannelsDriver derived class. If the driver does not override this function, the default implementation will create an instance of TRChannelsDriver.

One reason the driver may want to use a custom TRChannelsDriver derived class is to add asyn parameters to it. However, note that this is only needed when the parameter needs to be per-channel, otherwise the parameter would be better suited to the main class (derived class of TRBaseDriver).

Returns
The new channels driver, allocated using new.
virtual void TRBaseDriver::requestedSampleRateChanged ( )
protectedvirtual

Reports that the requested sample rate has changed.

The driver should recalculate the achievable sample rate (setAchievableSampleRate) based on the requested sample rate (getRequestedSampleRate). That can be done either synchronously in this function (if the calculation is not demanding) or asynchronously. In the latter case, it is important that waitForPreconditions waits until any ongoing clock calculation is completed.

This is called with the port locked and it MUST NOT unlock it at any point.

The default implementation calls getRequestedSampleRate then calls setAchievableSampleRate with that value. Be careful because this is probably not currect for most drivers, as the hardware usually allows only a discrete set of sample rates.

virtual bool TRBaseDriver::waitForPreconditions ( )
protectedvirtual

Wait for preconditions for arming to be satisifed.

This is called at the very beginning of arming. If this function returns false, arming will not proceed and an error will be reported. In that case the framework will wait until disarming is requested and only then allow another arming attempt.

This function is called with the port locked and MUST return with the port locked. It MAY internally unlock and re-lock the port (actually it must do that while waiting for anything).

In case of successful return, the framework will make snapshots of desired configuration parameters while the port is still locked. Normally arming will then proceed with checkSettings. However, there is no guarantee that a successful waitForPreconditions call will be followed by checkSettings; arming may be aborted without notice at this stage.

The default implementation only returns true.

Returns
True on success (port locked, proceed with arming), false on error (port not locked, abort arming).
virtual bool TRBaseDriver::checkSettings ( TRArmInfo arm_info)
protectedpure virtual

Check preconditions for arming and report the sample freq rate for display.

This is called just after a successful waitForPreconditions.

If this function returns false, arming will not proceed and an error will be reported. In that case the framework will wait until disarming is requested and only then allow another arming attempt.

If this function returns true, it must fill in arm_info as appropriate. Note that setting TRArmInfo::rate_for_display is mandatory in this case.

This is called with the port locked and it MUST NOT unlock it at any point.

There is no guarantee that a successful checkSettings will be followed by startAcquisition, arming may be aborted without notice at this stage.

Starting with this function, the driver is allowed to read the parameter snapshot values using TRConfigParam::getSnapshot as well as snapshot values provided by the framework (get*Snapshot functions). The snapshot values were captured just after waitForPreconditions returned successfully. Snapshot values may be read and are guaranteed to not change until the driver returns from stopAcquisition.

NOTE: Snapshot values MUST NOT be read before checkSettings is called or after stopAcquisition returns (until the next checkSettings call).

Parameters
arm_infoThe driver must set the relevant variables of this class if it returns true. Note that some of the variables are mandatory.
Returns
True on success (proceed with arming), false on error (abort arming).
virtual bool TRBaseDriver::startAcquisition ( bool  overflow)
protectedpure virtual

Configure the hardware to start acquisition.

This can be called in two scenarios. The normal scenario is just after checkSettings returned true (overflow==false). The other scenario is as part of recovery from buffer overflow (overflow==true).

This function should return false in case of unexpected errors. In that case an error will be reported, the framework will wait until disarming is requested, and only then call stopAcquisition and allow another arming attempt.

This is called with the port unlocked and MUST return unlocked. It MAY internally lock and unlock the port.

Parameters
overflowWhether this the initial call during for arming (overflow==false) or a subsequent call after a buffer overflow (overflow==true).
Returns
True on success (proceed with the read loop), false on error (abort arming).
virtual bool TRBaseDriver::readBurst ( )
protectedvirtual

This is called in a loop to wait for and read a burst of data.

If the driver does not wish to use the framework's implementation of the read loop:

This function should read one burst of data from the hardware buffers. Processing and submitting of data should be done in processBurstData which will normally follow readBurst (but may not in case of disarming).

This function should return false in case of unexpected errors. In that case an error will be reported, the framework will wait until disarming is requested, and only then call stopAcquisition and allow another arming attempt.

This is called with the port unlocked and MUST return unlocked. It MAY internally lock and unlock the port.

Returns
True on success of if aborted due to interruptReading, false on error (stop reading).
virtual bool TRBaseDriver::checkOverflow ( bool *  had_overflow,
int *  num_buffer_bursts 
)
protectedvirtual

Check if there has been a buffer overlow.

If the driver does not wish to use the framework's implementation of the read loop, it should not override this function (it would not be called).

This is called after every successful readBurst when a buffer overflow has not yet occurred. It should set *had_overflow to whether an overflow has occurred. If it sets *had_overflow to true, it should also set *num_buffer_bursts to the remaining number of bursts that can be read before restarting PLUS ONE (i.e. including the burst just read). Typically, *num_buffer_bursts would be set to the number of bursts which fit into the hardware buffer. But be careful because hardware may claim to have some power-of-two buffer size but really have one fewer usable capacity.

This function should return false in case of unexpected errors. In that case it is not necessary to set *had_overflow or *num_buffer_bursts, an error will be reported, the framework will wait until disarming is requested, and only then call stopAcquisition and allow another arming attempt.

If an overflow is detected, the driver may also perform any actions necessary to allow reading of the remaining data to proceed without problems.

This is called with the port unlocked and MUST return unlocked. It MAY internally lock and unlock the port.

The default implementation sets *had_overflow to false and returns true.

Parameters
had_overflowOn success, this should be set to whether a buffer overflow has occurred.
num_buffer_burstsOn success and if a buffer overflow has occurred, this MUST be set to the remaining number of bursts that can be read PLUS ONE.
Returns
True on success, false on error (stop reading).
virtual bool TRBaseDriver::processBurstData ( )
protectedvirtual

Process the read that has just been read by readBurst.

If the driver does not wish to use the framework's implementation of the read loop, it should not override this function (it would not be called).

This is normally called after each successful readBurst call (but may not be in exceptional cases like disarming or errors). From within this function, the driver should submit burst data using TRChannelDataSubmit objects and (preferably after that) call publishBurstMetaInfo.

This function should return false in case of unexpected errors. In that case an error will be reported, the framework will wait until disarming is requested, and only then call stopAcquisition and allow another arming attempt.

This is called with the port unlocked and MUST return unlocked. It MAY internally lock and unlock the port.

Returns
True on success, false on error (stop reading).
virtual void TRBaseDriver::interruptReading ( )
protectedvirtual

Interrupt reading of data.

If the driver does not wish to use the framework's implementation of the read loop, MUST NOT override this function.

This will only be called while the read thread is in the core of the read loop, that is after a successful startAcquisition but before stopAcquisition, and also only in between two startAcquisition in case of buffer overflows. It will also be called no more than once in the entire arming sequence.

Calling this must ensure that any ongoing or future readBurst call returns as soon as possible and that any future readBurst call returns immediately. Note that readBurst must not return an error (false) due to this interruption; readBurst does not need to report to the caller whether it returned due to interruption or because a burst was read.

This is called with the port locked and it MUST NOT unlock it at any point. It MUST NOT block. If synchronous actions are needed to ensure that reading is interrupted reliably, they MUST be done on another thread.

virtual void TRBaseDriver::stopAcquisition ( )
protectedpure virtual

Configure the hardware to stop acquisition.

This is called after a call to startAcquisition, and is to be understood as the reverse of that. It is called after any readBurst, checkOverflow or processBurstData calls have returned.

After this returns, the hardware will be considered disarmed and a new arming may later start, beginning with waitForPreconditions. There is no way to return an error here as the framework could not reasonably react to an error.

This is called with the port unlocked and MUST return unlocked. It MAY internally lock and unlock the port.

virtual void TRBaseDriver::onDisarmed ( )
protectedvirtual

Called when isArmed() changes from true to false.

This is called with the port locked and it MUST NOT unlock it.

This was added to support a design where changing a desired configuration parameter value should actually apply the change immediately unless the digitizer is armed, but if the value is changed while armed it should still be applied automatically when the digitizer is disarmed. To implement this correctly you should:

  • Override the write function corresponding to the type of the type of the parameter (writeInt32 or writeFloat64). There, before checking whether the parameter is owned by one of the base classes, check if the parameter index is equal to TRConfigParam::desiredParamIndex(). If it is equal then...
  • Call isArmed() and if it returned false, apply the configuration to hardware. You should use the value parameter of the function since TRConfigParam::getDesired was not updated yet at this point. You should still call and return the result of the base class write function regardless of isArmed.
  • Implement onDisarmed and in that function ensure that the value returned by TRConfigParam::getDesired is applied to the hardware. You can use a dirty flag to avoid having to access the hardware redundantly.

Do not instead use stopAcquisition for this or similar purposes because of possible race conditions and since stopAcquisition may not be called in case of an early error.

The default implementation does nothing.

virtual asynStatus TRBaseDriver::writeInt32 ( asynUser *  pasynUser,
epicsInt32  value 
)
virtual

Overridden asyn parameter write handler.

It is important that derived classes which override this function delegate to the base class method when the parameter is not from the derived class, including when the parameter belongs to a TRConfigParam defined by the derived class.

Care is needed because a comparison of the parameter index to the index of the first own parameter of the derived class may not yield the expected result. If such a check is used, then the dervived class must initialize all its TRConfigParam before its normal asyn parameters. This way, the asyn parameters belonging to TRConfigParam will receive lower indices than normal asyn parameters of the derived class.

Parameters
pasynUserAsyn user object.
valueValue to be written.
Returns
Operation result.
virtual asynStatus TRBaseDriver::writeFloat64 ( asynUser *  pasynUser,
epicsFloat64  value 
)
virtual

Overridden asyn parameter write handler.

Refer to the documentation of writeInt32.

Parameters
pasynUserAsyn user object.
valueValue to be written.
Returns
Operation result.

The documentation for this class was generated from the following file: