#ifndef _Brooks0254Par_ #define _Brooks0254Par_ #include "Brooks0254BasePar.hh" #include "Brooks0254Card.hh" // Typed class for Brooks0254 parameters for cards // All method lock the object and unlock when complete or // when calling another method which locks the object template class Brooks0254Par : virtual public Brooks0254BasePar { protected: unsigned bpCardNum; //! Card Number VarType bpWriteVal; //! Parameter value from the opratator VarType bpReadVal; //! Parameter value from the device string MakeReadString(); string MakeWriteString( VarType val ); int String2Int( string str ); // Convert to integer for port type string Int2String( unsigned char val ) ; // Convert to string for port type VarType FetchValue(); // Read value from device VarType WriteValue( VarType val ); // Write value to device inline bool CommIsOK() {return 1;} public: Brooks0254Par( Brooks0254Card& card, Brooks0254ParID parID ) : Brooks0254Module( card ), Brooks0254BasePar( card, parID ), bpCardNum(card.GetCardNum()), bpWriteVal(0), bpReadVal(0) { Brooks0254Par::Sync(1); } Brooks0254Par( Brooks0254Par& par ) : Brooks0254BasePar(par), bpCardNum(par.bpCardNum), bpWriteVal(par.bpWriteVal), bpReadVal(par.bpReadVal) {;} Brooks0254Par& operator=( const Brooks0254Par& par ); //! Return the Brooks port number based on the card number and the //! direction of the port. unsigned BrooksPortNumber(); //! Method to synchronize the values in the driver and the hardware void Sync( bool dir = 0 ); //! Paramters with numbers less than 100 are writable inline bool IsWritable() { MtxLock scopeLock( bmMutex ); if( bbpID.GetNum() < 100 ) return 1; else return 0; } //! Return the card number this parameter belongs to inline unsigned GetCardNum() { MtxLock scopeLock( bmMutex ); return bpCardNum; } inline VarType GetReadValue( ) { MtxLock scopeLock( bmMutex ); return bpReadVal; } inline VarType GetWriteValue( ) { MtxLock scopeLock( bmMutex ); return bpWriteVal; } //! Chanage the card number for this parameter inline unsigned SetCardNum( const unsigned num ) { MtxLock scopeLock( bmMutex ); return( bpCardNum = num ); } inline VarType SetReadValue( const VarType val ) { MtxLock scopeLock( bmMutex ); return ( bpReadVal = val ); } inline VarType SetWriteValue( const VarType val ) { MtxLock scopeLock( bmMutex ); return ( bpWriteVal = val ); } }; //! Begining of the template class implementation //! Copy operator template Brooks0254Par& Brooks0254Par::operator=( const Brooks0254Par& par ) { if( this == &par ) return *this; Brooks0254BasePar::operator=( par ); MtxLock scopeLock( bmMutex ); bpCardNum = par.GetCardNum(); bpWriteVal = par.bpWriteVal; bpReadVal = par.bpReadVal; return (*this); } //! Return the Brooks port number based on the card number and the //! direction of the port. template unsigned Brooks0254Par::BrooksPortNumber() { MtxLock scopeLock( bmMutex ); int offset = 0; if( bbpID.GetDir() == Brooks0254ParID::bpiInput ) { offset = 1; } else if( bbpID.GetDir() == Brooks0254ParID::bpiOutput ) { offset = 2; } return (2 * bpCardNum + offset); } //! This method cheks if the set value is different from the readback, //! and if it is theb it sets the new value into the hardware. //! syncDir == 0 - normal synchronization (driver -> hardware ) //! suncDir == 1 - inverse synchronization (hardware -> driver) template void Brooks0254Par::Sync( bool syncDir ) { //! Always read value from the hardware for all parameters VarType tmpVal = FetchValue(); bool parIsWritable = IsWritable(); //! Parameter is no PV readback MtxLock scopeLock( bmMutex ); bpReadVal = tmpVal; unsigned parNum = bbpID.GetNum() ; if( bmDebFlag > 1 ) { cout << "Read " << bpReadVal << " for parameter " << parNum << endl; cout << "Difference is " << bpWriteVal - bpReadVal << endl; } //! Check the difference between the value in the driver and in the //! actual hardware and sync them for settable parameters. if( parIsWritable && fabs( bpWriteVal - bpReadVal ) > bbpID.GetTolerance() ) { if( syncDir == 0 ) { //! Set values for updatable parameters cout << "**************************************************" << endl; cout << "Updating parameter " << parNum << " on card " << bpCardNum << endl; cout << "Old value is " << bpReadVal << " , new value " << bpWriteVal << endl; cout << "**************************************************" << endl; scopeLock.Unlock(); VarType newVal = WriteValue( bpWriteVal ); scopeLock.Lock(); bpReadVal = newVal; } else { //! Initilize the parameters from the hardware scopeLock.Unlock(); VarType newVal = FetchValue(); scopeLock.Lock(); bpWriteVal = bpReadVal = newVal; if( bmDebFlag > 1 ) { cout << "Starting with hardware values " << bpReadVal << " for parameter " << parNum << endl; } } } if( bmDebFlag ) cout << "Brooks0254Par::Sync(): Parameter #" << parNum << " is unlocked" << endl; return; } //! Fetch the bool and int value of the parameter from the device template VarType Brooks0254Par::FetchValue() { string readString = MakeReadString(); MtxLock scopeLock( bmMutex ); unsigned parNum = bbpID.GetNum() ; if( bmDebFlag ) { cout << "FetchValue: Paramter " << parNum << " is locked" << endl; cout << "Port address is " << bmPort << endl; } //! Send the string to the device using the serial port object string respRaw = bmPort->Send( readString, true ); if( bmDebFlag ) cout << "Raw response " << respRaw << endl; string response = RemoveComas( respRaw ); if( bmDebFlag ) cout << "Final response " << response << endl; // Dummy variable for reading message char d1[128], d2[128], d3[128], d4[128], d5[128], d6[128], d7[128], d8[128], d9[128], d10[128], d11[128]; VarType val; stringstream ssResp; ssResp << response; if( parNum== 0 ) { //! For the "port type" parameter (par #0), only the leftmost digit //! in the decimal represntation matters. We need to strip the //! remaining digits on the right. Also there is a possibility to //! have non-digit characters for parameter #0 for input port //! type, so special string manipulation are needed for this parameter. char chResp[128]; ssResp >> d1 >> d2 >> d3 >> d4 >> chResp >> d5; val = static_cast( String2Int( chResp ) ); } else if( parNum > 100 ) { //! For PV related non-writable values we issued the "K" command //! and have to read all three variables from a single //! string. These parameters are given fake number above 100. double chResp[100]; ssResp >> d1 >> d2 >> d3 >> chResp[0] >> chResp[1] >> chResp[2] >> d5 >> d6 >> d7 >> d8 >> d9 >> d10 >> d11; val = static_cast( chResp[parNum - 101] ); } else { //! For all other parameters directly read off the value from the //! response string ssResp >> d1 >> d2 >> d3 >> d4 >> val >> d5; } return static_cast ( val ); } // Write the value of the parameter into the device template VarType Brooks0254Par::WriteValue( VarType val ) { if( bbpID.BadRange( val ) ) { cerr << "Brooks0254Par::WriteValue(): Bad value for parameter type <" << bbpID.GetDir() << "," << bbpID.GetNum() << ">" << endl; return FetchValue(); } string writeString = MakeWriteString( val ); bmPort->Send( writeString, true ); return FetchValue(); } //! Create the string to request a readout template string Brooks0254Par::MakeReadString() { unsigned chanPort = BrooksPortNumber(); MtxLock scopeLock( bmMutex ); unsigned parNum = bbpID.GetNum() ; char tmpChar[256]; if( parNum < 100 ) { sprintf( tmpChar, "AZ%05d.%02dP%02d?", bmAddr, chanPort, parNum ); } else { sprintf( tmpChar, "AZ%05d.%02dK", bmAddr, chanPort ); } return string( tmpChar ); } //! This fucntion should work with booleans and integers template string Brooks0254Par::MakeWriteString( VarType val ) { unsigned chanPort = BrooksPortNumber(); MtxLock scopeLock( bmMutex ); stringstream ssMsg; ssMsg << "AZ" << setw(5) << setfill('0') << bmAddr << "." << setw(2) << chanPort << "P" << bbpID.GetNum() << "="; if( bbpID.GetNum() == 0 ) { //! For port-type parameter (par #0) manipulate strings because //! for input port type there is a need for a non-digit character. string valStr = Int2String( static_cast( val ) ); ssMsg << valStr << "0" << ( chanPort - 1 ) ; cout << "Par 0 string is " << ssMsg.str() << endl; } else { //! For all other parameters directly write value into the string stream ssMsg << setfill(' ') << setprecision(bbpDecPoint) << fixed << val; } cout << "Build the follwoing message " << ssMsg.str() << endl; return string( ssMsg.str() ); } //! A function to convert the first character of the string to integer //! number that corresponds to it. '0' (ASCII 48) corresponds to 0. template int Brooks0254Par::String2Int( string str ) { return static_cast( str[0] - 48 ); } //! A fucntion to covert integer value to corresponding string //! according to the ASCII table. 0 sill correspond to "0", and 10 //! will correspond to ":" template string Brooks0254Par::Int2String( unsigned char val ) { unsigned char asciiCode = val + 48; stringstream ssOut; ssOut << asciiCode; return ssOut.str(); } #endif