/* * BufferFiller.hh * * There is going to be a single object of this class that will * run in a separate thread to read a single VETROC board and * fill the circular buffer. This class inherits from BufferSubscriber. * * Created on: Dec 14, 2017 * Author: Hovanes Egiyan */ #ifndef BUFFERFILLER_HH_ #define BUFFERFILLER_HH_ extern "C" { #include "jvme.h" #include "vetrocLib.h" } #include #include #include #include #include #include #include #include #include // for auto_cpu_timer #include "BufferSubscriber.hh" // This pointer is something that is used in JLAB DMA library when // manipulating the DMA buffers. Although it may not be explicitly present in the // code, it shows up because of the macros like GETEVENT and PUTEVENT. extern DMANODE *the_event; // This pointer is something that is used in JLAB DMA library when // manipulating the DMA buffers. This is needed when using the VETROC // library to block-read. extern unsigned int *dma_dabufp; namespace VETROC { struct DMAItem { protected: DMANODE *outEvent; public: DMAItem( DMANODE* node = 0 ) : outEvent( node ) { } DMAItem( const DMAItem& item ) : outEvent( item.outEvent ) { } ~DMAItem() { if( outEvent != 0 ) dmaPFreeItem( outEvent ); } DMANODE* getOutEvent() { return outEvent; } }; template class BufferFiller: public BufferSubscriber { private: BufferFiller( const BufferFiller& ); BufferFiller& operator=( const BufferFiller& ); protected: // Slot number that the filling object needs to fill. // Currently only single VETROC board is supported. int slotNumber; // Mas of the slots for the filler unsigned slotMask; // Input and output DMA queues that are used by JLAB CODA DMA reading framework. // Values for these are passed from outside when the constructor is called. DMA_MEM_ID dmaInputQueue; DMA_MEM_ID dmaOutputQueue; // // Minimum number of free slots in the circular buffer that needs to be // // there for this filling class object pushed new entries into the buffer. // // This number should be sufficient to make a 1 second worth of data from the // // buffer. // static unsigned MinimumNumberOfBufferSlots; public: BufferFiller( BUFFER* buffer, unsigned slot, DMA_MEM_ID inQue, DMA_MEM_ID outQue ) : BufferSubscriber( buffer ), slotNumber( slot ), slotMask( 1 << slotNumber ), dmaInputQueue( inQue ), dmaOutputQueue( outQue ) { this->setActiveSleepTime( 1 ); } virtual ~BufferFiller() { } // Operator in case one wants to use this class as a functor void operator()() { keepFillingBuffer(); } // Method that gets run in the new thread. It calls a method with // the infinite loop that fills the buffer. void keepFillingBuffer() { this->setAccessingRequested( true ); std::cout << "Will keep filling" << std::endl; while ( !this->isExitThreadFlagRaised() ) { // std::cout << "Keep going" << std::endl; if ( this->isAccessingRequested() ) { // Go to filling state this->fillBuffer(); } usleep( this->getPassiveSleepTime() ); } } // Method that runs the infinite loop to fill the buffer (filling state). void fillBuffer() { std::cout << "In filling buffer" << std::endl; unsigned long iBuffer = 0; boost::timer::auto_cpu_timer progress; while ( this->isAccessingRequested() ) { // std::cout << "Filling requested" << std::endl; DMAItem dmaItem; unsigned* sourcePointer = 0; if ( sourceIsReady() ) { try { dmaItem = getItemDMA(); // std::cout << "Received event pointer " << std::hex << dmaItem.getOutEvent() // << " with length " << dmaItem.getOutEvent()->length << std::endl; } catch ( std::runtime_error& err ) { // If runtime error encountered, jump to the next event std::cout << err.what() << std::endl; continue; } // If the DMA item received successfully, transfer the data into the circular buffer // and free the DMA item pointer. sourcePointer = dmaItem.getOutEvent()->data; // If container is not full then push data to the front // if ( this->m_container->getNumberOfFreeSlots() // > BufferFiller::MinimumNumberOfBufferSlots ) { // if ( this->m_container->is_not_full() ) { typename VETROC::BufferSubscriber::value_type value( sourcePointer ); this->m_container->pushFront( value ); // std::cout << "Length is " << std::dec << dmaItem.getOutEvent()->length // << std::endl; // this->m_container->pushFront( // typename VETROC::BufferSubscriber::value_type( // sourcePointer ) ); // std::cout << "Filled" << std::endl; // std::cout << "Filled value " << value << std::endl; // } // Need to free the DMA item here, the getItemDMA does not free it. iBuffer++; unsigned mult = 10; if ( (iBuffer % (mult * SIZE)) == 0 && iBuffer > 0 ) { for ( unsigned iWord = 0; iWord < dmaItem.getOutEvent()->length; iWord++ ) { // std::cout << "Word " << iWord ; // decodeData( LSWAP(sourcePointer[iWord]) ); // std::cout << "Writer : " << iWord ; // decodeData( LSWAP(value[iWord]) ); } std::cout << "Filled " << std::dec << iBuffer << " buffers " << std::endl; // std::cout << "The number of elements in the circular buffer is " // << this->m_container->getSize() << std::endl; progress.report(); } } } } // Check if there are triggers in all VETROC boards and return true // if true. virtual bool sourceIsReady() const { // Check which slots with VETROC board are ready unsigned readySlotMask = vetrocGBready(); // std::cout << "readySlotMask is " << std::hex << readySlotMask << " , slotMask is " << slotMask << std::endl; // DMA is complete if all boards that were there are read bool dmaIsComplete = ((readySlotMask != 0) && (readySlotMask == slotMask)); // std::cout << "DMA is complete is " << dmaIsComplete << std::endl; return dmaIsComplete; } DMAItem& getItemDMA() { static long unsigned eventNumber = 1; // if ( (eventNumber % 1000) == 0 ) { // std::cout << "Getting Event #" << dec << eventNumber << std::endl; // } // std::cout << "Preparing input queue with " << hex << showbase << dmaInputQueue << std::endl; boost::mutex::scoped_lock lock( this->m_mutex ); GETEVENT( dmaInputQueue, eventNumber ); // std::cout << "Initiating DMA readout" << std::endl; int numberOfWordsRead = vetrocReadBlock( slotNumber, dma_dabufp, 10000, 1 ); dma_dabufp += numberOfWordsRead; // std::cout << "Putting event" << std::endl; PUTEVENT( dmaOutputQueue ); // std::cout << "Getting DMA item" << std::endl; DMANODE* outEvent = dmaPGetItem( dmaOutputQueue ); unsigned eventLength = (outEvent->length); // std::cout << "eventLegth is " << std::dec << eventLength // << " in the beginning for event pointer " << std::hex << outEvent << std::endl; if ( eventLength != 8460 ) { std::stringstream errMsg; errMsg << "The length read from the board is " << std::dec << eventLength << " words" << std::endl; errMsg << "BufferFiller::getItemDMA() : Wrong number of words"; throw std::runtime_error( errMsg.str() ); } if ( eventLength == 0 ) printf( "VETROC: no data or error. Bye ! \n" ); if ( eventLength == 0 ) { std::stringstream errMsg; std::cout << "Will throw an exception because got zero words" << std::endl; errMsg << "BufferFiller::getItemDMA() : No data or error encountered"; throw std::runtime_error( errMsg.str() ); } eventNumber++; DMAItem* itemPointer = new DMAItem( outEvent ); // std::cout << "eventLegth is " << std::dec << itemPointer->getOutEvent()->length // << " before returning for event pointer " << std::hex << itemPointer->getOutEvent() // << std::endl; return *itemPointer; } void startFilling() { this->setAccessingRequested( true ); } void stopFilling() { this->setAccessingRequested( false ); } DMA_MEM_ID getDmaInputQueue() const { return dmaInputQueue; } DMA_MEM_ID getDmaOutputQueue() const { return dmaOutputQueue; } unsigned getSlotMask() const { return slotMask; } int getSlotNumber() const { return slotNumber; } }; // template // unsigned BufferFiller::MinimumNumberOfBufferSlots = 100; } /* namespace VETROC */ #endif /* BUFFERFILLER_HH_ */