/* File: drvuScopeBias.cpp * Author: Hovanes Egiyan, Jefferson Lab * Date: 10-Jan-2014 * * Purpose: * This module provides the driver support for the asyn device support layer * for the UConn microscope biases. * * */ #include "drvuScopeBias.hh" #include "drvuScopeBiasBoard.hh" //! Declare global mutex and its attributes pthread_mutex_t drvuScopeBias::dubClassMutex; pthread_mutexattr_t drvuScopeBias::dubClassMtxAttr; //! Initialize global mutex and its attributes static int dummyInt = drvuScopeBias::initGlobalMutex(); string drvuScopeBias::dubbDriverName = "asynuScopeBias"; // The name of this driver string drvuScopeBias::dubPortName = "GlobalPortUConnBias"; // Asyn port name for the global port string drvuScopeBias::dubDirDB = "db/"; // Directory prefix string drvuScopeBias::dubFileNameDB = "uScopeBias.db"; // Template DB file name drvuScopeBias* drvuScopeBias::dubInstancePtr = 0; // The only instance of this object type /*Constructor */ drvuScopeBias::drvuScopeBias() : asynPortDriver( dubPortName.c_str(), 1, NUM_USCOPE_BIAS_PARAMS, asynInt32Mask | asynDrvUserMask | asynCommonMask | asynOptionMask, asynInt32Mask | asynDrvUserMask | asynCommonMask | asynOptionMask, ASYN_CANBLOCK, 1, 0, 0 ) // 0, 1, 0, 0 ) { static const char* functionName = "drvuScopeBias::drvuScopeBias"; cout << "In function " << functionName << endl; initMutex(); { MtxLock scopeLock( dubMutex ); this->dubEventID = epicsEventCreate( epicsEventEmpty ); createParam( uScopeBiasBoardNumberString , asynParamInt32 , &uScopeBiasBoardNumber_ ); /* unsigned, RO */ } // Uncomment this line to enable asynTraceFlow during the constructor // pasynTrace->setTraceMask( pasynUserSelf, 0x11 ); pasynTrace->setTraceMask( pasynUserSelf, 0x255 ); int status = 0; /* Create the thread that reads the values from the registers in the background */ status = (asynStatus)( epicsThreadCreate("UCONN_BIAS", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC) ::readBiasParameters, this) == NULL); if ( status ) { printf( "%s:%s: epicsThreadCreate failure\n", dubbDriverName.c_str(), functionName ); return; } cout << "Finished " << functionName << endl; return; } // Destructor drvuScopeBias::~drvuScopeBias() { MtxLock classLock( dubClassMutex ); closeMutex(); return; } // Return the only instance of the class drvuScopeBias* drvuScopeBias::getInstance() { if( dubInstancePtr == 0 ) { MtxLock classLock( dubClassMutex ); dubInstancePtr = new drvuScopeBias(); } return dubInstancePtr; } /* Report parameters */ void drvuScopeBias::report( FILE *fp, int details ) { if ( details > 0 ) { // fprintf(fp, " Scratch Content = 0x%x\n", MPODSratch_ ); } // Call the base class method asynPortDriver::report( fp, details ); return; } // This function reads the registers and calls the callbacks // It is supposed to run in a separate thread for each board // Because the registers are read here we do not need to read // in our new readUInt32Digital function, just call the base version in // case the SCAN field is set to some fixed rate scanning. // The values read here will be moved to th appropriate records. void drvuScopeBias::readBiasParameters( void ) { asynStatus aStat ; // Set updating time to value in seconds double updateTime = 2.0; // while( taskDelay(sysClkRateGet()) ) { while( 1 ) { epicsEventId eventID; { MtxLock scopeLock( dubMutex ); eventID = this->dubEventID; } epicsEventWaitWithTimeout( eventID, updateTime ); // usleep( 100000 ); // if (run) epicsEventWaitWithTimeout(this->eventId, updateTime); // else epicsEventWait(this->eventId); // /* run could have changed while we were waiting */ // getIntegerParam(P_Run, &run); // if (!run) continue; MtxLock scopeLock( dubMutex ); aStat = setIntegerParam( uScopeBiasBoardNumber_, drvuScopeBiasBoard::getPortMap().size() ); callParamCallbacks(); } } // Method to first load the global DB records, then call methods to // load DB records for each boards int drvuScopeBias::loadRecords() { { MtxLock classLock( dubClassMutex ); // First load global records string substitString = "PORT=" + drvuScopeBias::dubPortName; string fullFileName = dubDirDB + dubFileNameDB; cout << "Will load from " << fullFileName << endl; dbLoadRecords(fullFileName.c_str(), substitString.c_str()); } cout << "Global Database loaded" << endl; // Now load records for each boards map boardPortMap = drvuScopeBiasBoard::getPortMap(); cout << "Got iterators" << endl; for( map::iterator it = boardPortMap.begin(); it != boardPortMap.end(); it++ ) { drvuScopeBiasBoard* boardPtr = it->second; boardPtr->loadRecords(); } cout << "Finished loading DBs for all boards" << endl; return 0; } // Mutex manipulation functions //! Initialize global mutex int drvuScopeBias::initGlobalMutex() { pthread_mutexattr_init( &dubClassMtxAttr ); pthread_mutexattr_setpshared( &dubClassMtxAttr, PTHREAD_PROCESS_PRIVATE ); pthread_mutexattr_settype(&dubClassMtxAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init( &dubClassMutex, &dubClassMtxAttr ); return 0; } //! Initialize mutex for individual objects void drvuScopeBias::initMutex() { pthread_mutexattr_init( &dubMtxAttr ); pthread_mutexattr_setpshared( &dubMtxAttr, PTHREAD_PROCESS_PRIVATE ); pthread_mutexattr_settype(&dubMtxAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init( &dubMutex, &dubMtxAttr ); return; } //! Destroy mutex for individual objects void drvuScopeBias::closeMutex() { pthread_mutex_destroy( &dubMutex ); pthread_mutexattr_destroy( &dubMtxAttr ); return; } // This function simply calls the member function of the driver whose pointer // is passed as the argument. This function is to be called from a separate // thread and is specified in the argument when launching that thread void readBiasParameters( void *drvPtr ) { drvuScopeBias* pPtr = (drvuScopeBias *)drvPtr; pPtr->readBiasParameters(); } // Here we define IOC shell function calls extern "C" { int dbLoadRecordsUConnBias( const char* dummy ) { drvuScopeBias* instancePtr = drvuScopeBias::getInstance(); return instancePtr->loadRecords(); } /* iocsh config function */ static const iocshArg dbLoadRecordsUConnBiasArg0 = { "Crate IP Address", iocshArgString }; static const iocshArg * const dbLoadRecordsUConnBiasArgs[] = { &dbLoadRecordsUConnBiasArg0 }; static const iocshFuncDef dbLoadRecordsUConnBiasFuncDef = { "dbLoadRecordsUConnBias", 1, dbLoadRecordsUConnBiasArgs}; static void dbLoadRecordsUConnBiasCallFunc(const iocshArgBuf *args) { dbLoadRecordsUConnBias( args[0].sval ); } void drvuScopeBiasRegister(void) { iocshRegister( &dbLoadRecordsUConnBiasFuncDef, dbLoadRecordsUConnBiasCallFunc ); } epicsExportRegistrar( drvuScopeBiasRegister ); } // extern "C"