#include "Brooks0254Chassis.hh" #include "Brooks0254Par.hh" #include "Brooks0254GlobPar.hh" //! Number of card in Brooks0254 is 4. At this point this is the //! maxumal configuration of this hardware. const unsigned Brooks0254Chassis::bcCardMax = 4; int Brooks0254Chassis::bcDummyInt = Brooks0254Chassis::InitGlobalMutex(); //! Constructor to create a new object and open new serial port. After //! creating the serial port object it creates the Brooks0254Card //! objects correponding to the cards in this Brooks0254 chassis. Brooks0254Chassis::Brooks0254Chassis( unsigned portID, unsigned addr, string devName ) : Brooks0254Module( addr ) { if( bmDebFlag > 1 ) cout << "Started constructing chassis #" << portID << endl; MtxLock scopeLock( bmMutex ); //! Create the serial communication port object bmPort = new Brooks0254Port( portID, devName ); bool commFlag = false; scopeLock.Unlock(); commFlag = CommIsOK(); scopeLock.Lock(); if( bmDebFlag > 1 ) { cout << "Chassis #" << portID << " will create the cards " << endl; cout << "Chassis port address is " << bmPort << endl; } //! Create all cards for( unsigned iCard = 0; iCard < bcCardMax; iCard++ ) { scopeLock.Unlock(); Brooks0254Card* cardPtr = new Brooks0254Card( *this, iCard ); bcCard.push_back( cardPtr ); scopeLock.Lock(); } //! Create global parameters //! Zero Supression { scopeLock.Unlock(); Brooks0254ParID parID( Brooks0254ParID::bpiGlobal, 32 ) ; Brooks0254GlobPar* newPar = new Brooks0254GlobPar( *this, parID ) ; scopeLock.Lock(); bcPar[parID] = newPar ; } //! SetPoint Clear { scopeLock.Unlock(); Brooks0254ParID parID( Brooks0254ParID::bpiGlobal, 33 ) ; Brooks0254GlobPar* newPar = new Brooks0254GlobPar( *this, parID ) ; scopeLock.Lock(); bcPar[parID] = newPar ; } //! Audio Beep { scopeLock.Unlock(); Brooks0254ParID parID( Brooks0254ParID::bpiGlobal, 39 ) ; Brooks0254GlobPar* newPar = new Brooks0254GlobPar( *this, parID ) ; scopeLock.Lock(); bcPar[parID] = newPar ; } if ( bmDebFlag > 1 ) cout << "Finished constructing chassis #" << portID << endl; return; } //! Copy constructor Brooks0254Chassis::Brooks0254Chassis( Brooks0254Chassis& chassis ) : Brooks0254Module( chassis ) { MtxLock localLock( bmMutex ); bcCard = chassis.GetCardVector(); return; } //! Destructor is expected to be called after the thread corresponding //! to this instance is already stopped. A this point all it needs to //! do is to close the serial port if it is open. Brooks0254Chassis::~Brooks0254Chassis() { cout << "Entering Chassis destructor " << endl; { MtxLock localLock( bmMutex ); if( bmPort != 0 ) delete bmPort; } cout << "Chassis destruction done" << endl; return; } //! Copy operator for the chassis Brooks0254Chassis& Brooks0254Chassis::operator=( Brooks0254Chassis& chassis ) { if( this == &chassis ) return *this; Brooks0254Module::operator=( chassis ); MtxLock scopeLock( bmMutex ); bcCard = chassis.GetCardVector(); return *this; } //! Send "AZI" identification message to the device requiring the device to report back. //! Then checks the size of the readback string, and if it is zero //! return false value because this would mean that the checksum //! received did not match the checksum of the message read back. bool Brooks0254Chassis::CommIsOK() { if( bmDebFlag > 1 ) cout << "Checking serial port #" << bmPort->GetID() << endl; bool portOK = true; MtxLock scopeLock( bmMutex ); //! Create the synchronization string to terminate commands on the //! Brook device and put it into the initial state stringstream ssClear; ssClear << static_cast(27) << string( "AZ" ) ; string strClear = ssClear.str(); bmPort->Send( strClear, false ); usleep( Brooks0254Port::bpWriteDelay ) ; string strID = "AZI"; string readBack = bmPort->Send( strID, true ); if( readBack.empty() ) portOK = false; if( bmDebFlag > 1 ) cout << "Response was " << readBack << endl; return portOK; } //! Sync the particular chassis with the hardware. It loops over all //! cards and calls Sync method of each card, which is supposed to //! chain down to every parameter in the chassis. void Brooks0254Chassis::Sync( bool dir ) { bool commFlag = false; try { commFlag = CommIsOK(); MtxLock scopeLock( bmMutex ); bcCommStatus = commFlag; } catch ( Brooks0254Port::FailedWritePort& err ) { cerr << err.msg << endl; return; } catch ( Brooks0254Port::FailedReadPort& err ) { cerr << err.msg << endl; return; } if( commFlag ) { Brooks0254Card* cardPtr = 0; if( bmDebFlag > 1 ) cout << "Looping through chassis cards " << endl; for( unsigned iCard = 0; iCard < bcCardMax; iCard++ ) { { MtxLock scopeLock( bmMutex ); cardPtr = bcCard[iCard]; } //! Chain the Sync method all the way down to the cards and //! parameters. If there are comm-related exceptions, catch them //! here, write an error message and return. try { if( cardPtr != 0 ) cardPtr->Sync(); } //! Catch exceptions and return to the Loop which called the //! sync methods for the chassis objects. Do not take any action //! here, the communications will be checked upstream. catch ( Brooks0254Port::FailedWritePort err ) { cerr << err.msg << endl; MtxLock scopeLock( bmMutex ); bcCommStatus = false; return; } catch ( Brooks0254Port::FailedReadPort err ) { cerr << err.msg << endl; MtxLock scopeLock( bmMutex ); bcCommStatus = false; return; } } //! Now loop through the global parameters and synchronize them if ( bmDebFlag > 1 ) cout << "Looping through chassis parameters" << endl; map::iterator it; map::iterator itBegin; map::iterator itEnd; { MtxLock scopeLock( bmMutex ); itBegin = bcPar.begin(); itEnd = bcPar.end(); } for( it = itBegin; it != itEnd; it++ ) { Brooks0254BasePar* parPtr = it->second; try { if( parPtr != 0 ) parPtr->Sync(); } //! Catch exceptions and return to the Loop which called the //! sync methods for the chassis objects. Do not take any action //! here, the communications will be checked upstream. catch ( Brooks0254Port::FailedWritePort err ) { cerr << err.msg << endl; MtxLock scopeLock( bmMutex ); bcCommStatus = false; return; } catch ( Brooks0254Port::FailedReadPort err ) { cerr << err.msg << endl; MtxLock scopeLock( bmMutex ); bcCommStatus = false; return; } } } else { cerr << "Brooks0254Chassis::Loop(): Lost communication with the chassis #" << bmPort->GetID() << " on device " << bmPort->GetDevice() << endl; } return; } //! Start or stop Batch delivery mode. //! No continuous readback is available int Brooks0254Chassis::SetBatchMode( int mode ) { //! Count how many cards are in batch mode in this chassis //! This number is needed to specify the number of response lines //! from the serial interface Brooks0254ParID batchParID( Brooks0254ParID::bpiOutput, 2 ) ; int nBatchCard = 0; for( unsigned iCard = 0; iCard < bcCard.size(); iCard++ ) { Brooks0254Card* cardPtr = GetCard( iCard ); if( cardPtr != 0 ) { Brooks0254Par* parPtr = dynamic_cast*> ( cardPtr->GetPar( batchParID ) ); if( parPtr != 0 ) if( parPtr->GetReadValue() == 2 ) nBatchCard++; } } if( bmPort != 0 ) { try { if( mode == 1 ) { //! Start Batch mode cout << "Starting batch on chassis #" << bmPort->GetID() << endl; cout << "Will read " << nBatchCard << " lines" << endl; bmPort->Send( "AZF*", true, nBatchCard ); } else { //! Stop batch mode cout << "Stopping batch on chassis #" << bmPort->GetID() << endl; cout << "Will read " << nBatchCard << " lines" << endl; bmPort->Send( "AZF", true, nBatchCard ); } cout << "Batch mode has been set to " << mode << endl; return 0; } //! Catch exceptions, print messages and return to IOC catch ( Brooks0254Port::FailedWritePort err ) { cerr << err.msg << endl; return -1; } catch ( Brooks0254Port::FailedReadPort err ) { cerr << err.msg << endl; return -1; } } return -2; } Brooks0254BasePar* Brooks0254Chassis::GetPar( Brooks0254ParID& parID ) { MtxLock localLock( bmMutex ); Brooks0254BasePar* tmpPar = bcPar[parID]; return tmpPar ; }