Generic hardware access library
/home/cschwick/hal/generic/src/common/VMESlot.cc
Go to the documentation of this file.
00001 #include "hal/VMESlot.hh"
00002 #include "hal/VME64xDevice.hh"
00003 
00004 #include <sstream>
00005 #include <iomanip>
00006 #include <ext/hash_map>
00007 
00008 HAL::VMESlot::VMESlot( HAL::StaticVMEItem* staticVME,
00009                        HAL::VMEBusAdapterInterface* busAdapterPtr,
00010                        HAL::AddressTableContainerInterface& addressTableContainer,
00011                        HAL::ModuleMapperInterface& moduleMapper )
00012   throw( HAL::IllegalValueException )
00013   : busAdapterPtr_(busAdapterPtr),
00014     addressTableContainer_(addressTableContainer),
00015     moduleMapper_(moduleMapper),
00016     windowVector_(NUMBER_OF_VME64XFUNCTIONS) {
00017 
00018   // initialization of variables
00019   configAdapterPtr_ = (HAL::VMEConfigurationSpaceHandler*)0;
00020   for ( int i=0; i<NUMBER_OF_VME64XFUNCTIONS; i++ ) {
00021     windowVector_.push_back( (HAL::VME64xMappedWindow*)0 );
00022   }
00023   slotId_ = staticVME->getSlotId();
00024   serialNumber_ = staticVME->getSerialNumber();
00025   contents_ = (HAL::SlotContents)VME;
00026 
00027   // get database info: typeId and baseaddress
00028   uint32_t baseAddress = moduleMapper.getBaseaddress( serialNumber_ );
00029   typeId_ = moduleMapper.getTypeId( serialNumber_ );
00030 
00031   // get HAL::AddressTable and related info
00032   HAL::VMEAddressTable& addressTable = addressTableContainer_.getVMETableFromSerialNumber( serialNumber_ );
00033   std::vector<uint32_t> minAddresses, maxAddresses;
00034   addressTable.getAddressBoundaries( minAddresses, maxAddresses );
00035 
00036   // for standard vme modules only the first entry in the vectors is relevant:
00037   // the minimal addressRank in VME64x is 256 bytes Therefore we start
00038   // with that addressRank here.
00039   uint32_t addressRank = 8;
00040   while ( (1u<<(addressRank)) <= maxAddresses[0] ) addressRank++;
00041 
00042   HAL::VME64xFunction* functionPtr = new HAL::VME64xFunction( slotId_, baseAddress, addressRank );
00043   functionPtrs_.push_back( functionPtr );
00044 
00045   // fill the windowVector of the slot
00046 
00047   std::list< HAL::VME64xMappedWindow* >::const_iterator it;
00048   it = functionPtr->getMappedWindowPtrList().begin();
00049   windowVector_[0] = *it;
00050   
00051 }
00052 
00053 HAL::VMESlot::VMESlot(  uint32_t slotId,
00054                         HAL::VMEConfigurationSpaceHandler* configAdapterPtr,
00055                         HAL::AddressTableContainerInterface& addressTableContainer,
00056                         HAL::ModuleMapperInterface& moduleMapper,
00057                         bool ignoreChecksumError )
00058   throw(HAL::IllegalValueException,
00059         HAL::UnsupportedException )
00060   : slotId_(slotId),
00061     configAdapterPtr_(configAdapterPtr),
00062     addressTableContainer_(addressTableContainer),
00063     moduleMapper_(moduleMapper_),
00064     windowVector_(NUMBER_OF_VME64XFUNCTIONS) {
00065 
00066   // initialization of variables
00067   busAdapterPtr_ = &(configAdapterPtr->getBusAdapter());
00068   for ( int i=0; i<NUMBER_OF_VME64XFUNCTIONS; i++ ) {
00069     windowVector_.push_back( (HAL::VME64xMappedWindow*)0 );
00070   }
00071   
00072   typeId_ = "";
00073   serialNumber_ = "";
00074 
00075   // If there is no VME64x module we assume the slot is empty.
00076   if ( ! configAdapterPtr->containsVME64xModule( slotId ) ) {
00077     contents_ = (HAL::SlotContents)EMPTY;
00078     return;
00079   } else {
00080     if ( (! ignoreChecksumError) && (! configAdapterPtr->checksumOk( slotId )) ) {
00081       std::stringstream text;
00082       text << "Found VME64x module in slot " << std::dec << slotId
00083            << " but checksum is corrupted" << std::ends;
00084           throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00085         }
00086     contents_ = (HAL::SlotContents)VME64x;
00087   }
00088 
00089   // get the serial Number of this module
00090   // it is needed later when the HAL::VMEDevice is created.
00091   // in case of old VME modules it is set from the configration
00092   // given in the constructor:
00093   serialNumber_ = configAdapterPtr_->readSerialNumber( slotId_ );
00094   typeId_ = moduleMapper.getTypeId( serialNumber_ );
00095   
00096   // get the functions of the module in this slot:
00097   HAL::VME64xFunction* functionPtr;
00098   uint32_t funcId = 0;
00099   bool atLeastOneValidFunction = false;
00100 
00101   // Go through all possible functions and see if they are implemented.
00102   // Implemented functions are put into the list fucntionPtrs_
00103   // and all mapped windows are put into the windowVector_.
00104   while ( funcId < NUMBER_OF_VME64XFUNCTIONS ) {
00105     if ( configAdapterPtr_->functionIsImplemented( slotId_, funcId )) {
00106       functionPtr =  new HAL::VME64xFunction( slotId_, 
00107                                               funcId,
00108                                               configAdapterPtr_ );
00109       functionPtrs_.push_back( functionPtr );
00110       atLeastOneValidFunction = true;
00111       funcId += functionPtr->getNumberOfMappedWindows();
00112 
00113       // fill the windowVector of the slot
00114 
00115       std::list< HAL::VME64xMappedWindow* >::const_iterator it;
00116       std::list< HAL::VME64xMappedWindow* > windowList = functionPtr->getMappedWindowPtrList();
00117       for( it = windowList.begin(); it != windowList.end(); it++ ) {
00118         windowVector_[(*it)->getMappedWindowId()] = *it;
00119       }
00120     } else {
00121       funcId++;
00122     }      
00123   }
00124 
00125   if ( ! atLeastOneValidFunction ) {
00126     std::stringstream text;
00127     text << "No valid function found in VME64x module of slot "
00128          << std::dec << slotId_ 
00129          << ".\n    (HAL::VMESlot::VMESlot)" << std::ends;
00130  
00131     // clean up what we have generated before throwing an exception.
00132 
00133     std::list< HAL::VME64xFunction* >::iterator it;
00134     for ( it=functionPtrs_.begin(); it != functionPtrs_.end(); it++ ) {
00135       delete *it;
00136     }
00137     functionPtrs_.clear();
00138     throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ));
00139   }
00140 
00141 }
00142 
00143 HAL::VMESlot::~VMESlot() {
00144   std::list< HAL::VME64xFunction* >::iterator it;
00145   for ( it = functionPtrs_.begin(); it != functionPtrs_.end(); it++) {
00146     delete *it;
00147   }
00148 }
00149 
00150 enum HAL::SlotContents HAL::VMESlot::getContents() const {
00151   return contents_;
00152 }
00153 
00154 std::string HAL::VMESlot::getTypeId() const {
00155   return typeId_;
00156 }
00157 
00158 std::string HAL::VMESlot::getSerialNumber() const {
00159   return serialNumber_;
00160 }
00161 
00162 uint32_t HAL::VMESlot::getSlotId() const {
00163   return slotId_;
00164 }
00165 
00166 
00167 HAL::VMEDevice* HAL::VMESlot::getVMEDevice() const 
00168   throw( HAL::IllegalOperationException,
00169          HAL::IllegalValueException,
00170          HAL::UnsupportedException,
00171          HAL::BusAdapterException,
00172          HAL::NoSuchItemException ) {
00173   
00174   HAL::VMEDevice* module;
00175 
00176   if ( contents_ == EMPTY ) {
00177     std::stringstream text;
00178     text << "This slot (" << std::dec << slotId_ 
00179          << "is empty and contains no module" 
00180          << "\n    (HAL::VMESlot::getVMEDevice)" << std::ends;
00181     throw( HAL::IllegalOperationException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00182   }
00183   
00184   HAL::VMEAddressTable& addressTable = 
00185     addressTableContainer_.getVMETableFromSerialNumber( serialNumber_ );
00186 
00187   // VME64x module:
00188   if ( contents_ == VME64x ) { 
00189 
00190     checkVME64xTable( addressTable );
00191     // try to build the module if not yet there:
00192     std::vector <uint32_t> baseaddresses(NUMBER_OF_VME64XFUNCTIONS);
00193     for ( int ic=0; ic<NUMBER_OF_VME64XFUNCTIONS; ic++ ) {
00194       if (windowVector_[ic]) {
00195         baseaddresses[ic] = windowVector_[ic]->getBaseaddress();
00196       } else {
00197         baseaddresses[ic] = 0;
00198       }
00199     }
00200 
00201     module = new HAL::VME64xDevice( addressTable,
00202                                     *busAdapterPtr_,
00203                                     baseaddresses,
00204                                     false,
00205                                     *this );
00206 
00207     // normal VME module:
00208   } else {
00209     uint32_t baseaddress = moduleMapper_.getBaseaddress( serialNumber_ );
00210     module = new HAL::VMEDevice( addressTable,
00211                                  *busAdapterPtr_,
00212                                  baseaddress );
00213   }
00214   
00215   return module;
00216 }
00217 
00218 
00219 // nothing should go wrong here since if the constructor survived
00220 // there should be 8 valid VME64Function* in the functionPtrs_.
00221 std::list< HAL::VME64xFunction* > HAL::VMESlot::getImplementedFunctions() const {
00222   std::list< HAL::VME64xFunction* > result;
00223   std::list< HAL::VME64xFunction* >::const_iterator it;
00224   for ( it = functionPtrs_.begin(); it != functionPtrs_.end(); it++ ) {
00225         if ( (*it)->isImplemented() ) {
00226           result.push_back( *it );
00227         }
00228   }
00229   return result;
00230 }
00231 
00232 void HAL::VMESlot::checkVME64xTable( HAL::VMEAddressTable& table ) const 
00233   throw (HAL::IllegalValueException) {
00234 
00235   // First go through the items of the table and see if the AMs in the
00236   // table are really offered by the corresponding function. In case 
00237   // of standard VME modules there is one single function implemented of which
00238   // the configuration-settings are given to this class in the constructor.
00239   // This might have been done already during the mapping of the crate. 
00240   // But it depends on the chosen strategy so it is better to check it 
00241   // here once just before the HAL::VMEDevice is created. 
00242   uint32_t  mapId; 
00243   __gnu_cxx::hash_map<std::string, HAL::AddressTableItem*, HAL::HalHash<std::string> >::const_iterator it;
00244   for ( it=table.getItemListBegin(); it != table.getItemListEnd(); it++ ) {
00245         mapId = (*it).second->getGeneralHardwareAddress().getMapId();
00246 
00247         // is the function implemented and configured ?
00248         if ( ! ( windowVector_[mapId] && windowVector_[mapId]->isConfigured() ) ) {
00249           std::stringstream text;
00250           text << "HAL::AddressTableItem " << (*it).first
00251                << " uses non-implemented or not-configured function " << std::dec << mapId
00252                << ".\n    (HAL::VMESlot::checkVME64xTable)" << std::ends;
00253           throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00254         }
00255 
00256     // configure the HardwareAddress to work with the correct AM and dataWidth:
00257 
00258     uint32_t AM = windowVector_[mapId]->getAM();
00259     uint32_t width = windowVector_[mapId]->getDataAccessWidth();
00260     try {
00261       HAL::VME64xHardwareAddress& vme64xAddress = 
00262         dynamic_cast< HAL::VME64xHardwareAddress& >((*it).second->getGeneralHardwareAddress());
00263 
00264       // nothing needs to be done for configspace since the am is already set correctly in the 
00265       // constructor of the vme64xhardwareaddress and the width has also been set already.
00266       if ( vme64xAddress.isMemorySpace() ) {
00267         vme64xAddress.setWindowConfiguration( AM, width );
00268       }
00269     } catch ( std::bad_cast ) {
00270       std::stringstream text;
00271       text << "The address table does not contain VME64x items!" 
00272            << "\n    (HAL::VMESlot::checkVME64xTable)" << std::ends;
00273       throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ));
00274     }
00275   }
00276 
00277 
00278   // now that the data widths have been set for all items in the 
00279   // address table the boundaries for the various base addresses
00280   // have to be redetermined.
00281   table.determineAddressBoundaries();
00282 
00283   // Now check the limits of the address tables against what is 
00284   // demanded by the functions in the hardware. This test only has
00285   // to be done for VME64x modules. It must be done after the data 
00286   // widths have been set for the various address map items since the
00287   // width is needed in the calculation of address boundaries in the
00288   // call "table.getAddressBoundaries".
00289   if ( contents_ == VME64x ) {
00290     std::vector< uint32_t > minAddresses, maxAddresses;
00291     table.getAddressBoundaries( minAddresses, maxAddresses );
00292 
00293     // loop over all functions of this slot
00294     std::list< HAL::VME64xFunction* >::const_iterator itf;
00295     for ( itf = functionPtrs_.begin(); itf != functionPtrs_.end(); itf++ ) {
00296 
00297       // loop over all mapped windows of the function
00298       std::list< HAL::VME64xMappedWindow* > windowList = (*itf)->getMappedWindowPtrList();
00299       std::list< HAL::VME64xMappedWindow* >::const_iterator itw;
00300       for ( itw = windowList.begin(); itw != windowList.end(); itw++ ) {
00301 
00302         uint32_t windowDemand = 1 << (*itw)->getAddressRank();
00303         uint32_t windowId = (*itw)->getMappedWindowId();
00304 
00305         if ( windowDemand <= maxAddresses[windowId] ) {
00306         std::stringstream text;
00307         text << "mapped window number " << std::dec << windowId 
00308              << " demands less memory than required in HAL::AddressTable "
00309              << "(hex):\n" << std::hex << std::setw(8) << std::setfill('0') << windowDemand
00310              << " <= " <<  maxAddresses[windowId] 
00311              << "\n    (HAL::VMESlot::checkVME64xTable)" << std::ends;
00312         throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ));
00313         }
00314       }
00315     }
00316   }
00317 
00318 }
00319 
00320 
00321 void HAL::VMESlot::stdConfigRead( std::string item,
00322                                   uint32_t* resultPtr,
00323                                   uint32_t offset ) const
00324   throw( HAL::NoSuchItemException, 
00325          HAL::IllegalOperationException,
00326          HAL::BusAdapterException )
00327 {
00328   if ( ! configAdapterPtr_ ) 
00329     {
00330       std::stringstream text;
00331       text << "No ConfigurationSpace Adapter available for slot " << std::dec << slotId_ 
00332              << " .\nProbbably this means that there is no VME64x modules plugged into this slot."
00333              << std::ends;
00334          throw( HAL::IllegalOperationException( text.str(), __FILE__, __LINE__, __FUNCTION__ ));     
00335     }
00336   configAdapterPtr_->configRead( item, slotId_, resultPtr, offset );
00337 }
00338   
00339 void HAL::VMESlot::stdConfigWrite( std::string item,
00340                                    uint32_t data,
00341                                    HalVerifyOption verifyFlag,
00342                                    uint32_t offset ) const
00343   throw( HAL::NoSuchItemException, 
00344          HAL::IllegalOperationException,
00345          HAL::BusAdapterException )
00346 {
00347   if ( ! configAdapterPtr_ ) 
00348     {
00349       std::stringstream text;
00350       text << "No ConfigurationSpace Adapter available for slot " << std::dec << slotId_ 
00351              << " .\nProbbably this means that there is no VME64x modules plugged into this slot."
00352              << std::ends;
00353          throw( HAL::IllegalOperationException( text.str(), __FILE__, __LINE__, __FUNCTION__ ));     
00354     }
00355   configAdapterPtr_->configWrite( item, slotId_, data, verifyFlag, offset );
00356 }