/* * vmeChassis.hh * * Created on: June 16, 2014 * Author: * * This class provides interface that EPICS support will use to monitor * and control the JLAB boards on a VME/VXS chassis. * All methods, including accessors, need to be thread-safe since they * may be executing simultaneously on multiple threads. */ #ifndef _vmeChassis_HH_ #define _vmeChassis_HH_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "jlabBoard.hh" using namespace std; void* SharedMemoryThreadFunction(void* locArgument); template class vmeChassis { public: // Constructor. Open communication for the chassis specified by IP address. // Create all board objects on that chassis and fill the board map. // Throws an exception if fails to create the object or the chassis // already has been connected. vmeChassis(bool locDebugFlag = false); // Destructor. Destroys this chassis. ~vmeChassis(); // Return the 32-bit status word for this board uint32_t GetStatus() const; // Return the number of boards this chassis is serving uint32_t GetNumberOfBoards() const; // Return the number of boards this chassis is serving uint32_t GetNumberOfSlots() const; // Return the map with the boards that the chassis can see, of the given type. The key is the slot number. map GetBoardMap() const; // Return the board T* GetBoard(uint32_t locSlotNumber) const; // Return IP address of the CPU string GetIP() const; static map GetMapOfChassis(){return vcMapOfChassis;} // Determine the IP4 address of the host. Technically, will return the // address of "first" active Ethernet interface on this host. static string FindIP4(); protected: // Prevent copying boards vmeChassis(const vmeChassis& chassis); vmeChassis& operator=(const vmeChassis& chassis); bool dDebugFlag; // IP address of the VME controller on this chassis string ipAddress; // Map with the boards that the chassis can see. The key is the slot number. map dBoardMap; // Map of chassis that have been connected so far static map vcMapOfChassis; jlabROCSharedMemoryWrapper* dROCSharedMemoryWrapper; static const uint32_t dNumSlots = 21; pthread_t dMemoryReaderThread; }; template vmeChassis::vmeChassis(bool locDebugFlag) : dDebugFlag(locDebugFlag) { // Create shared memory wrapper, which creates board objects (since it can find out which boards are in which slots) if(dDebugFlag) cout << "Create Memory Wrapper" << endl; dROCSharedMemoryWrapper = new jlabROCSharedMemoryWrapper(dDebugFlag); if(dDebugFlag) cout << "Memory Wrapper Created" << endl; // Grab boards created by shared memory wrapper, and set them here for(uint32_t locSlot = 1; locSlot <= dNumSlots; ++locSlot) { // if(dDebugFlag) // cout << "Looking for a board of type " << typeid(T).name()<< " in slot " << locSlot << endl; jlabBoard* boardAddress = dROCSharedMemoryWrapper->GetBoard(locSlot); if(dDebugFlag) cout << "Address is " << hex << showbase << boardAddress << " cast address is " << dynamic_cast(boardAddress) << endl; if( dynamic_cast(boardAddress) != NULL ) dBoardMap[locSlot] = dynamic_cast(boardAddress); } // LAUNCH THREAD WITH WRAPPER if(dDebugFlag) cout << "Launch Thread" << endl; if(pthread_create(&dMemoryReaderThread, NULL, SharedMemoryThreadFunction, (void*)dROCSharedMemoryWrapper) != 0) { cout << "FAILED TO LAUNCH THREAD IN vmeChassis CONSTRUCTOR, UNABLE TO READ IN SCALARS. ABORTING." << endl; abort(); } if(dDebugFlag) cout << "Thread Launched" << endl; ipAddress = FindIP4(); // Determine the IP address if(dDebugFlag) cout << "IP address found is " << ipAddress << endl; return; } template vmeChassis::~vmeChassis(void) { dROCSharedMemoryWrapper->Stop_SharedMemoryThread(); pthread_join(dMemoryReaderThread, NULL); delete dROCSharedMemoryWrapper; } template inline uint32_t vmeChassis::GetStatus() const { //DEFINE ME return 0; } template inline string vmeChassis::GetIP() const { return ipAddress; } template inline T* vmeChassis::GetBoard(uint32_t locSlotNumber) const { typename map::const_iterator locIterator = dBoardMap.find(locSlotNumber); return ((locIterator != dBoardMap.end()) ? locIterator->second : NULL); } template inline uint32_t vmeChassis::GetNumberOfSlots(void) const { return dNumSlots; } template map vmeChassis::GetBoardMap() const { map locTypeBoardMap; typename map::const_iterator locIterator = dBoardMap.begin() ; for(; locIterator != dBoardMap.end(); ++locIterator) { T* locBoard = dynamic_cast(locIterator->second); if(locBoard != NULL) locTypeBoardMap.insert(pair(locIterator->first, locBoard)); } return locTypeBoardMap; } template uint32_t vmeChassis::GetNumberOfBoards() const { uint32_t locNumBoards = 0; typename map::const_iterator locIterator = dBoardMap.begin(); for(; locIterator != dBoardMap.end(); ++locIterator) { T* locBoard = dynamic_cast(locIterator->second); if(locBoard != NULL) ++locNumBoards; } return locNumBoards; } // Method to obtain the IP address of this host. // Lifted from an example at http://stackoverflow.com/questions/4130147/get-local-ip-address-in-c-linux template string vmeChassis::FindIP4() { string tempAddress; struct ifaddrs * ifAddrStruct=NULL; struct ifaddrs * ifa=NULL; void * tmpAddrPtr=NULL; getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4 // is a valid IP4 Address tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; char addressBuffer[INET_ADDRSTRLEN]; inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); // printf("'%s': %s\n", ifa->ifa_name, addressBuffer); if( strcmp( ifa->ifa_name, "lo" ) != 0 ) { // Assign IP address to the value in addressBuffer and break from the loop // if this is not the loopback interface tempAddress = string( addressBuffer ); break; } } else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6 // is a valid IP6 Address tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; char addressBuffer[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); // printf("'%s': %s\n", ifa->ifa_name, addressBuffer); } } // Free the allocated structures if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);//remember to free ifAddrStruct return tempAddress; } #endif /* _vmeChassis_HH_ */