Library of Bus-Adapters
/home/cschwick/hal/busAdapter/caen/src/common/CAENLinuxBusAdapter.cc
Go to the documentation of this file.
00001 #include "hal/CAENLinuxBusAdapter.hh"
00002 #include "CAENVMElib.h"
00003 #include <sstream>
00004 #include <iostream>
00005 #include <iomanip>
00006 #include <string.h>
00007 
00008 
00009 int32_t HAL::CAENLinuxBusAdapter::handleVX718UseCount_[8][8] = {{0,0,0,0,0,0,0,0},
00010                                                                 {0,0,0,0,0,0,0,0},
00011                                                                 {0,0,0,0,0,0,0,0},
00012                                                                 {0,0,0,0,0,0,0,0},
00013                                                                 {0,0,0,0,0,0,0,0},
00014                                                                 {0,0,0,0,0,0,0,0},
00015                                                                 {0,0,0,0,0,0,0,0},
00016                                                                 {0,0,0,0,0,0,0,0}};
00017 int32_t HAL::CAENLinuxBusAdapter::handleVX718_[8][8] = {{0,0,0,0,0,0,0,0},
00018                                                         {0,0,0,0,0,0,0,0},
00019                                                         {0,0,0,0,0,0,0,0},
00020                                                         {0,0,0,0,0,0,0,0},
00021                                                         {0,0,0,0,0,0,0,0},
00022                                                         {0,0,0,0,0,0,0,0},
00023                                                         {0,0,0,0,0,0,0,0},
00024                                                         {0,0,0,0,0,0,0,0}};
00025 sem_t*  HAL::CAENLinuxBusAdapter::handleSemaphore_ = 0;
00026 
00035 HAL::CAENLinuxBusAdapter::CAENLinuxBusAdapter( CAENModel model, int unit, int chain, CAENPCCard pcCard )
00036     throw (BusAdapterException)
00037     : unit_(unit),
00038       chain_(chain),
00039       model_(model)
00040 {
00041 
00042     int status;
00043     int32_t handle;
00044 
00045     // Initial check of parameters
00046     if ( unit > 7 || unit < 0 || chain > 7 || chain < 0 ) {
00047       std::stringstream errorMessage;
00048       errorMessage << "unit and chain parameters must be between 0 and 7 but they are " 
00049                    << unit << " and " << chain << "." << std::ends;
00050       throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00051     }
00052 
00053     if ( handleSemaphore_ == 0 ) {
00054       handleSemaphore_ = new sem_t;
00055       sem_init( handleSemaphore_, 0, 0 );
00056     } else {
00057       sem_wait( handleSemaphore_ );
00058     }
00059 
00060     V1718FwRelease_[0] = char(0);
00061     V2718FwRelease_[0] = char(0);
00062     AX818FwRelease_[0] = char(0);
00063     A2719FwRelease_[0] = char(0);
00064     VMELibRelease_[0]  = char(0);
00065   
00066     if ( pcCard == A3818 ) {
00067       pcCard_ = cvA3818;
00068       pcCardStr_ = "A3818";
00069     } else if ( pcCard == A2818 ) {
00070       pcCard_ = cvA2818;
00071       pcCardStr_ = "A2818";
00072     } else {
00073       // a software bug
00074       throw (BusAdapterException( "A HAL software bug: illegal pc card identifier set", 
00075                                   __FILE__, __LINE__, __FUNCTION__ ) );
00076     }
00077 
00078     // collect all the firmware and software versions
00079     
00080     if ( model == V2718 ) {     // model V2718
00081 
00082       // firmware version of the PCI board 
00083       if( (status=CAENVME_Init(pcCard_, unit_, 0, &handle)) != cvSuccess ) {
00084            std::stringstream errorMessage;
00085            errorMessage << "Could not initialize CAENVME library for PC card (status: "
00086                         << status 
00087                         << ")"
00088                         << std::ends;
00089            sem_post(handleSemaphore_);
00090            throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00091        }
00092        if ( ( status = CAENVME_BoardFWRelease( handle, AX818FwRelease_ )) != cvSuccess ) {
00093            std::stringstream errorMessage;
00094            errorMessage << "Could not determine firmware version of " << pcCardStr_ << " (status: "
00095                         << status 
00096                         << ")"
00097                         << std::ends;
00098            sem_post(handleSemaphore_);
00099            throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00100       }
00101        
00102         CAENVME_End( handle );
00103     
00104         // // The following must not be done since it sets the optical link add-on board
00105         // // in service mode: If at the same time another process tries to access the
00106         // // VME bus via the same optical link, it will get an error since the packet 
00107         // // gets stuck in the optical link board which is in service mode.
00108         // 
00109         // // firmware version of the optical link add-on board
00110         // if( (status=CAENVME_Init(cvA2719, unit_, 0, &handle_)) != cvSuccess ) {
00111         //   std::stringstream errorMessage;
00112         //   errorMessage << "Could not initialize CAENVME library with cvA2719 (status: "
00113         //             << status 
00114         //             << ")"
00115         //             << std::ends;
00116         //   throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00117         // }
00118         // if ( ( status = CAENVME_BoardFWRelease( handle_, A2719FwRelease_ )) != cvSuccess ) {
00119         //   std::stringstream errorMessage;
00120         //   errorMessage << "Could not determine firmware version of cvA2719 (status: "
00121         //             << status 
00122         //             << ")"
00123         //             << std::ends;
00124         //   throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00125         // }
00126         // CAENVME_End( handle_ );
00127         strcpy( A2719FwRelease_, "not available" ) ;
00128         
00129         // firmware version of the VME Controller board (optical link version)
00130         // This process must only call Init once!!!
00131         if ( handleVX718UseCount_[unit_][chain_] == 0 ) {
00132           if( (status=CAENVME_Init(cvV2718, unit_, chain_, &handleVX718_[unit_][chain_])) != cvSuccess ) {
00133             std::stringstream errorMessage;
00134             errorMessage << "Could not initialize CAENVME library with cvV2718 (status: "
00135                          << status 
00136                          << ")"
00137                          << std::ends;
00138             sem_post(handleSemaphore_);
00139             throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00140           }
00141         }
00142 
00143         if ( ( status = CAENVME_BoardFWRelease( handleVX718_[unit_][chain_], V2718FwRelease_ )) != cvSuccess ) {
00144           std::stringstream errorMessage;
00145           errorMessage << "Could not determine firmware version of V2718 (status: "
00146                        << status 
00147                        << ")"
00148                        << std::ends;
00149           sem_post(handleSemaphore_);
00150           throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00151         }       
00152         
00153     } else {   // V1718
00154       
00155       
00156       // firmware of the VME Controller board (USB version)
00157       if ( handleVX718UseCount_[unit_][chain_] == 0 ) {
00158         if( (status=CAENVME_Init(cvV1718, unit_, 0, &handleVX718_[unit_][chain_])) != cvSuccess ) {
00159           std::stringstream errorMessage;
00160           errorMessage << "Could not initialize CAENVME library with cvV1718 (status: "
00161                        << status 
00162                        << ")"
00163                        << std::ends;
00164           sem_post(handleSemaphore_);
00165           throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00166         }
00167       }
00168       if ( ( status = CAENVME_BoardFWRelease( handleVX718_[unit_][chain_], V1718FwRelease_ )) != cvSuccess ) {
00169           std::stringstream errorMessage;
00170           errorMessage << "Could not determine firmware version of V1718 (status: "
00171                        << status 
00172                        << ")"
00173                        << std::ends;
00174           sem_post(handleSemaphore_);
00175           throw (BusAdapterException( errorMessage.str(), __FILE__, __LINE__, __FUNCTION__ ) );   
00176       }
00177     }
00178     CAENVME_SWRelease( VMELibRelease_ );
00179     handleVX718UseCount_[unit_][chain_]++;
00180 
00181     sem_post(handleSemaphore_);
00182 
00183 }
00184 
00185 
00186 
00187 
00188 HAL::CAENLinuxBusAdapter::~CAENLinuxBusAdapter() 
00189     throw( BusAdapterException ){
00190 
00191   sem_wait( handleSemaphore_ );
00192   handleVX718UseCount_[unit_][chain_]--;
00193 
00194 
00195   if ( handleVX718UseCount_[unit_][chain_] == 0 ) {
00196     // we are the last user: close down everything
00197     if (CAENVME_End( handleVX718_[unit_][chain_] ) != cvSuccess ) {
00198         std::string errorMessage( "Could not close the CAENVME library" );
00199         sem_post( handleSemaphore_ );
00200         throw (BusAdapterException( errorMessage, __FILE__, __LINE__, __FUNCTION__ ) );
00201     }
00202     handleVX718_[unit_][chain_] = 0;
00203     sem_post( handleSemaphore_ );
00204     sem_destroy( handleSemaphore_ );
00205     handleSemaphore_ = 0;
00206     delete handleSemaphore_;
00207  
00208  } else {
00209 
00210    // somebody else is still using the busAdapter 
00211    sem_post( handleSemaphore_ );
00212 
00213   }
00214 }
00215 
00216 
00217 
00218 void HAL::CAENLinuxBusAdapter::openDevice(const VMEAddressTable& vmeAddressTable,
00219                                      uint32_t vmeBaseAddress,
00220                                      DeviceIdentifier** deviceIdentifierPtr,
00221                                      uint32_t* baseAddressPtr,
00222                                      bool doSwapping ) 
00223     throw (BusAdapterException) {
00224   
00225     *deviceIdentifierPtr= new HAL::CAENDeviceIdentifier( handleVX718_[unit_][chain_],
00226                                                          doSwapping );
00227 
00228     *baseAddressPtr = vmeBaseAddress;
00229 }
00230 
00231 
00232 
00233 void HAL::CAENLinuxBusAdapter::openDevice(const VMEAddressTable& vmeAddressTable,
00234                                      std::vector<uint32_t> vmeBaseAddresses,
00235                                      DeviceIdentifier** deviceIdentifierPtr,
00236                                      std::vector<uint32_t>* baseAddressesPtr,
00237                                      bool doSwapping ) 
00238     throw (BusAdapterException) {
00239   
00240     *deviceIdentifierPtr= new HAL::CAENDeviceIdentifier( handleVX718_[unit_][chain_],
00241                                                          doSwapping );
00242     
00243     *baseAddressesPtr = vmeBaseAddresses;
00244 }
00245 
00246 
00247 
00248 
00249 void HAL::CAENLinuxBusAdapter::closeDevice( DeviceIdentifier* vmeDevice ) 
00250     throw() {
00251     delete(vmeDevice);
00252 }
00253 
00254 
00255 
00256 void HAL::CAENLinuxBusAdapter::read( DeviceIdentifier* vmeDevice, 
00257                                 uint32_t address,
00258                                 uint32_t addressModifier,
00259                                 uint32_t dataWidth,
00260                                 uint32_t *resultPtr )
00261     throw( BusAdapterException ) {
00262 
00263     // The CAEN Adapter now supports byte swapping
00264     if ( dynamic_cast<HAL::CAENDeviceIdentifier*>(vmeDevice)->doSwapping() &&
00265          dataWidth > 1 ) {
00266         dataWidth += 16;
00267     }
00268 
00269     if( CAENVME_ReadCycle( handleVX718_[unit_][chain_], address, 
00270                            (void*)resultPtr, 
00271                            (CVAddressModifier)addressModifier, 
00272                            (CVDataWidth)dataWidth ) != cvSuccess ) {
00273         std::string errorMessage( "Could not read from CAEN BusAdapter" );
00274         throw (BusAdapterException( errorMessage, __FILE__, __LINE__, __FUNCTION__ ) );    
00275     }
00276 }
00277 
00278 void HAL::CAENLinuxBusAdapter::write( DeviceIdentifier* vmeDevice, 
00279                                  uint32_t address, 
00280                                  uint32_t addressModifier,
00281                                  uint32_t dataWidth,
00282                                  uint32_t data)
00283     throw( BusAdapterException ) {
00284 
00285     // The CAEN Adapter now supports byte swapping
00286     if ( dynamic_cast<HAL::CAENDeviceIdentifier*>(vmeDevice)->doSwapping() &&
00287          dataWidth > 1 ) {
00288         dataWidth += 16;
00289     }
00290 
00291     if( CAENVME_WriteCycle( handleVX718_[unit_][chain_], address, 
00292                             (void*)(&data), 
00293                             (CVAddressModifier)addressModifier, 
00294                             (CVDataWidth)dataWidth ) != cvSuccess ) {
00295         std::string errorMessage( "Could not read from CAEN BusAdapter" );
00296         throw (BusAdapterException( errorMessage, __FILE__, __LINE__, __FUNCTION__ ) );    
00297     }
00298 }
00299 
00300 void HAL::CAENLinuxBusAdapter::resetBus( ) 
00301     throw(BusAdapterException) {
00302 
00303     if (CAENVME_SystemReset( handleVX718_[unit_][chain_] )  != cvSuccess ) {
00304         throw( BusAdapterException( "Cannot issue sysReset on VME crate", __FILE__, __LINE__, __FUNCTION__ ));
00305     }
00306 }
00307 
00308 void HAL::CAENLinuxBusAdapter::readBlock( DeviceIdentifier *vmeDevice,
00309                                      uint32_t startAddress,
00310                                      uint32_t length,      // in bytes
00311                                      uint32_t addressModifier,
00312                                      uint32_t dataWidth,
00313                                      char *buffer,
00314                                      HalAddressIncrement addressBehaviour )
00315     throw( BusAdapterException,
00316            UnsupportedException ){
00317 
00318     int actualTransferred, status;
00319 
00320     // The CAEN Adapter now supports byte swapping
00321     if ( dynamic_cast<HAL::CAENDeviceIdentifier*>(vmeDevice)->doSwapping() &&
00322          dataWidth > 1 ) {
00323         dataWidth += 16;
00324     }
00325 
00326     if ( addressBehaviour != HAL_DO_INCREMENT ) {
00327 
00328       if ( (status = CAENVME_FIFOBLTReadCycle(handleVX718_[unit_][chain_], startAddress, (unsigned char *)buffer, 
00329                                               (int) length, (CVAddressModifier) addressModifier, 
00330                                               (CVDataWidth) dataWidth, &actualTransferred))  != cvSuccess ) {
00331 
00332         throw( BusAdapterException( "Error during read block transfer (FIFO mode)", __FILE__, __LINE__, __FUNCTION__ ));
00333 
00334       }
00335 
00336     } else {
00337 
00338       if ( (status = CAENVME_BLTReadCycle(handleVX718_[unit_][chain_], startAddress, (unsigned char *)buffer, 
00339                                           (int) length, (CVAddressModifier) addressModifier, 
00340                                           (CVDataWidth) dataWidth, &actualTransferred))  != cvSuccess ) {
00341         
00342         throw( BusAdapterException( "Error during read block transfer", __FILE__, __LINE__, __FUNCTION__ ));
00343       }
00344     }
00345   
00346     if ( (uint32_t)actualTransferred != length ) {
00347         std::stringstream message;
00348         message << "Block transfer has only transferred " << std::dec << actualTransferred 
00349                 << " bytes instead of the requested " << length
00350                 << std::ends;
00351         throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00352     }
00353 }
00354 
00355 void HAL::CAENLinuxBusAdapter::writeBlock( DeviceIdentifier *vmeDevice,
00356                                       uint32_t startAddress,
00357                                       uint32_t length,      // in bytes
00358                                       uint32_t addressModifier,
00359                                       uint32_t dataWidth,
00360                                       char *buffer,
00361                                       HalAddressIncrement addressBehaviour )
00362     throw( BusAdapterException,
00363            UnsupportedException ){
00364 
00365     int actualTransferred, status;
00366 
00367     // The CAEN Adapter now supports byte swapping
00368     if ( dynamic_cast<HAL::CAENDeviceIdentifier*>(vmeDevice)->doSwapping() &&
00369          dataWidth > 1 ) {
00370         dataWidth += 16;
00371     }
00372 
00373      if ( addressBehaviour != HAL_DO_INCREMENT ) {
00374 
00375        if ( (status = CAENVME_FIFOBLTWriteCycle(handleVX718_[unit_][chain_], startAddress, (unsigned char *)buffer, 
00376                                                 (int) length, (CVAddressModifier) addressModifier, 
00377                                                 (CVDataWidth) dataWidth, &actualTransferred))  != cvSuccess ) {
00378          
00379          throw( BusAdapterException( "Error during write block transfer (FIFO mode)", __FILE__, __LINE__, __FUNCTION__ ));
00380        }
00381 
00382      } else {
00383 
00384        if ( (status = CAENVME_BLTWriteCycle(handleVX718_[unit_][chain_], startAddress, (unsigned char *)buffer, 
00385                                             (int) length, (CVAddressModifier) addressModifier, 
00386                                             (CVDataWidth) dataWidth, &actualTransferred))  != cvSuccess ) {
00387     
00388          throw( BusAdapterException( "Error during write block transfer", __FILE__, __LINE__, __FUNCTION__ ));
00389        }
00390 
00391      }
00392   
00393      if ( (uint32_t)actualTransferred != length ) {
00394        std::stringstream message;
00395        message << "Block transfer has only transferred " << std::dec << actualTransferred 
00396                << " bytes instead of the requested " << length
00397                << std::ends;
00398         throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00399      }
00400 }
00401 
00402 void HAL::CAENLinuxBusAdapter::readVersions( std::ostream& os ) const {
00403     if ( model_ == V2718 ) {
00404         os << "V2718 firmware : " << V2718FwRelease_ << "\n"
00405            << pcCardStr_ << " firmware : " << AX818FwRelease_ << "\n"
00406           //<< "A2719 firmware : " << A2719FwRelease_ << "\n"
00407            << "VMELibRelease  : " << VMELibRelease_  << "\n" 
00408            << std::ends;
00409     } else {
00410         os << "V1718 firmware : " << V1718FwRelease_ << "\n" << std::ends;
00411     }
00412 }
00413 
00414 void HAL::CAENLinuxBusAdapter::readDisplay(  std::ostream& os ) const
00415     throw( BusAdapterException ) {
00416 
00417     CVDisplay displayData;
00418     int status;
00419     if ( (status = CAENVME_ReadDisplay(handleVX718_[unit_][chain_], &displayData)) != cvSuccess ) {
00420         throw( BusAdapterException( "Could not read display.", __FILE__, __LINE__, __FUNCTION__ ));
00421     }
00422 
00423     os << "Address : " << std::hex << std::setw(8) << std::setfill('0') << displayData.cvAddress << std::endl;
00424     os << "Data    : " << std::hex << std::setw(8) << std::setfill('0') << displayData.cvData << std::endl;
00425     os << "AM      : " << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)displayData.cvAM << std::endl;
00426     os << std::endl;           
00427     os << "DS0     : " << std::setw(1) << (0x01 & displayData.cvDS0) << std::endl;      
00428     os << "DS1     : " << std::setw(1) << (0x01 & displayData.cvDS1) << std::endl;      
00429     os << "AS      : " << std::setw(1) << (0x01 & displayData.cvAS) << std::endl;       
00430     os << "IACK    : " << std::setw(1) << (0x01 & displayData.cvIACK) << std::endl;     
00431     os << "WRITE   : " << std::setw(1) << (0x01 & displayData.cvWRITE) << std::endl;
00432     os << "LWORD   : " << std::setw(1) << (0x01 & displayData.cvLWORD) << std::endl;
00433     os << "DTACK   : " << std::setw(1) << (0x01 & displayData.cvDTACK) << std::endl;
00434     os << "BERR    : " << std::setw(1) << (0x01 & displayData.cvBERR) << std::endl;     
00435     os << "SYSRES  : " << std::setw(1) << (0x01 & displayData.cvSYSRES) << std::endl;
00436     os << "BR      : " << std::setw(1) << (0x01 & displayData.cvBR) << std::endl;
00437     os << "BG      : " << std::setw(1) << (0x01 & displayData.cvBG) << std::endl;   
00438 }
00439 
00440 
00441 void HAL::CAENLinuxBusAdapter::enableIRQ( uint32_t mask ) const
00442   throw( BusAdapterException ) {  
00443   int status;
00444   status = CAENVME_IRQEnable(handleVX718_[unit_][chain_], mask);
00445   if ( status != cvSuccess ) {
00446     std::stringstream message;
00447     message << "Could not enable Interrupts: CAEN error " << std::dec << status 
00448             << std::ends;
00449     throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00450   }
00451 }
00452 
00453 void HAL::CAENLinuxBusAdapter::disableIRQ( uint32_t mask ) const 
00454   throw( BusAdapterException ) {  
00455   int status;
00456   status = CAENVME_IRQDisable(handleVX718_[unit_][chain_], mask);
00457   if ( status != cvSuccess ) {
00458     std::stringstream message;
00459     message << "Could not disable Interrupts: CAEN error " << std::dec << status 
00460             << std::ends;
00461     throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00462   }
00463 }
00464 
00465 uint32_t  HAL::CAENLinuxBusAdapter::checkIRQ( ) const
00466   throw( BusAdapterException ) {  
00467   int status;
00468   CAEN_BYTE retval;
00469   status = CAENVME_IRQCheck(handleVX718_[unit_][chain_], &retval);
00470   if ( status != cvSuccess ) {
00471     std::stringstream message;
00472     message << "Could not check for Interrupts: CAEN error " << std::dec << status 
00473             << std::ends;
00474     throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00475   }
00476   return (uint32_t)retval;
00477 }
00478 
00479 uint32_t HAL::CAENLinuxBusAdapter::waitIRQ( uint32_t mask, uint32_t timeoutMs ) const 
00480   throw( BusAdapterException ) {  
00481   int status;
00482   status = CAENVME_IRQWait(handleVX718_[unit_][chain_], mask, timeoutMs);
00483   if ( status != cvSuccess ) {
00484   //  // This currently means that there was either a problem
00485   //  // or the timeout has fired. So we cannot assume that 
00486   //  // something went wrong. 
00487   //
00488   //  //std::stringstream message;
00489   //  //message << "Could not wait for Interrupts: CAEN error " << std::dec << status 
00490   //  //            << std::ends;
00491   //  //throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00492     return 0;
00493   }
00494   uint32_t retmask = checkIRQ();
00495   return retmask;
00496 }
00497 
00498 void HAL::CAENLinuxBusAdapter::acknowledgeIRQ( uint32_t level, void* vector, uint32_t width ) const 
00499   throw( BusAdapterException ) {
00500   int status;
00501   status = CAENVME_IACKCycle(handleVX718_[unit_][chain_], (CVIRQLevels)level, vector, (CVDataWidth)width);
00502   if ( status != cvSuccess ) {
00503     std::stringstream message;
00504     message << "Could not acknowledge Interrupt: CAEN error " << std::dec << status 
00505             << std::ends;
00506     throw( BusAdapterException( message.str(), __FILE__, __LINE__, __FUNCTION__ ));
00507   }
00508 }