/* * moAsynPar.hh * * Created on: February 18, 2015 * Author: Hovanes Egiyan * * This file defines an augmenting class for asynMasterOscillatorDrv to keep track of asyn parameters. * Some of the methods of this class expect to receive the pointer of the asynMasterOscillatorDrv object * for which the parameter instance is used for. So, this class is very much tied to the * asynMasterOscillatorDrv class and should not be considered as "an" independent class, these objects expect * to be members of asynMasterOscillatorDrv class object. */ #ifndef __MO_ASYNPAR_HH__ #define __MO_ASYNPAR_HH__ /************/ /* Includes */ /************/ #include #include #include #include #include #include #include #include #include #include /* EPICS includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "new" #include "boost/function.hpp" #include "boost/bind.hpp" #include "MtxLock.hh" #include "MutexedClass.hh" #include "moVAsynPar.hh" using namespace std; // Template class for asyn parameters. For different parameters types we will // use specialized methods for particular variable types. This class inherits // from the virtual base class. template class moAsynPar: public moVAsynPar { protected: // Structure for passing parameters to thread for writing to the board struct WriteParameters { asynMasterOscillatorDrv* drvPtr; moAsynPar* parPtr; unsigned chanNum; VarType value; WriteParameters( asynMasterOscillatorDrv* dPtr, moAsynPar* pPtr, unsigned cNum, VarType v ) : drvPtr(dPtr), parPtr(pPtr), chanNum(cNum), value(v) {} }; // Condition variable for pausing thread static pthread_cond_t mapWaitSignal; static bool mapNoSingalProduced; // Parameter value VarType mapValue; // Read function boost::function mapReadFunc; // Write function boost::function mapWriteFunc; // Defines if this parameter is a signal producer or expector. There should be // only one signal producer parameter for each type of parameters. bool mapProducerFlag; unsigned mapWriteCount; //! Initialize global mutex int InitGlobalMutex() { MutexedClass::initGlobalMutex(); pthread_cond_init( &mapWaitSignal, NULL ); return 0; } public: // Default constructor moAsynPar() : mapValue() { return;} // Main constructor moAsynPar(string parName, int parNum, boost::function readFun, boost::function writeFun, bool flag = false ); virtual ~moAsynPar() { return; } // Copy constructor moAsynPar(const moAsynPar& par); // Copy operator virtual moAsynPar& operator=(const moAsynPar& argPar); // This function is executed in a thread to asynchronously write values to the hardware static void asynWriteFunc( void* ptr ) ; virtual VarType WriteInThread( asynMasterOscillatorDrv* drv, unsigned channel, VarType value ) ; // Method to create the parameter for the driver passed by the argument. // This method is expected to be called from the AsynDriver constructor virtual void Connect2Driver(asynMasterOscillatorDrv* driver); virtual asynStatus Write(asynMasterOscillatorDrv* driver, unsigned channel, void* valPtr = 0, epicsUInt32 mask = moVAsynPar::mvapAllBitMask); virtual asynStatus Read(asynMasterOscillatorDrv* driver, unsigned channel, void* valPtr = 0, epicsUInt32* mask = 0); // Return parameter value virtual VarType GetValue() ; // Set parameter value virtual VarType SetValue(const VarType value) ; // Return a copy of the read function virtual boost::function& GetReadFunc() ; // Return a copy of the write function virtual boost::function& GetWriteFunc() ; bool isSignalProducer() { return mapProducerFlag; } }; // Main constructor template moAsynPar::moAsynPar(string parName, int parNum, boost::function readFun, boost::function writeFun, bool flag ) : moVAsynPar(parName, parNum), mapValue(), mapReadFunc(readFun), mapWriteFunc(writeFun), mapProducerFlag(flag), mapWriteCount(0) { cout << "Created moAsynPar " << this->GetName() << " with flag " << (int)mapProducerFlag << endl; return; } // Copy constructor template moAsynPar::moAsynPar(const moAsynPar& par) : moVAsynPar(par), mapValue(par.mapValue), mapReadFunc(par.mapReadFunc), mapWriteFunc(par.mapWriteFunc ) { return; } // Assignment operator template moAsynPar& moAsynPar::operator=( const moAsynPar& argPar ) { if ( &argPar != this ) { moAsynPar& par = const_cast&>( argPar ); moVAsynPar* baseClassPtr = dynamic_cast( this ); baseClassPtr->operator=( par ); MtxLock selfObjLock( this->mcMutex ); MtxLock otherObjLock( par.mcMutex ); mapValue = par.mapValue; mapProducerFlag = par.mapProducerFlag; } return *this; } // This function simply calls the write function for a parameter stored in the structure // whose pointer is passed to this function. The parameter structure passed to this // method is delete by this method since the caller will move on and cannot delete the // parameter object on its own. template void moAsynPar::asynWriteFunc( void* ptr ) { if ( ptr != 0 ) { WriteParameters* parStruct = reinterpret_cast( ptr ); asynMasterOscillatorDrv* driver = parStruct->drvPtr; moAsynPar* parameter = parStruct->parPtr; unsigned channel = parStruct->chanNum; VarType value = parStruct->value; if( parStruct != 0 ) delete parStruct; parameter->WriteInThread( driver, channel, value ); } else { cout << "Pointer is 0" << endl; } return; } // Method that gets called from the static method to set the parameter value to // the hardware. Depending if it is a "signal producer" it will either broadcast // the signal or will wait for the signal. template VarType moAsynPar::WriteInThread( asynMasterOscillatorDrv* drvPtr, unsigned channel, VarType value ) { if ( mapProducerFlag ) { try { this->GetWriteFunc()( channel, value ); } catch ( runtime_error& errMsg ) { cerr << errMsg.what() << endl; return VarType(); } if ( mapWriteCount == 0 ) { VarType readValue; unsigned counter = 0; unsigned mask = moVAsynPar::mvapAllBitMask; this->Read( drvPtr, channel, &readValue, &mask ); while ( readValue != value && counter < 1000000 ) { this->Read( drvPtr, channel, &readValue, &mask ); usleep( 10 ); counter++; } MtxLock classLock( mcClassMutex ); mapNoSingalProduced = false; pthread_cond_broadcast( &mapWaitSignal ); classLock.Unlock(); mapWriteCount = 1; } } else if ( mapWriteCount == 0 ) { while ( mapNoSingalProduced ) { MtxLock classLock( mcClassMutex ); pthread_cond_wait( &mapWaitSignal, &mcClassMutex ); classLock.Unlock(); } } try { this->GetWriteFunc()( channel, value ); } catch ( runtime_error& errMsg ) { cerr << errMsg.what() << endl; return VarType(); } mapWriteCount = 1; return value; } template VarType moAsynPar::GetValue() { MtxLock objLock(this->mcMutex); return mapValue; } template VarType moAsynPar::SetValue(const VarType value) { MtxLock objLock(this->mcMutex); return (mapValue = value); } template inline boost::function& moAsynPar::GetReadFunc() { MtxLock objLock(this->mcMutex); return mapReadFunc; } template inline boost::function& moAsynPar::GetWriteFunc() { MtxLock objLock(this->mcMutex); return mapWriteFunc; } // define the static member template pthread_cond_t moAsynPar::mapWaitSignal; // define the static member template bool moAsynPar::mapNoSingalProduced = true;; #endif /* __MO_ASYNPAR_HH__ */