/* 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 "BaseIUParADC.hh" const unsigned BaseIUParADC::bpaBitsADC = 0x3ff; // 10 bit ADC const unsigned BaseIUParADC::bpaBitsDAC = 0xfff; // 12 bit DAC //! Parameter type for ADC parameters on the board const string BaseIUParADC::bpaParType = "ADC"; //! Command byte for request for ADC readback for IU boards const int BaseIUParADC::bpaComndByte = 0xbb; //! Map describing extra byte for different parameters names for //! ADC type of parameters map BaseIUParADC::bpaExtraByteMap; map BaseIUParADC::bpaTolerance; //! Map describing the scale for converting to engineering units map BaseIUParADC::bpaScaleMap; map BaseIUParADC::bpaOffsetMap; static volatile int bpaDummyInt = BaseIUParADC::InitMaps(); //! Main constructor BaseIUParADC::BaseIUParADC(string name, BaseIUModule& board) : BaseIUVirtPar(bpaParType, name, board), bpaReadValue(0), bpaWriteValue( 0) { if (bmDebFlag > 5) { cout << "BaseIUParADC::BaseIUParADC() : Main constructor is invoked " << " for ADC parameter named " << name << " at address " << bmAddress << endl; } bvpWriteBuffer = reinterpret_cast( &bpaWriteValue ) ; return; } //! Short constructor BaseIUParADC::BaseIUParADC(string name) : BaseIUVirtPar(bpaParType, name), bpaReadValue(0), bpaWriteValue(0) { if (bmDebFlag > 5) { cout << "BaseIUParADC::BaseIUParADC() : Short constructor is invoked " << " for ADC parameter named " << name << " at address " << bmAddress << endl; } bvpWriteBuffer = reinterpret_cast( &bpaWriteValue ) ; return; } //! Copy constructor BaseIUParADC::BaseIUParADC(const BaseIUParADC& par) : BaseIUVirtPar(par) { if (bmDebFlag > 5) { cout << "BaseIUParADC::BaseIUParADC() : Copy constructor is invoked" << endl; } this->operator=(par); MtxLock objLock(bmMutex); bvpWriteBuffer = reinterpret_cast( &bpaWriteValue ) ; return; } //! Class destructor BaseIUParADC::~BaseIUParADC() { if (bmDebFlag > 5) { cout << "BaseIUParADC::~BaseIUParADC() : Destructor for ADC parameter " << bvpType << " : " << bvpName << " has been called" << endl; } } //! Assignment operator BaseIUParADC& BaseIUParADC::operator=(const BaseIUParADC& constPar) { if (bmDebFlag > 5) { cout << "BaseIUParADC::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); BaseIUParADC& par = const_cast(constPar); MtxLock objLock(bmMutex); bpaReadValue = par.GetReadValue(); bpaWriteValue = par.GetWriteValue(); 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* BaseIUParADC::CloneParameter() { if (bmDebFlag > 5) { cout << "BaseIUParADC::CloneParameter() : Cloning ADC parameter " << bvpName << endl; } BaseIUParADC* tmpPar = new BaseIUParADC(*this); return dynamic_cast(tmpPar); } //! Request read of this ADC for all boards on the bus void BaseIUParADC::ReadRequest( BaseIUDevice* dev, string name ) { if (bmDebFlag > 1) { cout << "BaseIUParADC::ReadRequest() : Requesting readback for parameters " << bpaParType << " : " << name << endl; } BaseIUMessage cmd; cmd << BaseIUMessage(bpaComndByte) << BaseIUMessage(bpaExtraByteMap[name]); 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 BaseIUParADC::SetWriteValueFrom( BaseIUVirtPar& fakePar ) { double* tmpValue = reinterpret_cast( fakePar.GetWriteBuffer() ); MtxLock objLock(bmMutex); bpaWriteValue = *tmpValue; return; } //! Method to synch the parameters bool BaseIUParADC::Sync(bool syncFromHW) { if (bmDebFlag > 1) { cout << "BaseIUParADC::Sync() : Syncing parameter " << bvpType << " : " << bvpName << " for address " << bmAddress << endl; cout << "BaseIUParADC::Sync() : Syncing from hardware flag is " << syncFromHW << endl; } //! Process FIFO and assign the readout value. Return value is true // if there was message found. bool msgFound = ProcessDeque(); if (syncFromHW) { //! If syncing from hardware then writeValue is set to what is readback if (bmDebFlag > 1) { cout << "BaseIUParADC::Sync() : Assigning write value from HW " << bpaReadValue << endl; } MtxLock objLock(bmMutex); bpaWriteValue = bpaReadValue; } else { //! Write to hardware if Sync is not requested from hardware to the driver //! If the difference between read and write value is larger than tolerance then //! write to hardware. This enforces the desired value into the hardware, for //! instance when there was an input to the desired setpoint. if (fabs(bpaReadValue - bpaWriteValue) > bpaTolerance[bvpName]) { if (bvpName == "SET") { // This value enforcement happens for cathode voltage parameter BaseIUMessage cmdMsg; //! The conversion formula here is taken from IU code. cmdMsg << BaseIUCommand::DA_INIT; int intValue = static_cast(round(bpaWriteValue * 2.0)); int dacValue = (intValue & bpaBitsDAC); //! The left shift by a byte of the second byte is somehow taken into account in the //! firmware or hardware on the base cmdMsg << (dacValue >> 4) << ((dacValue & 0x0000000F) << 4); if (bmDebFlag > 1) { cout << "BaseIUParADC::Sync() : Will write by sending message " << cmdMsg << " to address " << bmAddress << endl; } //! Send the command bmDevice->Send(bmAddress, cmdMsg); // bmDevice->Sleep(); } } } // If message was found return true indicating that sync was successful return msgFound; } //! 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 BaseIUParADC::ProcessDeque( bool clearFlag ) { if (bmDebFlag > 1) { cout << "BaseIUParADC::ProcessDeque() : Processing deque for parameter " << bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << endl; } bool msgFound = false; deque msgDeque = bmDevice->GetDeque(bmAddress); if (msgDeque.size() < 1) { if (bmDebFlag > 1) { cout << "BaseIUParADC::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. Also check that the //! the extra byte returned by the ADc matches the name of the ADc //! for this parameter. We think that this does happen. if ( ( msg[0] == BaseIUParADC::bpaComndByte ) && ( msg[3] == bpaExtraByteMap[bvpName] ) ) { int adcChan = (msg[1] << 8) | (msg[2]); MtxLock objLock(bmMutex); bpaReadValue = bpaOffsetMap[bvpName] + bpaScaleMap[bvpName] * adcChan; msgFound = true; } else if( msg[0] == BaseIUParADC::bpaComndByte && msg[3] != bpaExtraByteMap[bvpName] ) { // Just print a message about the ADC type mismatch in the response cerr << "BaseIUParADC::ProcessDeque(): Wrong ADC type " << hex << showbase << static_cast(msg[3]) << " in the response received by parameter " << bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << dec << endl; } } if (bmDebFlag > 1) { cout << "BaseIUParADC::ProcessDeque() : Read value " << bpaReadValue << " for parameter " << bvpType << " : " << bvpName << " for address " << hex << showbase << bmAddress << endl; } return msgFound; } //! Initialize the maps for ADCs for the power chassis for IU base control. //! Some of the parameters, like the byte values and the scaling constants are //! taken from a document by C. Tarbert or from Dan Bennett's code. int BaseIUParADC::InitMaps() { if (bmDebFlag > 1) { cout << "BaseIUParADC::InitMaps() : Initializing maps for ADC parameters" << endl; } //! These parameters are defined in the write up by C.Tarbert bpaExtraByteMap["MVB"] = 0x00; //! medium voltage bottom bpaExtraByteMap["MVT"] = 0x01; //! medium voltage top bpaExtraByteMap["DYN"] = 0x02; //! 1st dynode voltage bpaExtraByteMap["CAT"] = 0x03; //! PHOTOCATHODE voltage bpaExtraByteMap["DAC"] = 0x04; //! DAC output voltage bpaExtraByteMap["TEM"] = 0x05; //! temperature monitor bpaExtraByteMap["CUR"] = 0x06; //! current monitor bpaExtraByteMap["SET"] = 0x07; //! demand voltage bpaExtraByteMap["VLA"] = 0x11; //! Voltage Left A bpaExtraByteMap["VLB"] = 0x12; //! Voltage Left B bpaExtraByteMap["VLC"] = 0x13; //! Voltage Left C bpaExtraByteMap["VLD"] = 0x14; //! Voltage Left D bpaExtraByteMap["VRA"] = 0x15; //! Voltage Right A bpaExtraByteMap["VRB"] = 0x16; //! Voltage Right B bpaExtraByteMap["VRC"] = 0x17; //! Voltage Right C bpaExtraByteMap["VRD"] = 0x18; //! Voltage Right D bpaExtraByteMap["ILA"] = 0x21; //! Current Left A bpaExtraByteMap["ILB"] = 0x22; //! Current Left B bpaExtraByteMap["ILC"] = 0x23; //! Current Left C bpaExtraByteMap["ILD"] = 0x24; //! Current Left D // Ask Dan bpaExtraByteMap["IRA"] = 0x25; //! Current Right A bpaExtraByteMap["IRB"] = 0x26; //! Current Right B bpaExtraByteMap["IRC"] = 0x27; //! Current Right C bpaExtraByteMap["IRD"] = 0x28; //! Current Right D bpaExtraByteMap["SLA"] = 0x31; //! Status Left A bpaExtraByteMap["SLB"] = 0x32; //! Status Left B bpaExtraByteMap["SLC"] = 0x33; //! Status Left C bpaExtraByteMap["SLD"] = 0x34; //! Status Left D bpaExtraByteMap["SRA"] = 0x35; //! Status Right A bpaExtraByteMap["SRB"] = 0x36; //! Status Right B bpaExtraByteMap["SRC"] = 0x37; //! Status Right C bpaExtraByteMap["SRD"] = 0x38; //! Status Right D //! Scale calibration parameters copied from IU code bpaScaleMap["MVB"] = 3.00 * 1 / bpaBitsADC; //! medium voltage bottom bpaScaleMap["MVT"] = 3.00 * 1 / bpaBitsADC; //! medium voltage top bpaScaleMap["DYN"] = 3.00 * 1000 / bpaBitsADC; //! 1st dynode voltage bpaScaleMap["CAT"] = 3.00 * 1000 / bpaBitsADC; //! photocathode voltage bpaScaleMap["DAC"] = 3.00 * 1 / bpaBitsADC; //! DAC output voltage bpaScaleMap["TEM"] = 3.00 * 100 / bpaBitsADC; //! temperature monitor // bpaScaleMap["CUR"] = 3.00 * 0.005 / bpaBitsADC; //! current monitor bpaScaleMap["CUR"] = 3.00 * 5.0 / bpaBitsADC; //! current monitor bpaScaleMap["SET"] = 1.00 / 32.0; //! demand voltage bpaScaleMap["VLA"] = 3.00 * 10 / bpaBitsADC; //! Voltage Left A bpaScaleMap["VLB"] = 3.00 * 10 / bpaBitsADC; //! Voltage Left B bpaScaleMap["VLC"] = 3.00 * 10 / bpaBitsADC; //! Voltage Left C bpaScaleMap["VLD"] = 3.00 * 10 / bpaBitsADC; //! Voltage Left D bpaScaleMap["VRA"] = 3.00 * 10 / bpaBitsADC; //! Voltage Right A bpaScaleMap["VRB"] = 3.00 * 10 / bpaBitsADC; //! Voltage Right B bpaScaleMap["VRC"] = 3.00 * 10 / bpaBitsADC; //! Voltage Right C bpaScaleMap["VRD"] = 3.00 * 10 / bpaBitsADC; //! Voltage Right D bpaScaleMap["ILA"] = 3.00 * 1 / bpaBitsADC; //! Current Left A bpaScaleMap["ILB"] = 3.00 * 1 / bpaBitsADC; //! Current Left B bpaScaleMap["ILC"] = 3.00 * 1 / bpaBitsADC; //! Current Left C bpaScaleMap["ILD"] = 3.00 * 1 / bpaBitsADC; //! Current Left D bpaScaleMap["IRA"] = 3.00 * 1 / bpaBitsADC; //! Current Right A bpaScaleMap["IRB"] = 3.00 * 1 / bpaBitsADC; //! Current Right B bpaScaleMap["IRC"] = 3.00 * 1 / bpaBitsADC; //! Current Right C bpaScaleMap["IRD"] = 3.00 * 1 / bpaBitsADC; //! Current Right D bpaScaleMap["SLA"] = 1; //! Status Left A bpaScaleMap["SLB"] = 1; //! Status Left B bpaScaleMap["SLC"] = 1; //! Status Left C bpaScaleMap["SLD"] = 1; //! Status Left D bpaScaleMap["SRA"] = 1; //! Status Right A bpaScaleMap["SRB"] = 1; //! Status Right B bpaScaleMap["SRC"] = 1; //! Status Right C bpaScaleMap["SRD"] = 1; //! Status Right D //! Offset parameters for conversions bpaOffsetMap["MVB"] = 0; //! medium voltage bottom bpaOffsetMap["MVT"] = 0; //! medium voltage top bpaOffsetMap["DYN"] = 0; //! 1st dynode voltage bpaOffsetMap["CAT"] = 0; //! photocathode voltage bpaOffsetMap["DAC"] = 0; //! DAC output voltage bpaOffsetMap["TEM"] = 0; //! temperature monitor bpaOffsetMap["CUR"] = 0; //! current monitor bpaOffsetMap["SET"] = 0; //! demand voltage bpaOffsetMap["VLA"] = 0; //! Voltage Left A bpaOffsetMap["VLB"] = 0; //! Voltage Left B bpaOffsetMap["VLC"] = 0; //! Voltage Left C bpaOffsetMap["VLD"] = 0; //! Voltage Left D bpaOffsetMap["VRA"] = 0; //! Voltage Right A bpaOffsetMap["VRB"] = 0; //! Voltage Right B bpaOffsetMap["VRC"] = 0; //! Voltage Right C bpaOffsetMap["VRD"] = 0; //! Voltage Right D bpaOffsetMap["ILA"] = 0; //! Current Left A bpaOffsetMap["ILB"] = 0; //! Current Left B bpaOffsetMap["ILC"] = 0; //! Current Left c bpaOffsetMap["ILD"] = 0; //! Current Left D bpaOffsetMap["IRA"] = 0; //! Current Right A bpaOffsetMap["IRB"] = 0; //! Current Right B bpaOffsetMap["IRC"] = 0; //! Current Right C bpaOffsetMap["IRD"] = 0; //! Current Right D bpaOffsetMap["SLA"] = 0; //! Status Left A bpaOffsetMap["SLB"] = 0; //! Status Left B bpaOffsetMap["SLC"] = 0; //! Status Left C bpaOffsetMap["SLD"] = 0; //! Status Left D bpaOffsetMap["SRA"] = 0; //! Status Right A bpaOffsetMap["SRB"] = 0; //! Status Right B bpaOffsetMap["SRC"] = 0; //! Status Right C bpaOffsetMap["SRD"] = 0; //! Status Right D //! Tolerances for parameter syncing bpaTolerance["MVB"] = 1; //! medium voltage bottom bpaTolerance["MVT"] = 1; //! medium voltage top bpaTolerance["DYN"] = 1; //! 1st dynode voltage bpaTolerance["CAT"] = 1; //! photocathode voltage bpaTolerance["DAC"] = 1; //! DAC output voltage bpaTolerance["TEM"] = 1; //! temperature monitor bpaTolerance["CUR"] = 1; //! current monitor bpaTolerance["SET"] = 1; //! demand voltage bpaTolerance["VLA"] = 1; //! Voltage Left A bpaTolerance["VLB"] = 1; //! Voltage Left B bpaTolerance["VLC"] = 1; //! Voltage Left C bpaTolerance["VLD"] = 1; //! Voltage Left D bpaTolerance["VRA"] = 1; //! Voltage Right A bpaTolerance["VRB"] = 1; //! Voltage Right B bpaTolerance["VRC"] = 1; //! Voltage Right C bpaTolerance["VRD"] = 1; //! Voltage Right D bpaTolerance["ILA"] = 1; //! Current Left A bpaTolerance["ILB"] = 1; //! Current Left B bpaTolerance["ILC"] = 1; //! Current Left C bpaTolerance["ILD"] = 1; //! Current Left D bpaTolerance["IRA"] = 1; //! Current Right A bpaTolerance["IRB"] = 1; //! Current Right B bpaTolerance["IRC"] = 1; //! Current Right C bpaTolerance["IRD"] = 1; //! Current Right D bpaTolerance["SLA"] = 1; //! Status Left A bpaTolerance["SLB"] = 1; //! Status Left B bpaTolerance["SLC"] = 1; //! Status Left C bpaTolerance["SLD"] = 1; //! Status Left D bpaTolerance["SRA"] = 1; //! Status Right A bpaTolerance["SRB"] = 1; //! Status Right B bpaTolerance["SRC"] = 1; //! Status Right C bpaTolerance["SRD"] = 1; //! Status Right D return 0; }