/* * PulserDetector.cpp * * Implementation of the base class for pulser detector * * Created on: Aug 14, 2015 * Author: Hovanes Egiyan */ #include "PulserDetector.hh" using namespace std; PulserDetector::PulserDetector( const std::string detName ) : pdName(detName), pdPulserMap(), pdReadyToProcess(false), pdFlag() { initMutex(); MtxLock objLock(pdMutex); // Create the object that contains information sent from the SNL code. pdPV = new PulserPVs(); return; } // Destructor PulserDetector::~PulserDetector() { MtxLock obLock(pdMutex); // Destroy all pulser objects for ( map::iterator it = pdPulserMap.begin(); it != pdPulserMap.end(); it++ ) { std::string pulserName = it->first; VPulser* pulserPtr = it->second; if( pulserPtr != 0 ) delete pulserPtr; pdPulserMap.erase( pulserName); } // Destroy the object with the SNL PV info. if( pdPV != 0 ) delete pdPV; closeMutex(); return; } //! Initialize mutex for individual objects void PulserDetector::initMutex() { pthread_mutexattr_init( &pdMtxAttr ); pthread_mutexattr_setpshared( &pdMtxAttr, PTHREAD_PROCESS_PRIVATE ); pthread_mutex_init( &pdMutex, &pdMtxAttr ); return; } //! Destroy mutex for individual objects void PulserDetector::closeMutex() { pthread_mutex_destroy( &pdMutex ); pthread_mutexattr_destroy( &pdMtxAttr ); return; } // Connect and set monitor for the PVs needed for this detector void PulserDetector::assignPVs() { MtxLock obLock(pdMutex); pdPV->assignPVs(); pdReadyToProcess = true; // Start the thread for this detector that monitors the PVs // and sets the flags that have been registered when input PVs change. pthread_t thID; int thStat = pthread_create( &thID, NULL, (void* (*)(void*))PulserDetector::ThreadFunc, (void*) this ); // If fails to create the threat throw and exception if ( thStat !=0 ) { std::stringstream errStream; errStream << "PulserDetector::assignPVs: Failed to create thread " << hex << showbase << thID << dec << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // Specify which PVs will be used in this detector. The first parameter is the // state sequence ID, the second parameter is the reference to the structure // defined in the SNL code. This method the points the arrays in PV object for // this detector to the arrays in pvStruct in the argument, and then assigns the PV pointers // in all pulser to the value of pdPV pointer for this detector. All pulsers end // up using the same struct, so care must be taken. void PulserDetector::usePVs( SS_ID ssID, PulserPVs::pvStruct& pvStruct ) { MtxLock obLock(pdMutex); pdPV->setSSID(ssID); // Set the SSID for this detector pdPV->getArrays() = pvStruct; // Set the pointers to this arrays in this detector. // Loop over all pulsers in this detector and set their PV object pointer to the // PV object pointer of this detector so that all pulser within this detector use the // same PV arrays. for ( map::iterator it = pdPulserMap.begin(); it != pdPulserMap.end(); it++ ) { std::string pulserName = it->first; VPulser* pulserPtr = it->second; if( pulserPtr != 0 ) { pulserPtr->setPVs(pdPV); } } return; } // Method to register the flag for synchronization with a new sequencer ID. void PulserDetector::registerFlag( const SS_ID ssID, const EV_ID flagID ) { MtxLock obLock(pdMutex); // Each ssID can only have one synchronization flag, that is the convention. if( pdFlag.count(ssID) == 0 ) { pdFlag[ssID] = flagID; } else { // throw an exception if that ssID already have registered a event flag. std::stringstream errStream; errStream << "PulserDetector::registerFlag : SSID " << hex << ssID << dec << " has already register a flag " << flagID << " for detector " << pdName; throw std::runtime_error(errStream.str()); } return; } // Check if a pulser pulserID exists for this detector bool PulserDetector::pulserExists( const std::string pulserID ) { if( pdPulserMap.count(pulserID) > 0 ) { return true; } else { return false; } } // Function that executes in a separate thread and checks if the PVs have changed // and sets the signal for SNL code to process PVs. void* PulserDetector::ThreadFunc( void* argPtr ) { PulserDetector* detPtr = (PulserDetector*)( argPtr ); bool exitFlag = false; // infinite loop while ( !exitFlag ) { if ( detPtr->getPVs()->inputsChanged() ) { map flagMap = detPtr->getFlags(); MtxLock objLock( detPtr->getMutex() ); // Loop over all SSID and notify them by setting their flags. The corresponding // state sequence should read the PVs from this detector and clear the flag. for (map::iterator it = flagMap.begin(); it != flagMap.end(); it++) { SS_ID ssID = it->first; EV_ID flagID = it->second; // cout << "PulserDetector::ThreadFunc: Notifying SSID " << ssID << " using flag ID " << flagID << endl; seq_efSet( ssID, flagID ); // Set the flag received from SNL during registration } } usleep( 100 ); // Sleep for a while } return 0; } // Switch the pulser state void PulserDetector::switchState( const std::string pulserID, const short state ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; if( isReady() ) pulser->switchState( state ); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::switchState : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // Set pulse width for pulserID void PulserDetector::setWidth( const std::string pulserID, const unsigned width ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; if( isReady() ) pulser->setWidth( width ); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::setWidth : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // Set pulse frequency for pulserID void PulserDetector::setFrequency( const std::string pulserID, const double freq ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; if( isReady() ) pulser->setFrequency( freq ); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::setFrequency : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // Set the number of pulses for pulserID void PulserDetector::setNPulses( const std::string pulserID, const unsigned n ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; if( isReady() ) pulser->setNPulses( n ); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::setNPulses : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // Set pulse dealy for pulserID void PulserDetector::setDelay( const std::string pulserID, const unsigned delay ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; if( isReady() ) pulser->setDelay( delay ); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::setDelay : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } return; } // return status of the pulser pulserID short PulserDetector::getStatus( const std::string pulserID ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; return pulser->getStatus(); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::getStatus : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } } // return pulser width of the pulser pulserID unsigned PulserDetector::getWidth( const std::string pulserID ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; return pulser->getWidth(); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::getWidth : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } } // return pulsing frequency of the pulser pulserID double PulserDetector::getFrequency( const std::string pulserID ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; return pulser->getFrequency(); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::getFrequency : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } } // return number of pulses for the pulser pulserID unsigned PulserDetector::getNPulses( const std::string pulserID ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; return pulser->getNPulses(); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::getNPulses : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } } // return pulser delay of the pulser pulserID unsigned PulserDetector::getDelay( const std::string pulserID ) { if( pulserExists( pulserID) ) { VPulser* pulser = pdPulserMap[pulserID]; return pulser->getDelay(); } else { // throw an exception std::stringstream errStream; errStream << "PulserDetector::getDelay : Pulser object called " << pulserID << " does not exists" << " for detector " << pdName ; throw std::runtime_error( errStream.str()); } }