/* Copyright (c) 20011 Hovanes Egiyan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "BaseIUParStatus.hh" using namespace std; //! Parameter type for STATUS parameters on the board const string BaseIUParStatus::bpsParType = "STATUS"; //! Parameter name, its one for all pins. Different pins will //! be dealt with through member functions. //const string BaseIUParStatus::bpsParName = "PINS"; //! Command byte for request for STATUS readback for IU boards const int BaseIUParStatus::bpsComndByte = 0x99 ; //! Map describing extra byte for different parameters names for //! STATUS type of parameters when sending to the devices map > BaseIUParStatus::bpsExtraByteMap; //! Map describing the mask for retrieval of the statuses for //! different pins. map BaseIUParStatus::bpsPinMaskMap; //! Do not allow any bits for the JAM pins. This way will //! be able to turn on or off any JAM bits. uint16_t BaseIUParStatus::bpsWriteProtectionMask = 0xFF00; static volatile int bpsDummyInt = BaseIUParStatus::InitMaps(); //! Main constructor BaseIUParStatus::BaseIUParStatus( string name, BaseIUModule& board ) : BaseIUVirtPar( bpsParType, name, board ), bpsReadValue(0x00), bpsWriteValue(0x0000) { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::BaseIUParStatus() : Main constructor is invoked " << " for STATUS parameter at address " << bmAddress << endl; cout << "BaseIUParStatus object is at " << hex << showbase << this << endl; } bvpWriteBuffer = reinterpret_cast( &bpsWriteValue ) ; return; } //! Short constructor BaseIUParStatus::BaseIUParStatus( string name ) : BaseIUVirtPar( bpsParType, name ), bpsReadValue(0x00), bpsWriteValue(0x0000) { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::BaseIUParStatus() : Short constructor is invoked " << " for STATUS parameter named at address " << bmAddress << endl; cout << "BaseIUParStatus object is at " << hex << showbase << this << endl; } bvpWriteBuffer = reinterpret_cast( &bpsWriteValue ) ; return; } //! Copy constructor BaseIUParStatus::BaseIUParStatus( const BaseIUParStatus& par ) : BaseIUVirtPar ( par ) { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::BaseIUParStatus() : Copy constructor is invoked" << endl; cout << "BaseIUParStatus object is at " << hex << showbase << this << endl; } *this = operator=( par ); MtxLock objLock( bmMutex ); bvpWriteBuffer = reinterpret_cast( &bpsWriteValue ) ; return; } //! Class destructor BaseIUParStatus::~BaseIUParStatus() { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::~BaseIUParStatus() : Destructor for STATUS parameter " << bvpType << " : " << bvpName << " has been called" << endl; } } //! Assignment operator BaseIUParStatus& BaseIUParStatus::operator=( const BaseIUParStatus& constPar ) { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::operator=() : Assignment operator is called" << endl; } //! Do not do anything if assigned to itself if( this == &constPar ) return *this; //! Call the assignment operator for the base class BaseIUVirtPar::operator=( constPar ); BaseIUParStatus& par = const_cast( constPar ); MtxLock objLock( bmMutex ); bpsReadValue = par.GetReadValue(); bpsWriteValue = par.GetWriteValue(); objLock.Unlock(); return *this; } //! Cloning function defined for polymorphism for copy constructor //! Invokes the copy constructor for this class and returns the //! the address of the resulting object BaseIUVirtPar* BaseIUParStatus::CloneParameter() { if( bmDebFlag > 5 ) { cout << "BaseIUParStatus::CloneParameter() : Cloning STATUS parameter " << " named " << bvpName << endl; } BaseIUParStatus* tmpPar = new BaseIUParStatus( *this ) ; return dynamic_cast( tmpPar ); } //! Request read of this STATUS for all boards on the bus void BaseIUParStatus::ReadRequest( BaseIUDevice* dev, string name ) { if( bmDebFlag > 1 ) { cout << "BaseIUParStatus::ReadRequest() : Requesting readback for parameters " << bvpType << " : " << name << endl; } //! The extra bytes for reading status is 0x00 0x00 as defined in //! writeup by C. Tarbert BaseIUMessage cmd; cmd << BaseIUMessage( bpsComndByte ) << BaseIUMessage( 0x00 ) << BaseIUMessage( 0x00 ); if( bmDebFlag > 1 ) { cout << "Will send message : <" << cmd << "> for all boards" << endl; } dev->Send( 0, cmd ); return; } // Set the write values for this object from the write value of another parameter. // It is assumed that the two parameters are of the same class, otherwise the // program will seg. fault. void BaseIUParStatus::SetWriteValueFrom( BaseIUVirtPar& fakePar ) { uint16_t* tmpValue = reinterpret_cast( fakePar.GetWriteBuffer() ); cout << "BaseIUParStatus::SetWriteValueFrom : Write value was " << bpsWriteValue << endl; MtxLock objLock( bmMutex ); bpsWriteValue = *tmpValue; cout << "BaseIUParStatus::SetWriteValueFrom : Write value set to " << bpsWriteValue << endl; return; } //! Method to synch the status parameter bool BaseIUParStatus::Sync(bool syncFromHW) { if (bmDebFlag > 1) { cout << "BaseIUParStatus::Sync() : Synching parameter " << bvpType << " : " << bvpName << " for address " << bmAddress << endl; } //! Process FIFO and assign the readout value bool syncSuccessful = ProcessDeque( true ); // cout << "BaseIUParStatus::Sync() : Syncing parameter " << bvpType // << " : " << bvpName << " for address " << bmAddress << " on port " << bmDevice->GetPortName() // << " HW sync flag is " << syncFromHW << endl; // cout << "Last value read is " << (int)bpsReadValue << "(" << ReadToWrite(bpsReadValue) << // ") , requested write value is " << bpsWriteValue << endl; if (syncFromHW) { //! If sync from hardware requested set the write value to the //! value that matches the pin statuses read from the hardware // cout << "Synching from HW for address " << bmAddress << " on port " << bmDevice->GetPortName() << endl; uint16_t newWriteVal = ReadToWrite(bpsReadValue); if (bmDebFlag > 1) { cout << "BaseIUParStatus::Sync() : Requested to sync from hardware" << endl; cout << "BaseIUParStatus::Sync() : Will change the existing write value " << bpsWriteValue << " to " << newWriteVal << endl; } MtxLock objLock( bmMutex ); bpsWriteValue = newWriteVal; } else { //! Write to hardware if Sync is not requested from the hardware to the driver //! If the status word is different in the driver and hardware //! write to hardware. if (!BitsMatch(bpsReadValue, bpsWriteValue)) { BaseIUMessage cmdMsg; cmdMsg << BaseIUCommand::HV_INIT; cmdMsg << ((bpsWriteValue & 0xFF00) >> 8); // separate the first byte cmdMsg << (bpsWriteValue & 0x00FF); // separate the second byte if (bmDebFlag > 1) { cout << "BaseIUParStatus::Sync() : Will write by sending message " << cmdMsg << " to address " << bmAddress << endl; cout << "Write two-byte value is " << bpsWriteValue << endl; } // cout // << "BaseIUParStatus::Sync() : Will write by sending message " // << cmdMsg << " to address " << bmAddress << endl; // cout << "Write two-byte value is " << bpsWriteValue << endl; //! Send the command bmDevice->Send(bmAddress, cmdMsg); // bmDevice->Sleep(); } else { if (bmDebFlag > 1) { cout << "BaseIUParStatus::Sync() : There was not need to write" << endl; } } } return syncSuccessful; } //! Get the deque after sending read request and process it to //! retrieve the parameter value on the board. If there was not //! message found then the return value is false. Otherwise it is true. bool BaseIUParStatus::ProcessDeque( bool clearFlag ) { if( bmDebFlag > 1 ) { cout << "BaseIUParStatus::ProcessDeque() : Processing deque for parameter " << bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << endl; } bool msgFound = false; //! Get all messages for this address from the FIFO, and remove them from //! the FIFO. Since each parameter is processed at a time there should not //! be messages for this address related to other parameters. deque msgDeque = bmDevice->GetDeque( bmAddress, clearFlag ); if( msgDeque.size() < 1 ) { if( bmDebFlag > 1 ) { cout << "BaseIUParStatus::ProcessDeque() : Received empty deque" << endl; } return msgFound; } //! Loop through the messages and if the command byte matches, //! read the status for( unsigned iMsg = 0; iMsg < msgDeque.size(); iMsg++ ) { BaseIUMessage& msg = msgDeque[iMsg]; //! Check that the command byte in the message is the same as the //! command byte for this parameter. The opposite should not happen, //! so this is more of a precaution measure. if( msg[0] == BaseIUParStatus::bpsComndByte ) { int statusVal = msg[1]; MtxLock objLock( bmMutex ); bpsReadValue = statusVal; // cout << "Read Status value of " << hex << (int)bpsReadValue << " (" << ReadToWrite(bpsReadValue) << ") for parameter " << // bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << " on port " << bmDevice->GetPortName() <( statusVal ); msgFound = true; } } if( bmDebFlag > 1 ) { cout << "BaseIUParStatus::ProcessDeque() : Read value " << static_cast( bpsReadValue )<< " for parameter " << bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << " on port " << bmDevice->GetPortName() << endl; } return msgFound; } //! Initialize the maps for STATUSes int BaseIUParStatus::InitMaps() { if (bmDebFlag > 1) { cout << "BaseIUParStatus::InitMaps() : Initializing maps for STATUS parameters" << endl; } //! These are the enable/disable two-byte pairs for various pins. //! When sent to the board, the two-bytes are split into two separate //! bytes then sent out via the message class. //! The first in the pair is the enable combination for the pin, //! the second in the pair is the disable combination for the bin. //! These parameters are defined in the write up by C.Tarbert bpsExtraByteMap["MVB"] = pair(0x1100, 0x1000); //! medium voltage bottom bpsExtraByteMap["MVT"] = pair(0x2200, 0x2000); //! medium voltage top bpsExtraByteMap["HVB"] = pair(0x4400, 0x4000); //! High voltage bottom bpsExtraByteMap["HVT"] = pair(0x8800, 0x8000); //! High voltage top bpsExtraByteMap["HVA"] = pair(0xFF00, 0xF000); //! All HV pins except JAM bpsExtraByteMap["JVB"] = pair(0x0005, 0x0004); //! JAM High voltage bottom bpsExtraByteMap["JVT"] = pair(0x000A, 0x0008); //! JAM High voltage top bpsExtraByteMap["JVA"] = pair(0x000F, 0x000C); //! All JAM HV pins //! These are the masks for retrieving the statuses for pins //! The value for these masks is taken from the IU code. bpsPinMaskMap["MVB"] = 0x40; //! medium voltage bottom bpsPinMaskMap["MVT"] = 0x80; //! medium voltage top bpsPinMaskMap["HVB"] = 0x10; //! High voltage bottom bpsPinMaskMap["HVT"] = 0x04; //! High voltage top bpsPinMaskMap["HVA"] = 0xD4; //! All HV pins except JAM bpsPinMaskMap["JVB"] = 0x20; //! JAM High voltage bottom bpsPinMaskMap["JVT"] = 0x08; //! JAM High voltage top bpsPinMaskMap["JVA"] = 0x28; //! All JAM HV pins return 0; } //! Return pin status from the board. If the pin name does not exist in //! pin mask map it will return "false",which means OFF. bool BaseIUParStatus::GetPinStatus( const string pinName ) { bool pinExist = false; uint8_t pinMask = 0x00; { MtxLock globLock( bmGlobMutex ); pinExist = ( bpsPinMaskMap.count( pinName ) > 0 ); if( pinExist ) pinMask = bpsPinMaskMap[ pinName ]; } if( pinExist ) { MtxLock localLock( bmMutex ); return ( ( bpsReadValue & pinMask ) == pinMask ) ; } else { return false; } } //! Set the value for the status word which will be written out to //! the board based on the requested status for a particular pin. uint16_t BaseIUParStatus::SetPinStatus(const string pinName, const bool status) { if (bmDebFlag > 1) { cout << "BaseIUParStatus::SetPinStatus() : Setting pin " << pinName << " to " << status << endl; } // cout << "BaseIUParStatus::SetPinStatus() : Setting pin " << pinName // << " to " << status << endl; MtxLock globLock(bmGlobMutex); int nElms = bpsPinMaskMap.count(pinName); globLock.Unlock(); MtxLock localLock(bmMutex); if (nElms > 0) { // cout << "Start value is " << bpsWriteValue << endl; // cout << "Read value corresponds to " << ReadToWrite(bpsReadValue) << endl; uint16_t startVal = bpsWriteValue; localLock.Unlock(); uint16_t writeVal = SetPinToWrite(pinName, status, startVal); localLock.Lock(); bpsWriteValue = writeVal; // cout << "End value is " << bpsWriteValue << endl; } return bpsWriteValue; } //! Set write bits based on the status of one particular pin. It starts with //! a given "current" write value. uint16_t BaseIUParStatus::SetPinToWrite( string pinName, bool pinON, uint16_t writeVal ) { MtxLock classLock( bmGlobMutex ); uint16_t onMask = bpsExtraByteMap[pinName].first; uint16_t offMask = bpsExtraByteMap[pinName].second; uint16_t protectionMask = bpsWriteProtectionMask; classLock.Unlock(); //! Start with requiring that this pin be on writeVal |= onMask ; if( ! pinON ) { //! if the request was to turn it off then we need to //! remove the actual set bit and leave the pin identifier bit writeVal &= ~( onMask ^ offMask ); //! Use protection mask to disable turning on unwanted bits. //! This is done since we do not think we will ever need to turn on JAM bits. writeVal &= protectionMask; } return writeVal; } //! Convert read status into corresponding write word which would //! result in the identical state on the hardware uint16_t BaseIUParStatus::ReadToWrite(uint8_t readVal) { //! Loop over all pin names in the mask map and set the corresponding //! bits in the write value uint16_t writeVal = 0x0000; // Start with all bits unset map::iterator itPin; MtxLock globLock(bmGlobMutex); for (itPin = bpsPinMaskMap.begin(); itPin != bpsPinMaskMap.end(); itPin++) { //! First get the status for this pin based in the read values string pinName = itPin->first; uint8_t pinMask = itPin->second; bool pinReadOn = ((pinMask & readVal) != 0); //! Now or the existing write value with what the current pin read setting //! requires. globLock.Unlock(); writeVal = SetPinToWrite(pinName, pinReadOn, writeVal); globLock.Lock(); } return writeVal; } bool BaseIUParStatus::GetBit( const string pinName ) { MtxLock classLock( bmGlobMutex ); // cout << "Status word readback is " << hex << showbase << (int)bpsReadValue << " for parameter " << bvpType << " : " << // bvpName << " for address " << hex << showbase << bmAddress << " on port " << bmDevice->GetPortName() // << " , will return bit value as " << ( ( bpsReadValue & bpsPinMaskMap[pinName] ) == bpsPinMaskMap[pinName] ) // << " for bit " << pinName << endl; // cout << "The pointer to the object is " << hex << showbase << dynamic_cast(this) << endl; return ( ( bpsReadValue & bpsPinMaskMap[pinName] ) == bpsPinMaskMap[pinName] ); } //! Compare if there is any difference between the read and to-be-written values. //! This function exists because the way IU designed the hw/fw is such that //! there is no easy matching between the bit arrangement in read and written words. bool BaseIUParStatus::BitsMatch(uint8_t readVal, uint16_t writeVal) { //! Loop over all pin names in the mask map and compare the read and write statuses static map::iterator itPin; MtxLock globLock(bmGlobMutex); for (itPin = bpsPinMaskMap.begin(); itPin != bpsPinMaskMap.end(); itPin++) { //! First get the status for this pin based in the read values string pinName = itPin->first; uint8_t pinMask = itPin->second; bool pinReadOn = ((pinMask & readVal) != 0); //! Now get the status of the pin based on the write value uint16_t onMask = bpsExtraByteMap[pinName].first; uint16_t offMask = bpsExtraByteMap[pinName].second; bool pinWriteOn = (((writeVal & (onMask & offMask)) != 0) && ((writeVal & (onMask ^ offMask)) != 0)); /* cout << "Write value is " << writeVal << endl; cout << "Coincidence 1 is " << ( onMask & offMask ) << endl; cout << "Exclusion 2 is " << ( onMask ^ offMask ) << endl; cout << "Bool 1 is " << ( ( writeVal & ( onMask & offMask ) ) != 0 ) << " , Bool 2 is " << ( ( writeVal & ( onMask ^ offMask ) ) != 0 ) << endl;*/ if (pinReadOn != pinWriteOn) { //! if the statuses do not match then return false value if (bmDebFlag > 1) { cout << "BaseIUParStatus::BitsMatch() : Bits for pin " << pinName << " for the STATUS parameter " << " do not match " << endl; cout << "BaseIUParStatus::BitsMatch() : pin status from " << static_cast(readVal) << " is " << pinReadOn << " , write status from value " << writeVal << " is " << pinWriteOn << endl; cout << "Will not check the other pins" << endl; } return false; } } //! if reached here then all pin statuses were consistent return true; }