@@ -89,6 +89,8 @@ void ReadoutDevice::PreRun()
8989 mGui = std::make_unique<RootGui>(" Emulator" , " Readout Emulator" , 500 , 500 );
9090 mGuiThread = std::thread (&ReadoutDevice::GuiThread, this );
9191 }
92+
93+ mSendingThread = std::thread (&ReadoutDevice::SendingThread, this );
9294}
9395
9496void ReadoutDevice::ResetTask ()
@@ -101,65 +103,85 @@ void ReadoutDevice::ResetTask()
101103 if (mBuildHistograms && mGuiThread .joinable ()) {
102104 mGuiThread .join ();
103105 }
106+
107+ if (mSendingThread .joinable ()) {
108+ mSendingThread .join ();
109+ }
104110}
105111
106112bool ReadoutDevice::ConditionalRun ()
107113{
114+ using namespace std ::chrono_literals;
115+ std::this_thread::sleep_for (1s);
116+ return true ;
117+ }
118+
119+ void ReadoutDevice::SendingThread ()
120+ {
121+
122+ WaitForRunningState ();
123+
108124 auto & lOutputChan = GetChannel (mOutChannelName , 0 );
109125
110126 // finish an STF every ~1/45 seconds
111127 static const auto cDataTakingStart = std::chrono::high_resolution_clock::now ();
112- static constexpr auto cStfInterval = std::chrono::microseconds (22222 );
128+ static constexpr auto cStfInterval = std::chrono::microseconds (22810 );
113129 static uint64_t lNumberSentStfs = 0 ;
130+ static uint64_t lCurrentTfId = 0 ;
114131
115- auto isStfFinished =
116- (std::chrono::high_resolution_clock::now () - cDataTakingStart) - (lNumberSentStfs * cStfInterval) > cStfInterval;
117-
118- if (isStfFinished)
119- lNumberSentStfs += 1 ;
120-
121- ReadoutLinkO2Data lCruLinkData;
122- if (!mCruMemoryHandler ->getLinkData (lCruLinkData)) {
123- LOG (INFO) << " GetLinkData failed. Stopping interface thread." ;
124- return false ;
125- }
126-
127- if (mBuildHistograms )
128- mFreeSuperpagesSamples .Fill (mCruMemoryHandler ->free_superpages ());
129-
130- // check no data signal
131- if (lCruLinkData.mLinkDataHeader .subSpecification ==
132- o2::header::DataHeader::SubSpecificationType (-1 )) {
133- // LOG(WARN) << "No Superpages left! Losing data...";
134- return true ;
135- }
136-
137- ReadoutSubTimeframeHeader lHBFHeader;
138- lHBFHeader.mTimeFrameId = lNumberSentStfs;
139- lHBFHeader.mNumberHbf = lCruLinkData.mLinkRawData .size ();
140- lHBFHeader.mLinkId = lCruLinkData.mLinkDataHeader .subSpecification ;
141-
142- assert (mDataBlockMsgs .empty ());
143- mDataBlockMsgs .reserve (lCruLinkData.mLinkRawData .size ());
144-
145- // create messages for the header
146- mDataBlockMsgs .emplace_back (lOutputChan.NewMessage (sizeof (ReadoutSubTimeframeHeader)));
147- std::memcpy (mDataBlockMsgs .front ()->GetData (), &lHBFHeader, sizeof (ReadoutSubTimeframeHeader));
148-
149- // create messages for the data
150- for (const auto & lDmaChunk : lCruLinkData.mLinkRawData ) {
151- // mark this as used in the memory handler
152- mCruMemoryHandler ->get_data_buffer (lDmaChunk.mDataPtr , lDmaChunk.mDataSize );
132+ while (IsRunningState ()) {
153133
154- // create a message out of unmanaged region
155- mDataBlockMsgs .emplace_back (lOutputChan.NewMessage (mDataRegion , lDmaChunk.mDataPtr , lDmaChunk.mDataSize ));
134+ auto isStfFinished =
135+ (std::chrono::high_resolution_clock::now () - cDataTakingStart) - (lNumberSentStfs * cStfInterval) > cStfInterval;
136+
137+ if (isStfFinished) {
138+ lNumberSentStfs += 1 ;
139+ lCurrentTfId = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now ().time_since_epoch ()).count () / cStfInterval.count ();
140+ }
141+
142+ ReadoutLinkO2Data lCruLinkData;
143+ if (!mCruMemoryHandler ->getLinkData (lCruLinkData)) {
144+ LOG (INFO) << " GetLinkData failed. Stopping interface thread." ;
145+ return ;
146+ }
147+
148+ if (mBuildHistograms ) {
149+ mFreeSuperpagesSamples .Fill (mCruMemoryHandler ->free_superpages ());
150+ }
151+
152+ // check no data signal
153+ if (lCruLinkData.mLinkDataHeader .subSpecification ==
154+ o2::header::DataHeader::SubSpecificationType (-1 )) {
155+ // LOG(WARN) << "No Superpages left! Losing data...";
156+ }
157+
158+ ReadoutSubTimeframeHeader lHBFHeader;
159+ lHBFHeader.mTimeFrameId = lCurrentTfId;
160+ lHBFHeader.mNumberHbf = lCruLinkData.mLinkRawData .size ();
161+ lHBFHeader.mLinkId = lCruLinkData.mLinkDataHeader .subSpecification ;
162+
163+ assert (mDataBlockMsgs .empty ());
164+ mDataBlockMsgs .reserve (lCruLinkData.mLinkRawData .size ());
165+
166+ // create messages for the header
167+ mDataBlockMsgs .emplace_back (lOutputChan.NewMessage (sizeof (ReadoutSubTimeframeHeader)));
168+ std::memcpy (mDataBlockMsgs .front ()->GetData (), &lHBFHeader, sizeof (ReadoutSubTimeframeHeader));
169+
170+ // create messages for the data
171+ for (const auto & lDmaChunk : lCruLinkData.mLinkRawData ) {
172+ // mark this as used in the memory handler
173+ mCruMemoryHandler ->get_data_buffer (lDmaChunk.mDataPtr , lDmaChunk.mDataSize );
174+
175+ // create a message out of unmanaged region
176+ mDataBlockMsgs .emplace_back (lOutputChan.NewMessage (mDataRegion , lDmaChunk.mDataPtr , lDmaChunk.mDataSize ));
177+ }
178+
179+ lOutputChan.Send (mDataBlockMsgs );
180+ mDataBlockMsgs .clear ();
156181 }
182+ }
157183
158- lOutputChan.Send (mDataBlockMsgs );
159- mDataBlockMsgs .clear ();
160184
161- return true ;
162- }
163185
164186void ReadoutDevice::GuiThread ()
165187{
0 commit comments