Transient Recorder Framework
|
Central class of the Transient Recorder framework for transient recorders (digitizers). More...
#include <TRBaseDriver.h>
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 > ¶m, char const *base_name, EffectiveValueType invalid_value=EffectiveValueType()) |
Initialize a configuration parameter. More... | |
template<typename ValueType , typename EffectiveValueType > | |
void | initInternalParam (TRConfigParam< ValueType, EffectiveValueType > ¶m, char const *base_name, EffectiveValueType invalid_value=EffectiveValueType()) |
Initialize an internal configration parameter. More... | |
void | completeInit () |
Complete initialization of the class. More... | |
TRChannelsDriver & | getChannelsDriver () |
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 TRChannelsDriver * | createChannelsDriver () |
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 |
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:
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.
cfg | Parameters for construction as a struct. See TRChannelDataSubmit for an example of how to initialize the parameters in an expression. |
|
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).
param | The configuration parameter to be initialized. |
base_name | The base name of the configuration parameter. The prefixes DESIRED_ and EFFECTIVE_ will be added to form the asyn parameter names. |
invalid_value | The 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. |
|
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.
param | The configuration parameter to be initialized. |
base_name | The base name of the configuration parameter. The prefixes DESIRED_ and EFFECTIVE_ will be added to form the asyn parameter names. |
invalid_value | The 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.
|
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.
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.
name | Digitizer 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.
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.
value | The achievable sample rate. |
|
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.
|
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.
|
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.
|
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.
|
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.
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:
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.
info | Meta-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.
|
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).
|
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.
|
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.
|
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).
arm_info | The driver must set the relevant variables of this class if it returns true. Note that some of the variables are mandatory. |
|
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.
overflow | Whether this the initial call during for arming (overflow==false) or a subsequent call after a buffer overflow (overflow==true). |
|
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.
|
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.
had_overflow | On success, this should be set to whether a buffer overflow has occurred. |
num_buffer_bursts | On success and if a buffer overflow has occurred, this MUST be set to the remaining number of bursts that can be read PLUS ONE. |
|
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.
|
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.
|
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.
|
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:
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 |
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.
pasynUser | Asyn user object. |
value | Value to be written. |
|
virtual |
Overridden asyn parameter write handler.
Refer to the documentation of writeInt32.
pasynUser | Asyn user object. |
value | Value to be written. |