Line data Source code
1 :
2 : #include "TRACE/tracemf.h"
3 : #define TRACE_NAME "CFO.cpp"
4 :
5 : #include "CFO.h"
6 : #define TLVL_GetData TLVL_DEBUG + 5
7 : #define TLVL_ReadBuffer TLVL_DEBUG + 7
8 : #define TLVL_ReadNextDAQPacket TLVL_DEBUG + 8
9 : #define TLVL_ReleaseBuffers TLVL_DEBUG + 20
10 : #define TLVL_GetCurrentBuffer TLVL_DEBUG + 21
11 :
12 : #include "dtcInterfaceLib/otsStyleCoutMacros.h"
13 :
14 : #define CFO_TLOG(lvl) TLOG(lvl) << "CFO " << device_.getDeviceUID() << ": "
15 : #undef __COUT_HDR__
16 : #define __COUT_HDR__ "CFO " << device_.getDeviceUID() << ": "
17 :
18 : #include <unistd.h>
19 : #include <fstream>
20 : #include <iostream>
21 : #include <sstream> // Convert uint to hex string
22 :
23 0 : CFOLib::CFO::CFO(DTC_SimMode mode, int cfo, std::string expectedDesignVersion, bool skipInit, const std::string& uid)
24 0 : : CFO_Registers(mode, cfo, expectedDesignVersion, skipInit, uid), daqDMAInfo_() //, dcsDMAInfo_()
25 : {
26 0 : __COUT_INFO__ << "CONSTRUCTOR";
27 0 : }
28 :
29 0 : CFOLib::CFO::~CFO()
30 : {
31 0 : __COUT_INFO__ << "DESTRUCTOR";
32 : // TLOG_ENTEX(-6);
33 0 : TRACE_EXIT
34 : {
35 0 : __COUT__ << "DESTRUCTOR exit";
36 0 : };
37 :
38 : // do not want to release all from destructor, in case this instance of the device is not the 'owner' of a DMA-channel
39 : // so do not call ReleaseAllBuffers(CFO_DMA_Engine_DAQ) or ReleaseAllBuffers(CFO_DMA_Engine_RunPlan);
40 0 : }
41 :
42 : //
43 : // DMA Functions
44 : //
45 0 : bool CFOLib::CFO::GetData(std::vector<std::unique_ptr<CFOLib::CFO_Event>>& output,
46 : DTC_EventWindowTag when, bool matchEventWindowTag)
47 : {
48 0 : CFO_TLOG(TLVL_GetData) << "GetCFOEventData begin EventWindowTag=" << when.GetEventWindowTag(true) << ", matching=" << (matchEventWindowTag ? "true" : "false");
49 : // std::vector<std::unique_ptr<CFO_Event>> output;
50 0 : output.clear(); // start out with vector empty
51 0 : bool result = false;
52 :
53 : // Release read buffers here "I am done with everything I read before" (because the return may be pointers to the raw data, not copies)
54 0 : ReleaseBuffers(DTC_DMA_Engine_DAQ); // Currently race condition because GetCurrentBuffer(info) is used inside to decide how many buffers to release.
55 :
56 : try
57 : {
58 : // Read the next CFO_Event
59 0 : auto tries = 0;
60 0 : while (!result && tries < 3)
61 : {
62 0 : CFO_TLOG(TLVL_GetData) << "GetCFOEventData before ReadNextCFORecordDMA(...), tries = " << tries;
63 0 : result = ReadNextCFORecordDMA(output, 100 /* ms */);
64 0 : if (result)
65 : {
66 0 : if (output.size() == 0) // check that output vector is not empty
67 :
68 : {
69 0 : __SS__ << "Impossible empty ouput vector after returned success!" << __E__;
70 0 : __SS_THROW__;
71 0 : }
72 :
73 0 : CFO_TLOG(TLVL_GetData) << "GetCFOEventData after ReadNextCFORecordDMA, found tag = "
74 0 : << output.back()->GetEventWindowTag().GetEventWindowTag(true) << " (0x"
75 0 : << std::hex << output.back()->GetEventWindowTag().GetEventWindowTag(true) << "), expected tag = "
76 0 : << std::dec << when.GetEventWindowTag(true) << " (0x" << std::hex << when.GetEventWindowTag(true) << ")";
77 : }
78 : else
79 0 : CFO_TLOG(TLVL_GetData) << "GetCFOEventData after ReadNextCFORecordDMA, no data";
80 0 : tries++;
81 : // if (!result) usleep(5000); //causes loss of bandwidth
82 : }
83 :
84 : // return if no data found
85 0 : if (!result)
86 : {
87 0 : CFO_TLOG(TLVL_GetData) << "GetData: Timeout Occurred! (CFO_Event is nullptr after retries); no data found; RETURNing output.size()=" << output.size();
88 0 : return output.size();
89 : }
90 :
91 : // return if failed to match
92 0 : if (matchEventWindowTag && output[0]->GetEventWindowTag() != when)
93 : {
94 0 : CFO_TLOG(TLVL_ERROR) << "GetData: Error: CFO_Event has wrong Event Window Tag! 0x" << std::hex << when.GetEventWindowTag(true)
95 0 : << "(expected) != 0x" << std::hex << output[0]->GetEventWindowTag().GetEventWindowTag(true);
96 : // packet.reset(nullptr);
97 0 : daqDMAInfo_.currentReadPtr = daqDMAInfo_.lastReadPtr;
98 0 : return output.size();
99 : }
100 :
101 : // // increment for next packet search
102 : // when = DTC_EventWindowTag(packet->GetEventWindowTag().GetEventWindowTag(true) + 1);
103 :
104 : // CFO_TLOG(TLVL_GetData) << "GetData: Adding CFO_Event tag = " << packet->GetEventWindowTag().GetEventWindowTag(true) << " to the list, ptr=" << (void*)daqDMAInfo_.lastReadPtr;
105 : // output.push_back(std::move(packet));
106 : }
107 0 : catch (DTC_WrongPacketTypeException& ex)
108 : {
109 0 : daqDMAInfo_.currentReadPtr = nullptr;
110 0 : CFO_TLOG(TLVL_ERROR) << "GetData: Bad omen: Wrong packet type at the current read position";
111 0 : device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
112 0 : throw;
113 0 : }
114 0 : catch (DTC_IOErrorException& ex)
115 : {
116 0 : daqDMAInfo_.currentReadPtr = nullptr;
117 0 : CFO_TLOG(TLVL_ERROR) << "GetData: IO Exception Occurred!";
118 0 : device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
119 0 : throw;
120 0 : }
121 0 : catch (DTC_DataCorruptionException& ex)
122 : {
123 0 : daqDMAInfo_.currentReadPtr = nullptr;
124 0 : CFO_TLOG(TLVL_ERROR) << "GetData: Data Corruption Exception Occurred!";
125 0 : device_.spy(DTC_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */ | 16 /* for stack trace */);
126 0 : throw;
127 0 : }
128 :
129 0 : CFO_TLOG(TLVL_GetData) << "GetCFOEventData RETURN output.size()=" << output.size()
130 0 : << " first tag=" << output[0]->GetEventWindowTag().GetEventWindowTag(true)
131 0 : << " last tag=" << output.back()->GetEventWindowTag().GetEventWindowTag(true);
132 0 : return output.size();
133 : } // GetData
134 :
135 0 : bool CFOLib::CFO::ReadNextCFORecordDMA(std::vector<std::unique_ptr<CFO_Event>>& output, int tmo_ms)
136 : {
137 0 : TRACE_EXIT
138 : {
139 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA EXIT"
140 0 : << " currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
141 0 : << " lastReadPtr=" << (void*)daqDMAInfo_.lastReadPtr
142 0 : << " buffer.size()=" << daqDMAInfo_.buffer.size();
143 0 : };
144 :
145 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEGIN";
146 :
147 0 : if (daqDMAInfo_.currentReadPtr != nullptr)
148 : {
149 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEFORE BUFFER CHECK daqDMAInfo_.currentReadPtr="
150 0 : << (void*)daqDMAInfo_.currentReadPtr << " currentBufferTransferSize=0x" << std::hex
151 0 : << *(uint16_t*)daqDMAInfo_.currentReadPtr;
152 : }
153 : else
154 : {
155 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA BEFORE BUFFER CHECK daqDMAInfo_.currentReadPtr=nullptr";
156 : }
157 :
158 0 : auto index = CFOandDTC_DMAs::GetCurrentBuffer(&daqDMAInfo_); // if buffers onhand, returns daqDMAInfo_.buffer.size().. which is count used by ReleaseBuffers()
159 :
160 0 : size_t metaBufferSize = 0;
161 :
162 : // Need new starting subevent buffer if GetCurrentBuffer returns -1 (no buffers) or -2 (done with all held buffers)
163 0 : if (index < 0)
164 : {
165 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA Obtaining new DAQ Buffer";
166 :
167 0 : void* oldBufferPtr = nullptr;
168 0 : if (daqDMAInfo_.buffer.size() > 0) oldBufferPtr = &daqDMAInfo_.buffer.back()[0];
169 0 : auto sts = ReadBuffer(DTC_DMA_Engine_DAQ, tmo_ms); // does return code
170 0 : if (sts <= 0)
171 : {
172 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA: ReadBuffer returned " << sts << ", returning nullptr";
173 0 : return false;
174 : }
175 0 : metaBufferSize = sts;
176 :
177 : // MUST BE ABLE TO HANDLE daqbuffer_==nullptr OR retry forever?
178 0 : daqDMAInfo_.currentReadPtr = &daqDMAInfo_.buffer.back()[0];
179 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA daqDMAInfo_.currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
180 0 : << " currentBufferTransferSize=0x" << std::hex << *(unsigned*)daqDMAInfo_.currentReadPtr
181 0 : << " lastReadPtr=0x" << (void*)daqDMAInfo_.lastReadPtr
182 0 : << " metaBufferSize=0x" << metaBufferSize;
183 0 : void* bufferIndexPointer = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
184 0 : if (daqDMAInfo_.currentReadPtr == oldBufferPtr && daqDMAInfo_.bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
185 : {
186 0 : daqDMAInfo_.currentReadPtr = nullptr;
187 : // We didn't actually get a new buffer...this probably means there's no more data
188 : // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
189 0 : device_.read_release(DTC_DMA_Engine_DAQ, 1);
190 0 : CFO_TLOG(TLVL_WARN)
191 0 : << "ReadNextCFORecordDMA: New buffer was the same as old. Released buffer and returning nullptr";
192 0 : return false;
193 : }
194 0 : daqDMAInfo_.bufferIndex++;
195 :
196 0 : daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
197 0 : *static_cast<uint32_t*>(daqDMAInfo_.currentReadPtr) = daqDMAInfo_.bufferIndex;
198 0 : daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
199 :
200 0 : index = daqDMAInfo_.buffer.size() - 1;
201 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "Creating CFO_EventRecord(s) from new DMA Buffer, index=" << index << " in " << daqDMAInfo_.buffer.size() << " buffers.";
202 : }
203 : else // buffer already onhand
204 : {
205 0 : __SS__ << "Impossible buffer already onhand!" << __E__;
206 0 : __SS_THROW__;
207 :
208 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "Creating CFO_EventRecord from current DMA Buffer, index=" << index <<
209 : // " in " << daqDMAInfo_.buffer.size() << " buffers.";
210 0 : }
211 :
212 0 : if ( // current read ptr sanity check
213 0 : (void*)(static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) - 8) !=
214 0 : (void*)(&daqDMAInfo_.buffer[index][0]))
215 : {
216 0 : __SS__ << "Impossible current buffer pointer for index " << index << ".. " << (void*)(static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) - 8) << " != " << (void*)&daqDMAInfo_.buffer[index - 1][0] << __E__;
217 0 : __SS_THROW__;
218 0 : }
219 :
220 : // Utilities::PrintBuffer(daqDMAInfo_.currentReadPtr, 128, TLVL_ReadNextDAQPacket);
221 : // auto res = std::make_unique<CFO_Event>(daqDMAInfo_.currentReadPtr);
222 : // complete data was copied into CFO Event Record
223 :
224 : // auto subEventByteCount = res->GetSubEventByteCount();
225 : // if (subEventByteCount < sizeof(CFO_EventRecord))
226 : // {
227 : // __SS__ << "SubEvent inclusive byte count cannot be less than the size of the subevent header (" << sizeof(CFO_EventRecord) << "-bytes)!" << __E__;
228 : // __SS_THROW__;
229 : // }
230 0 : size_t remainingBufferSize = CFOandDTC_DMAs::GetBufferByteCount(&daqDMAInfo_, index);
231 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "sizeof(CFO_EventRecord) = " << sizeof(CFO_EventRecord)
232 0 : << " GetBufferByteCount=" << remainingBufferSize
233 0 : << " metaBufferSize=" << metaBufferSize;
234 :
235 : // Use DMA descriptor byte count from ReadBuffer (dont use the in-buffer DMA transfer size count because the CFO stacks transfers!)
236 : // Subtract 1 for tlast byte, but NOT when buffer is completely full (no room for tlast)
237 0 : remainingBufferSize = metaBufferSize < sizeof(mu2e_databuff_t) ? metaBufferSize - 1 : metaBufferSize;
238 :
239 : // if (0) // for deubbging
240 : // {
241 : // std::cout << "1st DMA buffer res size=" << remainingBufferSize << "\n";
242 : // auto ptr = reinterpret_cast<const uint8_t*>(res->GetRawBufferPointer());
243 : // for (size_t i = 0; i < remainingBufferSize + 16; i += 4)
244 : // std::cout << std::dec << "res#" << i << "/" << remainingBufferSize << "(" << i / 16 << "/" << remainingBufferSize / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
245 : // }
246 :
247 0 : uint64_t lastTag = -1;
248 0 : while (remainingBufferSize >= sizeof(CFO_EventRecord))
249 : {
250 0 : remainingBufferSize -= sizeof(uint64_t); // remove DMA transfer size from remaining byte count
251 :
252 0 : auto res = std::make_unique<CFO_Event>(daqDMAInfo_.currentReadPtr);
253 :
254 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "subevent tag=" << res->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << res->GetEventWindowTag().GetEventWindowTag(true) << ")"
255 0 : << " inclusive byte count: 0x" << std::hex << sizeof(CFO_EventRecord) << " (" << std::dec << sizeof(CFO_EventRecord) << ")"
256 0 : << ", remaining buffer size: 0x" << std::hex << remainingBufferSize << " (" << std::dec << remainingBufferSize << ")";
257 :
258 0 : if (res->GetEventWindowTag().GetEventWindowTag(true) == lastTag)
259 : {
260 0 : __SS__ << "Impossible repeating tag " << lastTag << __E__;
261 0 : __SS_THROW__;
262 0 : }
263 :
264 0 : lastTag = res->GetEventWindowTag().GetEventWindowTag(true);
265 :
266 0 : daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + sizeof(CFO_EventRecord) + sizeof(uint64_t);
267 0 : remainingBufferSize -= sizeof(CFO_EventRecord);
268 :
269 0 : output.push_back(std::move(res));
270 :
271 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "CFO subevent record JSON=" << output.back()->GetEventRecord().toJson();
272 0 : } // end primary CFO Event Record extraction loop
273 :
274 : // check that size is multiple of CFO Event Record side sanity
275 0 : if (remainingBufferSize != 0)
276 : {
277 0 : __SS__ << "Impossible remainingBufferSize of " << remainingBufferSize << __E__;
278 0 : __SS_THROW__;
279 0 : }
280 :
281 : // // Check if there are more than one CFO_EventRecords
282 : // if (subEventByteCount > remainingBufferSize)
283 : // {
284 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "subevent needs more data by bytes " << std::hex << subEventByteCount - remainingBufferSize << " (" << std::dec << subEventByteCount - remainingBufferSize << ") packets " << (subEventByteCount - remainingBufferSize) / 16 << ". subEventByteCount=" << subEventByteCount << " remainingBufferSize=" << remainingBufferSize;
285 :
286 : // // We're going to set lastReadPtr here, so that if this buffer isn't used by GetData, we start at the beginning of this event next time
287 : // daqDMAInfo_.lastReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr);
288 :
289 : // auto inmem = std::make_unique<CFO_EventRecord>(subEventByteCount);
290 :
291 : // memcpy(const_cast<void*>(inmem->GetRawBufferPointer()), res->GetRawBufferPointer(), remainingBufferSize);
292 :
293 : // if (0) // for deubbging
294 : // {
295 : // std::cout << "1st DMA buffer inmem size=" << remainingBufferSize << "\n";
296 : // auto ptr = reinterpret_cast<const uint8_t*>(inmem->GetRawBufferPointer());
297 : // for (size_t i = 0; i < remainingBufferSize + 16; i += 4)
298 : // std::cout << std::dec << "inmem#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
299 : // }
300 :
301 : // auto bytes_read = remainingBufferSize;
302 : // while (bytes_read < subEventByteCount)
303 : // {
304 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")"
305 : // << " Obtaining new DAQ Buffer, bytes_read=" << bytes_read << ", subEventByteCount=" << subEventByteCount;
306 :
307 : // void* oldBufferPtr = nullptr;
308 : // if (daqDMAInfo_.buffer.size() > 0) oldBufferPtr = &daqDMAInfo_.buffer.back()[0];
309 :
310 : // if (0) // for deubbging
311 : // {
312 : // std::cout << "1st DMA buffer\n";
313 : // auto ptr = reinterpret_cast<const uint8_t*>(&daqDMAInfo_.buffer.back()[0]);
314 : // for (size_t i = 0; i < bytes_read + 32; i += 4)
315 : // std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
316 : // }
317 :
318 : // int sts;
319 : // int retry = 10;
320 : // // timeout is an exception at this point because no way to resolve partial subevent record!
321 : // while ((sts = ReadBuffer(CFO_DMA_Engine_DAQ, 10 /* retries */)) // does return code
322 : // <= 0 &&
323 : // --retry > 0) usleep(1000);
324 :
325 : // if (sts <= 0)
326 : // {
327 : // __SS__ << "Timeout of " << tmo_ms << " ms after receiving only partial subevent! Subevent tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")";
328 : // __SS_THROW__;
329 : // }
330 :
331 : // daqDMAInfo_.currentReadPtr = &daqDMAInfo_.buffer.back()[0];
332 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA daqDMAInfo_.currentReadPtr=" << (void*)daqDMAInfo_.currentReadPtr
333 : // << " *daqDMAInfo_.currentReadPtr=0x" << std::hex << *(unsigned*)daqDMAInfo_.currentReadPtr
334 : // << " lastReadPtr=" << (void*)daqDMAInfo_.lastReadPtr;
335 :
336 : // if (0) // for deubbging
337 : // {
338 : // std::cout << "1st buffer\n";
339 : // auto ptr = reinterpret_cast<const uint8_t*>(inmem->GetRawBufferPointer());
340 : // for (size_t i = 0; i < bytes_read + 16; i += 4)
341 : // std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
342 : // }
343 :
344 : // void* bufferIndexPointer = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
345 : // if (daqDMAInfo_.currentReadPtr == oldBufferPtr && daqDMAInfo_.bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
346 : // {
347 : // // We didn't actually get a new buffer...this probably means there's no more data
348 : // // timeout is an exception at this point because no way to resolve partial subevent record!
349 : // __SS__ << "Received same buffer twice, only received partial subevent!! Subevent tag=" << inmem->GetEventWindowTag().GetEventWindowTag(true) << std::hex << "(0x" << inmem->GetEventWindowTag().GetEventWindowTag(true) << ")";
350 : // __SS_THROW__;
351 : // }
352 : // daqDMAInfo_.bufferIndex++;
353 :
354 : // size_t buffer_size = *static_cast<uint16_t*>(daqDMAInfo_.currentReadPtr);
355 : // daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
356 : // *static_cast<uint32_t*>(daqDMAInfo_.currentReadPtr) = daqDMAInfo_.bufferIndex;
357 : // daqDMAInfo_.currentReadPtr = static_cast<uint8_t*>(daqDMAInfo_.currentReadPtr) + 4;
358 :
359 : // size_t remainingEventSize = subEventByteCount - bytes_read;
360 : // size_t copySize = remainingEventSize < buffer_size - 8 ? remainingEventSize : buffer_size - 8;
361 :
362 : // if (0) // for deubbging
363 : // {
364 : // std::cout << "2nd buffer\n";
365 : // auto ptr = reinterpret_cast<const uint8_t*>(daqDMAInfo_.currentReadPtr);
366 : // for (size_t i = 0; i < copySize; i += 4)
367 : // std::cout << std::dec << "#" << i << "(" << i / 16 << ")" << std::hex << std::setw(8) << std::setfill('0') << *((uint32_t*)(&(ptr[i]))) << std::endl;
368 : // }
369 :
370 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA bytes_read = " << bytes_read << " packets = " << bytes_read / 16 - sizeof(CFO_EventRecord) / 16;
371 : // CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA copySize = " << copySize << " packets = " << copySize / 16;
372 : // memcpy(const_cast<uint8_t*>(static_cast<const uint8_t*>(inmem->GetRawBufferPointer()) + bytes_read), daqDMAInfo_.currentReadPtr, copySize);
373 : // bytes_read += buffer_size - 8;
374 :
375 : // // Increment by the size of the data block
376 : // daqDMAInfo_.currentReadPtr = reinterpret_cast<char*>(daqDMAInfo_.currentReadPtr) + copySize;
377 : // } // end primary continuation of multi-DMA subevent transfers
378 :
379 : // res.swap(inmem);
380 : // }
381 : // else // SubEvent not split over multiple DMAs
382 : // {
383 : // // Update the packet pointers
384 :
385 : // // lastReadPtr_ is easy...
386 : // daqDMAInfo_.lastReadPtr = daqDMAInfo_.currentReadPtr;
387 :
388 : // // Increment by the size of the data block
389 : // daqDMAInfo_.currentReadPtr = reinterpret_cast<char*>(daqDMAInfo_.currentReadPtr) + res->GetSubEventByteCount();
390 : // }
391 :
392 : // try
393 : // {
394 : // res->SetupSubEvent(); // does setup of SubEvent header + all payload
395 : // }
396 : // catch (...)
397 : // {
398 : // device_.spy(CFO_DMA_Engine_DAQ, 3 /* for once */ | 8 /* for wide view */);
399 : // CFO_TLOG(TLVL_ERROR) << otsStyleStackTrace();
400 : // throw;
401 : // }
402 :
403 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextCFORecordDMA: RETURN vector of " << output.size() << " CFO Event Records";
404 : // return res;
405 0 : return true;
406 0 : } // end ReadNextCFORecordDMA()
407 :
408 0 : std::unique_ptr<CFOLib::CFO_DataPacket> CFOLib::CFO::ReadNextPacket(const DTC_DMA_Engine& engine, int tmo_ms)
409 : {
410 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEGIN";
411 : CFOandDTC_DMAs::DMAInfo* info;
412 0 : if (engine == DTC_DMA_Engine_DAQ)
413 0 : info = &daqDMAInfo_;
414 : // else if (engine == DTC_DMA_Engine_DCS)
415 : // info = &dcsDMAInfo_;
416 : else
417 : {
418 0 : __COUT_ERR__ << "ReadNextPacket: Invalid DMA Engine specified!";
419 0 : throw new DTC_DataCorruptionException();
420 : }
421 :
422 0 : if (info->currentReadPtr != nullptr)
423 : {
424 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEFORE BUFFER CHECK info->currentReadPtr="
425 0 : << (void*)info->currentReadPtr << " *nextReadPtr_=0x" << std::hex
426 0 : << *(uint16_t*)info->currentReadPtr;
427 : }
428 : else
429 : {
430 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket BEFORE BUFFER CHECK info->currentReadPtr=nullptr";
431 : }
432 :
433 0 : auto index = CFOandDTC_DMAs::GetCurrentBuffer(info);
434 :
435 : // Need new buffer if GetCurrentBuffer returns -1 (no buffers) or -2 (done with all held buffers)
436 0 : if (index < 0)
437 : {
438 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket Obtaining new " << (engine == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS")
439 0 : << " Buffer";
440 :
441 0 : void* oldBufferPtr = nullptr;
442 0 : if (info->buffer.size() > 0) oldBufferPtr = &info->buffer.back()[0];
443 0 : auto sts = ReadBuffer(engine, tmo_ms); // does return code
444 0 : if (sts <= 0)
445 : {
446 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: ReadBuffer returned " << sts << ", returning nullptr";
447 0 : return nullptr;
448 : }
449 : // MUST BE ABLE TO HANDLE daqbuffer_==nullptr OR retry forever?
450 0 : info->currentReadPtr = &info->buffer.back()[0];
451 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket info->currentReadPtr=" << (void*)info->currentReadPtr
452 0 : << " *info->currentReadPtr=0x" << std::hex << *(unsigned*)info->currentReadPtr
453 0 : << " lastReadPtr_=" << (void*)info->lastReadPtr;
454 0 : void* bufferIndexPointer = static_cast<uint8_t*>(info->currentReadPtr) + 2;
455 0 : if (info->currentReadPtr == oldBufferPtr && info->bufferIndex == *static_cast<uint32_t*>(bufferIndexPointer))
456 : {
457 0 : CFO_TLOG(TLVL_ReadNextDAQPacket)
458 0 : << "ReadNextPacket: New buffer is the same as old. Releasing buffer and returning nullptr";
459 0 : info->currentReadPtr = nullptr;
460 : // We didn't actually get a new buffer...this probably means there's no more data
461 : // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
462 0 : device_.read_release(engine, 1);
463 0 : return nullptr;
464 : }
465 0 : info->bufferIndex++;
466 :
467 0 : info->currentReadPtr = reinterpret_cast<uint8_t*>(info->currentReadPtr) + 2;
468 0 : *static_cast<uint32_t*>(info->currentReadPtr) = info->bufferIndex;
469 0 : info->currentReadPtr = reinterpret_cast<uint8_t*>(info->currentReadPtr) + 6;
470 :
471 0 : index = info->buffer.size() - 1;
472 : }
473 :
474 : // Read the next packet
475 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket reading next packet from buffer: info->currentReadPtr="
476 0 : << (void*)info->currentReadPtr;
477 :
478 0 : auto blockByteCount = *reinterpret_cast<uint16_t*>(info->currentReadPtr);
479 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: blockByteCount=" << blockByteCount
480 0 : << ", info->currentReadPtr=" << (void*)info->currentReadPtr
481 0 : << ", *nextReadPtr=" << (int)*((uint16_t*)info->currentReadPtr);
482 0 : if (blockByteCount == 0 || blockByteCount == 0xcafe)
483 : {
484 0 : if (static_cast<size_t>(index) < info->buffer.size() - 1)
485 : {
486 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: blockByteCount is invalid, moving to next buffer";
487 0 : auto nextBufferPtr = *info->buffer[index + 1];
488 0 : info->currentReadPtr = nextBufferPtr + 8; // Offset past DMA header
489 0 : return ReadNextPacket(engine, tmo_ms); // Recursion
490 : }
491 : else
492 : {
493 0 : CFO_TLOG(TLVL_ReadNextDAQPacket)
494 0 : << "ReadNextPacket: blockByteCount is invalid, and this is the last buffer! Returning nullptr!";
495 0 : info->currentReadPtr = nullptr;
496 : // This buffer is invalid, release it!
497 : // Try and see if we're merely stuck...hopefully, all the data is out of the buffers...
498 0 : device_.read_release(engine, 1);
499 0 : return nullptr;
500 : }
501 : }
502 :
503 0 : auto test = std::make_unique<CFO_DataPacket>(info->currentReadPtr);
504 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: current+blockByteCount="
505 0 : << (void*)(reinterpret_cast<uint8_t*>(info->currentReadPtr) + blockByteCount)
506 0 : << ", end of dma buffer="
507 0 : << (void*)(info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) +
508 0 : 8); // +8 because first 8 bytes are not included in byte count
509 0 : if (reinterpret_cast<uint8_t*>(info->currentReadPtr) + blockByteCount >
510 0 : info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) + 8)
511 : {
512 0 : blockByteCount = static_cast<uint16_t>(
513 0 : info->buffer[index][0] + CFOandDTC_DMAs::GetBufferByteCount(info, index) + 8 -
514 0 : reinterpret_cast<uint8_t*>(info->currentReadPtr)); // +8 because first 8 bytes are not included in byte count
515 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: Adjusting blockByteCount to " << blockByteCount
516 0 : << " due to end-of-DMA condition";
517 0 : test->SetByte(0, blockByteCount & 0xFF);
518 0 : test->SetByte(1, (blockByteCount >> 8));
519 : }
520 :
521 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << test->toJSON();
522 :
523 : // Update the packet pointers
524 :
525 : // lastReadPtr_ is easy...
526 0 : info->lastReadPtr = info->currentReadPtr;
527 :
528 : // Increment by the size of the data block
529 0 : info->currentReadPtr = reinterpret_cast<char*>(info->currentReadPtr) + blockByteCount;
530 :
531 0 : CFO_TLOG(TLVL_ReadNextDAQPacket) << "ReadNextPacket: RETURN";
532 0 : return test;
533 0 : }
534 :
535 : //
536 : // Private Functions.
537 : //
538 0 : int CFOLib::CFO::ReadBuffer(const DTC_DMA_Engine& channel, int tmo_ms)
539 : {
540 : mu2e_databuff_t* buffer;
541 :
542 0 : int retry = 1;
543 :
544 : // Break long timeouts into multiple 10 ms retries
545 0 : if (tmo_ms > 10)
546 : {
547 0 : retry = tmo_ms / 10;
548 0 : tmo_ms = 10;
549 : }
550 :
551 : int errorCode;
552 : do
553 : {
554 0 : CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer before device_.read_data tmo=" << tmo_ms << " retry=" << retry;
555 0 : errorCode = device_.read_data(channel, reinterpret_cast<void**>(&buffer), 1 /* tmo_ms */);
556 : // if (errorCode == 0) usleep(1000);
557 :
558 0 : } while (retry-- > 0 && errorCode == 0); // error code of 0 is timeout
559 :
560 0 : if (errorCode == 0)
561 : {
562 0 : CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: Device timeout occurred! ec=" << errorCode << ", rt=" << retry;
563 : }
564 0 : else if (errorCode < 0)
565 : {
566 0 : CFO_TLOG(TLVL_ERROR) << "ReadBuffer: read_data returned " << errorCode << ", throwing CFO_IOErrorException!";
567 0 : throw DTC_IOErrorException(errorCode);
568 : }
569 : else
570 : {
571 0 : CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer buffer_=" << (void*)buffer << " errorCode=" << errorCode << " *buffer_=0x"
572 0 : << std::hex << *(unsigned*)buffer;
573 0 : if (channel == DTC_DMA_Engine_DAQ)
574 : {
575 0 : daqDMAInfo_.buffer.push_back(buffer);
576 0 : CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: There are now " << daqDMAInfo_.buffer.size()
577 0 : << " DAQ buffers held in the DTC Library";
578 : }
579 : // else if (channel == DTC_DMA_Engine_DCS)
580 : // {
581 : // dcsDMAInfo_.buffer.push_back(buffer);
582 : // CFO_TLOG(TLVL_ReadBuffer) << "ReadBuffer: There are now " << dcsDMAInfo_.buffer.size()
583 : // << " DCS buffers held in the DTC Library";
584 : // }
585 : }
586 0 : return errorCode;
587 : }
588 :
589 0 : void CFOLib::CFO::ReleaseAllBuffers(const DTC_DMA_Engine& channel)
590 : {
591 0 : TLOG_ENTEX(1) << "ReleaseAllBuffers - channel=" << channel;
592 :
593 0 : if (channel == DTC_DMA_Engine_DAQ)
594 : {
595 0 : daqDMAInfo_.buffer.clear();
596 0 : device_.release_all(channel);
597 : }
598 : // else if (channel == CFO_DMA_Engine_RunPlan)
599 : // {
600 : // dcsDMAInfo_.buffer.clear();
601 : // device_.release_all(channel);
602 : // }
603 : else
604 : {
605 0 : CFO_TLOG(TLVL_ERROR) << "ReadNextPacket: Invalid DMA Engine specified!";
606 0 : throw new DTC_DataCorruptionException();
607 : }
608 0 : }
609 :
610 0 : void CFOLib::CFO::ReleaseBuffers(const DTC_DMA_Engine& channel)
611 : {
612 0 : CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers BEGIN";
613 : CFOandDTC_DMAs::DMAInfo* info;
614 0 : if (channel == DTC_DMA_Engine_DAQ)
615 0 : info = &daqDMAInfo_;
616 : // else if (channel == CFO_DMA_Engine_RunPlan)
617 : // info = &dcsDMAInfo_;
618 : else
619 : {
620 0 : CFO_TLOG(TLVL_ERROR) << "ReadNextPacket: Invalid DMA Engine specified!\n\n"
621 0 : << otsStyleStackTrace();
622 0 : throw new DTC_DataCorruptionException();
623 : }
624 :
625 0 : auto releaseBufferCount = CFOandDTC_DMAs::GetCurrentBuffer(info);
626 0 : if (releaseBufferCount > 0)
627 : {
628 0 : CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers releasing " << releaseBufferCount << " "
629 0 : << (channel == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS") << " buffers.";
630 :
631 : // if (channel == CFO_DMA_Engine_DCS)
632 : // device_.begin_dcs_transaction();
633 0 : device_.read_release(channel, releaseBufferCount);
634 : // if (channel == DTC_DMA_Engine_DCS)
635 : // device_.end_dcs_transaction();
636 :
637 0 : for (int ii = 0; ii < releaseBufferCount; ++ii)
638 : {
639 0 : info->buffer.pop_front();
640 : }
641 : }
642 : // else
643 : // {
644 : // CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers releasing ALL " << (channel == DTC_DMA_Engine_DAQ ? "DAQ" : "DCS")
645 : // << " buffers.";
646 : // ReleaseAllBuffers(channel);
647 : // }
648 0 : CFO_TLOG(TLVL_ReleaseBuffers) << "ReleaseBuffers END";
649 0 : }
650 :
651 : // int CFOLib::CFO::GetCurrentBuffer(DMAInfo* info)
652 : // {
653 : // CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer BEGIN";
654 : // if (info->currentReadPtr == nullptr || info->buffer.size() == 0)
655 : // {
656 : // CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer returning -1 because not currently reading a buffer";
657 : // return -1;
658 : // }
659 :
660 : // for (size_t ii = 0; ii < info->buffer.size(); ++ii)
661 : // {
662 : // auto bufferptr = *info->buffer[ii];
663 : // uint16_t bufferSize = *reinterpret_cast<uint16_t*>(bufferptr);
664 : // if (info->currentReadPtr > bufferptr &&
665 : // info->currentReadPtr < bufferptr + bufferSize)
666 : // {
667 : // CFO_TLOG(TLVL_GetCurrentBuffer) << "Found matching buffer at index " << ii << ".";
668 : // return ii;
669 : // }
670 : // }
671 : // CFO_TLOG(TLVL_GetCurrentBuffer) << "GetCurrentBuffer returning -2: Have buffers but none match, need new";
672 : // return -2;
673 : // }
674 :
675 : // uint16_t CFOLib::CFO::GetBufferByteCount(DMAInfo* info, size_t index)
676 : // {
677 : // if (index >= info->buffer.size()) return 0;
678 : // auto bufferptr = *info->buffer[index];
679 : // uint16_t bufferSize = *reinterpret_cast<uint16_t*>(bufferptr);
680 : // return bufferSize;
681 : // }
|