Line data Source code
1 : // This file (mu2edev.cc) was created by Ron Rechenmacher <ron@fnal.gov> on
2 : // Feb 13, 2014. "TERMS AND CONDITIONS" governing this file are in the README
3 : // or COPYING file. If you do not have such a file, one can be obtained by
4 : // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
5 : // $RCSfile: .emacs.gnu,v $
6 : // rev="$Revision: 1.23 $$Date: 2012/01/23 15:32:40 $";
7 :
8 : /*
9 : * make mu2edev.o CFLAGS='-g -Wall -std=c++0x'
10 : */
11 :
12 : #include "TRACE/tracemf.h"
13 : #define TRACE_NAME "mu2esim"
14 :
15 : #define TLVL_Constructor TLVL_DEBUG + 2
16 : #define TLVL_Init TLVL_DEBUG + 3
17 : #define TLVL_ReadData TLVL_DEBUG + 4
18 : #define TLVL_ReadData2 TLVL_DEBUG + 5
19 : #define TLVL_WriteData TLVL_DEBUG + 6
20 : #define TLVL_ReadRelease TLVL_DEBUG + 7
21 : #define TLVL_ReadRegister TLVL_DEBUG + 8
22 : #define TLVL_ReadRegister2 TLVL_DEBUG + 9
23 : #define TLVL_WriteRegister TLVL_DEBUG + 10
24 : #define TLVL_WriteRegister2 TLVL_DEBUG + 11
25 : #define TLVL_CFOEmulator TLVL_DEBUG + 12
26 : #define TLVL_CFOEmulator2 TLVL_DEBUG + 13
27 : #define TLVL_DeltaChn TLVL_DEBUG + 14
28 : #define TLVL_ClearBuffer TLVL_DEBUG + 15
29 : #define TLVL_ClearBuffer2 TLVL_DEBUG + 16
30 : #define TLVL_OpenEvent TLVL_DEBUG + 17
31 : #define TLVL_CloseEvent TLVL_DEBUG + 18
32 : #define TLVL_DCSPacketSimulator TLVL_DEBUG + 19
33 : #define TLVL_PacketSimulator TLVL_DEBUG + 20
34 : #define TLVL_EventSimulator TLVL_DEBUG + 21
35 :
36 : #define CURRENT_EMULATED_TRACKER_VERSION 1
37 : #define CURRENT_EMULATED_CALORIMETER_VERSION 0
38 : #define CURRENT_EMULATED_CRV_VERSION 0
39 :
40 : #include "mu2esim.h"
41 : #include "DTC_Registers.h"
42 :
43 : #include <cmath>
44 : #include <vector>
45 :
46 : #define THREADED_CFO_EMULATOR 0
47 :
48 0 : mu2esim::mu2esim(std::string ddrFileName)
49 0 : : registers_()
50 0 : , swIdx_()
51 : /*, detSimLoopCount_(0)*/
52 0 : , dmaData_()
53 0 : , ddrFileName_(ddrFileName)
54 0 : , ddrFile_(nullptr)
55 0 : , mode_(DTCLib::DTC_SimMode_Disabled)
56 0 : , cancelCFO_(true)
57 0 : , readoutRequestReceived_()
58 0 : , event_(nullptr)
59 0 : , sub_event_(nullptr)
60 : {
61 0 : TLOG(TLVL_Constructor) << "mu2esim::mu2esim BEGIN";
62 0 : for (unsigned ii = 0; ii < MU2E_MAX_CHANNELS; ++ii)
63 0 : swIdx_[ii] = 0;
64 0 : for (unsigned ii = 0; ii < MU2E_MAX_CHANNELS; ++ii)
65 0 : hwIdx_[ii] = 0;
66 0 : for (unsigned ii = 0; ii < SIM_BUFFCOUNT; ++ii)
67 : {
68 0 : dmaData_[0][ii] = reinterpret_cast<mu2e_databuff_t *>(new char[0x10000]);
69 0 : dmaData_[1][ii] = reinterpret_cast<mu2e_databuff_t *>(new char[0x10000]);
70 : }
71 0 : release_all(0);
72 0 : release_all(1);
73 :
74 0 : event_mode_num_tracker_blocks_ = 6;
75 0 : auto tracker_count_c = getenv("DTCLIB_NUM_TRACKER_BLOCKS");
76 0 : if (tracker_count_c != nullptr)
77 : {
78 0 : event_mode_num_tracker_blocks_ = std::atoi(tracker_count_c);
79 : }
80 : // Max is 134
81 0 : event_mode_num_calo_blocks_ = 6;
82 0 : auto calo_count_c = getenv("DTCLIB_NUM_CALORIMETER_BLOCKS");
83 0 : if (calo_count_c != nullptr)
84 : {
85 0 : event_mode_num_calo_blocks_ = std::atoi(calo_count_c);
86 : }
87 0 : event_mode_num_calo_hits_ = 6;
88 0 : auto calo_hit_count_c = getenv("DTCLIB_NUM_CALORIMETER_HITS");
89 0 : if (calo_hit_count_c != nullptr)
90 : {
91 0 : event_mode_num_calo_hits_ = std::atoi(calo_hit_count_c);
92 : }
93 0 : event_mode_num_crv_blocks_ = 0;
94 0 : auto crv_count_c = getenv("DTCLIB_NUM_CRV_BLOCKS");
95 0 : if (crv_count_c != nullptr)
96 : {
97 0 : event_mode_num_crv_blocks_ = std::atoi(crv_count_c);
98 : }
99 :
100 0 : reopenDDRFile_();
101 :
102 0 : TLOG(TLVL_Constructor) << "mu2esim::mu2esim END";
103 0 : }
104 :
105 0 : mu2esim::~mu2esim()
106 : {
107 0 : cancelCFO_ = true;
108 0 : if (cfoEmulatorThread_.joinable()) cfoEmulatorThread_.join();
109 0 : for (unsigned ii = 0; ii < SIM_BUFFCOUNT; ++ii)
110 : {
111 0 : delete[] dmaData_[0][ii];
112 0 : delete[] dmaData_[1][ii];
113 : }
114 0 : ddrFile_.reset(nullptr);
115 0 : }
116 :
117 0 : int mu2esim::init(DTCLib::DTC_SimMode mode)
118 : {
119 0 : TLOG(TLVL_Init) << "mu2e Simulator::init";
120 0 : mode_ = mode;
121 :
122 0 : TLOG(TLVL_Init) << "Initializing registers";
123 : // Set initial register values...
124 0 : registers_[DTCLib::CFOandDTC_Register_DesignVersion] = 0x00006363; // v99.99
125 0 : registers_[DTCLib::CFOandDTC_Register_DesignDate] = 0xA5020796; // A for sim mode, 6-ROC, and date sim functionaliy was last modified
126 0 : registers_[DTCLib::CFOandDTC_Register_Control] = 0x00000003; // System Clock, Timing Enable
127 0 : registers_[DTCLib::CFOandDTC_Register_DMATransferLength] = 0x80000010; // Default value from HWUG
128 0 : registers_[DTCLib::CFOandDTC_Register_SERDES_LoopbackEnable] = 0x00000000; // SERDES Loopback Disabled
129 0 : registers_[DTCLib::CFOandDTC_Register_ClockOscillatorStatus] = 0x20002; // Initialization Complete, no IIC Error
130 0 : registers_[DTCLib::DTC_Register_ROCEmulationEnable] = 0x3F; // ROC Emulators enabled (of course!)
131 0 : registers_[DTCLib::CFOandDTC_Register_LinkEnable] = 0x3F3F; // All links Tx/Rx enabled, CFO and timing disabled
132 0 : registers_[DTCLib::CFOandDTC_Register_SERDES_PLLLocked] = 0x7F; // SERDES PLL Locked
133 0 : registers_[DTCLib::CFOandDTC_Register_SERDES_ResetDone] = 0xFFFFFFFF; // SERDES Resets Done
134 0 : registers_[DTCLib::DTC_Register_SERDES_RXCDRLockStatus] = 0x7F00007F; // RX CDR Locked
135 0 : registers_[DTCLib::DTC_Register_DMATimeoutPreset] = 0x800; // DMA Timeout Preset
136 0 : registers_[DTCLib::DTC_Register_ROCReplyTimeout] = 0x200000; // ROC Timeout Preset
137 0 : registers_[DTCLib::CFOandDTC_Register_SERDESClock_IICBusLow] = 0xFFFFFFFF;
138 0 : registers_[DTCLib::CFOandDTC_Register_SERDESClock_IICBusHigh] = 0x77f3f;
139 : // registers_[DTCLib::DTC_Register_DDRReferenceClockFrequency] = 0xbebc200;
140 : // registers_[DTCLib::DTC_Register_DDRClock_IICBusLow] = 0x1074f43b;
141 : // registers_[DTCLib::DTC_Register_DDRClock_IICBusHigh] = 0x30303;
142 0 : registers_[DTCLib::DTC_Register_EthernetFramePayloadSize] = 0x5D4;
143 0 : registers_[DTCLib::DTC_Register_FPGAPROMProgramStatus] = 0x1;
144 :
145 0 : TLOG(TLVL_Init) << "mu2e Simulator::init finished";
146 0 : return 0;
147 : }
148 :
149 : /*****************************
150 : read_data
151 : returns number of bytes read; negative value indicates an error
152 : */
153 0 : int mu2esim::read_data(int chn, void **buffer, int tmo_ms)
154 : {
155 0 : auto start = std::chrono::steady_clock::now();
156 0 : size_t bytesReturned = 0;
157 0 : if (delta_(chn, C2S) == 0) // no data, generate if ddrFile
158 : {
159 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Clearing output buffer";
160 0 : clearBuffer_(chn, false);
161 :
162 0 : if (chn == 0)
163 : {
164 0 : if (!ddrFile_->is_open() || ddrFile_->fail())
165 : {
166 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Simulating DTC data DMA subevent trasfer...";
167 0 : sleep(1);
168 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Simulating DTC data DMA subevent trasfer, after sleep.";
169 :
170 0 : auto ptr = reinterpret_cast<uint8_t *>(dmaData_[chn][swIdx_[chn]]);
171 0 : ptr += sizeof(uint64_t); // advance past data size
172 :
173 0 : DTCLib::DTC_SubEventHeader header;
174 0 : uint64_t size = sizeof(header) + 6 * 16 + 6 * 3 * 16; // subevent header + ROC headers + ROC payloads
175 :
176 0 : header.event_tag_low = simDataEWT_++;
177 0 : header.event_mode = 1;
178 0 : memcpy(ptr, &header, sizeof(header));
179 0 : header.inclusive_subevent_byte_count = size;
180 :
181 0 : TLOG(TLVL_DEBUG + 6) << "Found sub event inclusive byte count as: " << header.inclusive_subevent_byte_count << " 0x" << std::hex << std::setw(4) << std::setfill('0') << header.inclusive_subevent_byte_count << ". i.e., " << std::dec << std::setw(0) << (header.inclusive_subevent_byte_count - sizeof(header)) / 16 << " subevent packets.";
182 :
183 0 : ptr += sizeof(header); // moving ptr past subevent header
184 :
185 0 : size_t num_of_packets = (header.inclusive_subevent_byte_count - sizeof(header)) / 16;
186 0 : size_t packets_per_roc = num_of_packets / 6;
187 0 : TLOG(TLVL_DEBUG + 6) << "num_of_packets = " << num_of_packets;
188 0 : TLOG(TLVL_DEBUG + 6) << "packets_per_roc = " << packets_per_roc;
189 :
190 0 : for (int i = 0; i > 6; ++i)
191 : {
192 0 : size_t packets_this_roc = packets_per_roc;
193 0 : if (i == 5) packets_this_roc = num_of_packets;
194 0 : if (packets_this_roc > 2023) packets_this_roc = 0; // assume wrapped around negative
195 0 : TLOG(TLVL_TRACE) << "Setup ROC-" << i << " data header. packets_this_roc = " << packets_this_roc;
196 :
197 0 : *((uint16_t *)(&(ptr[1 * 2]))) = 0x8000 | (i << 8) | (5 << 4); // packet type Data Header 0x5
198 0 : *((uint16_t *)(&(ptr[2 * 2]))) = packets_this_roc; // packet count
199 0 : *((uint16_t *)(&(ptr[3 * 2]))) = simDataEWT_; // tag.GetEventWindowTag(true); //packet count
200 0 : *((uint16_t *)(&(ptr[4 * 2]))) = simDataEWT_ >> 16; // tag.GetEventWindowTag(true)>>16; //packet count
201 0 : *((uint16_t *)(&(ptr[5 * 2]))) = 0; // tag.GetEventWindowTag(true)>>32; //packet count
202 :
203 0 : ptr += 16 * 1 + 16 * packets_this_roc; // move ptr past ROC header + data
204 : } // end ROC loop
205 :
206 0 : memcpy(dmaData_[chn][swIdx_[chn]], &size, sizeof(uint64_t));
207 0 : bytesReturned = size;
208 : } // end generate sim data
209 : else
210 : {
211 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Reading size from memory file";
212 : uint64_t size;
213 0 : ddrFile_->read(reinterpret_cast<char *>(&size), sizeof(uint64_t) / sizeof(char));
214 :
215 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Size is " << size;
216 :
217 0 : if (ddrFile_->eof() || size == 0)
218 : {
219 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: End of file reached, looping back to start";
220 0 : ddrFile_->clear();
221 0 : ddrFile_->seekg(std::ios::beg);
222 :
223 0 : TLOG(TLVL_ReadData) << " mu2esim::read_data: Re-reading size from memory file";
224 0 : ddrFile_->read(reinterpret_cast<char *>(&size), sizeof(uint64_t));
225 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: Size is " << size;
226 0 : if (ddrFile_->eof())
227 : {
228 0 : TLOG(TLVL_ReadData) << "mu2esim::read_data: 0-size file detected!";
229 0 : return -1;
230 : }
231 : }
232 0 : TLOG(TLVL_ReadData) << "Size of data is " << size - sizeof(uint64_t) << ", reading into buffer " << swIdx_[chn] << ", at "
233 0 : << (void *)dmaData_[chn][swIdx_[chn]];
234 0 : memcpy(dmaData_[chn][swIdx_[chn]], &size, sizeof(uint64_t));
235 0 : ddrFile_->read(reinterpret_cast<char *>(dmaData_[chn][swIdx_[chn]]) + sizeof(uint64_t), size - sizeof(uint64_t));
236 0 : bytesReturned = size;
237 : } // end DDR File sim read
238 : }
239 0 : else if (chn == 1)
240 : {
241 : // Data should already be in appropriate buffer, generated by dcsPacketSimulator_()
242 : }
243 : }
244 : else // there is data to read, calculate size
245 0 : if (chn == 1)
246 : {
247 0 : uint64_t dcsSize = *reinterpret_cast<uint64_t *>(dmaData_[chn][swIdx_[chn]]);
248 0 : TLOG(TLVL_ReadData2) << "mu2esim::read_data: dcsSize = " << dcsSize;
249 0 : bytesReturned = (size_t)dcsSize;
250 : }
251 :
252 0 : *buffer = dmaData_[chn][swIdx_[chn]];
253 0 : TLOG(TLVL_ReadData2) << "mu2esim::read_data: *buffer (" << (void *)*buffer << ") should now be equal to dmaData_[" << chn << "]["
254 0 : << swIdx_[chn] << "] (" << (void *)dmaData_[chn][swIdx_[chn]] << "), bytesReturned = " << bytesReturned << " data = 0x" << std::hex << *reinterpret_cast<uint64_t *>(dmaData_[chn][swIdx_[chn]]);
255 0 : swIdx_[chn] = (swIdx_[chn] + 1) % SIM_BUFFCOUNT;
256 :
257 : auto duration =
258 0 : std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
259 0 : TLOG(TLVL_ReadData2) << "mu2esim::read_data took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
260 0 : return static_cast<int>(bytesReturned);
261 : }
262 :
263 0 : int mu2esim::write_data(int chn, void *buffer, size_t bytes)
264 : {
265 0 : if (chn == 0)
266 : {
267 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: adding buffer to simulated DDR memory sz=" << bytes
268 0 : << ", *buffer=" << *((uint64_t *)buffer);
269 0 : if (bytes <= sizeof(mu2e_databuff_t))
270 : {
271 0 : if (event_) closeEvent_();
272 :
273 : // Strip off first 64-bit word
274 0 : auto writeBytes = *reinterpret_cast<uint64_t *>(buffer) - sizeof(uint64_t);
275 0 : auto ptr = reinterpret_cast<char *>(buffer) + (sizeof(uint64_t) / sizeof(char));
276 0 : ddrFile_->write(ptr, writeBytes);
277 0 : registers_[DTCLib::DTC_Register_DetEmulation_DataEndAddress] += static_cast<uint32_t>(writeBytes);
278 0 : ddrFile_->flush();
279 0 : return 0;
280 : }
281 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: I was asked to write more than one buffer's worth of data. Cowardly refusing.";
282 : }
283 0 : else if (chn == 1)
284 : {
285 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data start: chn=" << chn << ", buf=" << buffer << ", bytes=" << bytes;
286 :
287 : // extract target ROC link "activeDAQLink" from bufer
288 : uint32_t worda;
289 0 : memcpy(&worda, reinterpret_cast<uint64_t *>(buffer) + 1, sizeof worda);
290 0 : auto word = static_cast<uint16_t>(worda >> 16);
291 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data worda is 0x" << std::hex << worda << " and word is 0x" << std::hex << word;
292 0 : auto activeLink = static_cast<DTCLib::DTC_Link_ID>((word & 0x0F00) >> 8);
293 :
294 0 : DTCLib::DTC_EventWindowTag ts(reinterpret_cast<uint8_t *>(buffer) + 6);
295 0 : if ((word & 0x8010) == 0x8010)
296 : {
297 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: Readout Request: activeDAQLink=" << activeLink
298 0 : << ", ts=" << ts.GetEventWindowTag(true);
299 0 : readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink] = true;
300 : }
301 0 : else if ((word & 0x8020) == 0x8020)
302 : {
303 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: Data Request: activeDAQLink=" << activeLink << ", ts=" << ts.GetEventWindowTag(true);
304 0 : if (activeLink != DTCLib::DTC_Link_Unused)
305 : {
306 0 : if (!readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink])
307 : {
308 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: Data Request Received but missing Readout Request!";
309 : }
310 : else
311 : {
312 0 : openEvent_(ts);
313 :
314 0 : if (mode_ == DTCLib::DTC_SimMode_Performance || mode_ == DTCLib::DTC_SimMode_Timeout)
315 : {
316 0 : auto packetCount = *(reinterpret_cast<uint16_t *>(buffer) + 7);
317 0 : packetSimulator_(ts, activeLink, packetCount);
318 0 : }
319 0 : else if (mode_ == DTCLib::DTC_SimMode_Tracker)
320 : {
321 0 : trackerBlockSimulator_(ts, activeLink, 0);
322 : }
323 0 : else if (mode_ == DTCLib::DTC_SimMode_Calorimeter)
324 : {
325 0 : calorimeterBlockSimulator_(ts, activeLink, 0);
326 : }
327 0 : else if (mode_ == DTCLib::DTC_SimMode_CosmicVeto)
328 : {
329 0 : crvBlockSimulator_(ts, activeLink, 0);
330 : }
331 :
332 0 : readoutRequestReceived_[ts.GetEventWindowTag(true)][activeLink] = false;
333 0 : if (readoutRequestReceived_[ts.GetEventWindowTag(true)].count() == 0)
334 : {
335 0 : closeEvent_();
336 0 : readoutRequestReceived_.erase(ts.GetEventWindowTag(true));
337 : }
338 : }
339 : }
340 : }
341 0 : if ((word & 0x0080) == 0)
342 : {
343 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data activeDCSLink is " << activeLink;
344 0 : if (activeLink != DTCLib::DTC_Link_Unused)
345 : {
346 0 : DTCLib::DTC_DataPacket packet(reinterpret_cast<uint64_t *>(buffer) + 1); // skip 64-bit packet size
347 0 : TLOG(TLVL_WriteData) << "packet " << packet.toJSON();
348 :
349 0 : DTCLib::DTC_DCSRequestPacket thisPacket(packet);
350 :
351 0 : if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_Write ||
352 0 : thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockWrite)
353 : {
354 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: Recieved DCS Write Request:" << thisPacket.toJSON();
355 :
356 0 : auto request1 = thisPacket.GetRequest(false);
357 0 : rocRegisters_[activeLink][request1.first] = request1.second;
358 :
359 0 : if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockWrite)
360 : {
361 0 : auto request2 = thisPacket.GetRequest(true);
362 0 : rocRegisters_[activeLink][request2.first] = request2.second;
363 : }
364 : }
365 :
366 : // Note: write's can request ack
367 0 : if (thisPacket.GetType() == DTCLib::DTC_DCSOperationType_Read ||
368 0 : thisPacket.GetType() == DTCLib::DTC_DCSOperationType_BlockRead || thisPacket.RequestsAck())
369 : {
370 0 : TLOG(TLVL_WriteData) << "mu2esim::write_data: Recieved DCS Request:" << thisPacket.toJSON();
371 0 : dcsPacketSimulator_(thisPacket, activeLink);
372 : }
373 0 : }
374 : }
375 0 : }
376 :
377 0 : return 0;
378 : }
379 :
380 0 : int mu2esim::read_release(int chn, unsigned num)
381 : {
382 : // Always succeeds
383 0 : TLOG(TLVL_ReadRelease) << "mu2esim::read_release: Simulating a release of " << num << "u buffers of channel " << chn;
384 0 : for (unsigned ii = 0; ii < num; ++ii)
385 : {
386 0 : if (delta_(chn, C2S) != 0) swIdx_[chn] = (swIdx_[chn] + 1) % SIM_BUFFCOUNT;
387 : }
388 0 : TLOG(TLVL_DeltaChn) << "mu2esim::read_release: After release... chn=" << chn << " hw=" << hwIdx_[chn] << " sw=" << swIdx_[chn];
389 0 : return 0;
390 : }
391 :
392 0 : int mu2esim::release_all(int chn)
393 : {
394 0 : read_release(chn, SIM_BUFFCOUNT);
395 : // swIdx_[chn] = 0; //do not reset, just release up to hw pointer
396 0 : return 0;
397 : }
398 :
399 0 : int mu2esim::read_register(uint16_t address, int tmo_ms, uint32_t *output)
400 : {
401 0 : auto start = std::chrono::steady_clock::now();
402 0 : *output = 0;
403 0 : if (registers_.count(address) > 0)
404 : {
405 0 : TLOG(TLVL_ReadRegister) << "mu2esim::read_register: Returning value 0x" << std::hex << registers_[address] << " for address 0x"
406 0 : << std::hex << address;
407 0 : *output = registers_[address];
408 : }
409 : auto duration =
410 0 : std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
411 0 : TLOG(TLVL_ReadRegister2) << "mu2esim::read_register took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
412 0 : return 0;
413 : }
414 :
415 0 : int mu2esim::write_register(uint16_t address, int tmo_ms, uint32_t data)
416 : {
417 0 : auto start = std::chrono::steady_clock::now();
418 : // Write the register!!!
419 0 : TLOG(TLVL_WriteRegister) << "mu2esim::write_register: Writing value 0x" << std::hex << data << " into address 0x" << std::hex
420 0 : << address;
421 0 : registers_[address] = data;
422 : auto duration =
423 0 : std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
424 0 : TLOG(TLVL_WriteRegister2) << "mu2esim::write_register took " << duration << " milliseconds out of tmo_ms=" << tmo_ms;
425 0 : std::bitset<32> dataBS(data);
426 0 : if (address == DTCLib::CFOandDTC_Register_Control)
427 : {
428 0 : auto detectorEmulationMode = (registers_[DTCLib::DTC_Register_DetEmulation_Control0] & 0x3) != 0;
429 0 : if (dataBS[30] == 1 && !detectorEmulationMode)
430 : {
431 0 : TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: CFO Emulator Enable Detected!";
432 0 : cancelCFO_ = true;
433 0 : if (cfoEmulatorThread_.joinable()) cfoEmulatorThread_.join();
434 0 : cancelCFO_ = false;
435 : #if THREADED_CFO_EMULATOR
436 : if (registers_[0x91AC] > 10)
437 : {
438 : cfoEmulatorThread_ = std::thread(&mu2esim::CFOEmulator_, this);
439 : }
440 : else
441 : #endif
442 : {
443 0 : CFOEmulator_();
444 : }
445 : }
446 0 : else if (dataBS[26] == 1 && detectorEmulationMode)
447 : {
448 0 : TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: IGNORING CFO Emulator Enable because we're in Detector Simulator mode!";
449 : }
450 0 : if (dataBS[31] == 1)
451 : {
452 0 : TLOG(TLVL_WriteRegister2) << "mu2esim::write_register: RESETTING DTC EMULATOR!";
453 0 : init(mode_);
454 0 : reopenDDRFile_();
455 : }
456 : }
457 0 : if (address == DTCLib::DTC_Register_DetEmulation_Control0)
458 : {
459 0 : if (dataBS[0] == 0)
460 : {
461 0 : reopenDDRFile_();
462 : }
463 : }
464 0 : if (address == DTCLib::DTC_Register_DetEmulation_DataStartAddress)
465 : {
466 0 : ddrFile_->seekg(data);
467 : }
468 0 : return 0;
469 : }
470 :
471 0 : void mu2esim::CFOEmulator_()
472 : {
473 0 : if (cancelCFO_)
474 : {
475 0 : std::bitset<32> ctrlReg(registers_[0x9100]);
476 0 : ctrlReg[30] = 0;
477 0 : registers_[0x9100] = ctrlReg.to_ulong();
478 0 : return;
479 : }
480 0 : DTCLib::DTC_EventWindowTag start(registers_[DTCLib::DTC_Register_CFOEmulation_TimestampLow],
481 0 : static_cast<uint16_t>(registers_[DTCLib::DTC_Register_CFOEmulation_TimestampHigh]));
482 0 : auto count = registers_[DTCLib::DTC_Register_CFOEmulation_NumHeartbeats];
483 0 : auto ticksToWait = static_cast<long long>(registers_[DTCLib::DTC_Register_CFOEmulation_HeartbeatInterval] * 0.0064);
484 0 : TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ start timestamp=" << start.GetEventWindowTag(true) << ", count=" << count
485 0 : << ", delayBetween=" << ticksToWait;
486 : bool linkEnabled[6];
487 0 : for (auto link : DTCLib::DTC_ROC_Links)
488 : {
489 0 : std::bitset<32> linkRocs(registers_[DTCLib::CFOandDTC_Register_LinkEnable]);
490 0 : auto number = linkRocs[link] + linkRocs[link + 8];
491 0 : TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ linkRocs[" << static_cast<int>(link) << "]=" << number;
492 0 : linkEnabled[link] = number != 0;
493 : }
494 :
495 0 : unsigned sentCount = 0;
496 0 : while (sentCount < count && !cancelCFO_)
497 : {
498 0 : if (mode_ == DTCLib::DTC_SimMode_Event)
499 : {
500 0 : TLOG(TLVL_CFOEmulator) << "Event mode enabled, calling eventSimulator_";
501 0 : eventSimulator_(start + sentCount);
502 : }
503 : else
504 : {
505 0 : openEvent_(start + sentCount);
506 0 : for (auto link : DTCLib::DTC_ROC_Links)
507 : {
508 : uint16_t packetCount;
509 0 : switch (link)
510 : {
511 0 : case DTCLib::DTC_Link_0:
512 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks10]);
513 0 : break;
514 0 : case DTCLib::DTC_Link_1:
515 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks10] >> 16);
516 0 : break;
517 0 : case DTCLib::DTC_Link_2:
518 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks32]);
519 0 : break;
520 0 : case DTCLib::DTC_Link_3:
521 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks32] >> 16);
522 0 : break;
523 0 : case DTCLib::DTC_Link_4:
524 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks54]);
525 0 : break;
526 0 : case DTCLib::DTC_Link_5:
527 0 : packetCount = static_cast<uint16_t>(registers_[DTCLib::DTC_Register_ROCEmulation_NumPacketsLinks54] >> 16);
528 0 : break;
529 0 : default:
530 0 : packetCount = 0;
531 0 : break;
532 : }
533 0 : if (linkEnabled[link] != 0)
534 : {
535 0 : TLOG(TLVL_CFOEmulator) << "mu2esim::CFOEmulator_ linkRocs[" << static_cast<int>(link) << "]=" << linkEnabled[link];
536 0 : if (mode_ == DTCLib::DTC_SimMode_Performance || mode_ == DTCLib::DTC_SimMode_Timeout)
537 : {
538 0 : TLOG(TLVL_CFOEmulator) << "Performance or Timeout mode enabled, calling packetSimulator_";
539 0 : packetSimulator_(start + sentCount, link, packetCount);
540 0 : }
541 0 : else if (mode_ == DTCLib::DTC_SimMode_Tracker)
542 : {
543 0 : TLOG(TLVL_CFOEmulator) << "Tracker mode enabled, calling trackerBlockSimulator_";
544 0 : trackerBlockSimulator_(start + sentCount, link, 0);
545 : }
546 0 : else if (mode_ == DTCLib::DTC_SimMode_Calorimeter)
547 : {
548 0 : TLOG(TLVL_CFOEmulator) << "Calorimeter mode enabled, calling calorimeterBlockSimulator_";
549 0 : calorimeterBlockSimulator_(start + sentCount, link, 0);
550 : }
551 0 : else if (mode_ == DTCLib::DTC_SimMode_CosmicVeto)
552 : {
553 0 : TLOG(TLVL_CFOEmulator) << "CRV mode enabled, calling crvBlockSimulator_";
554 0 : crvBlockSimulator_(start + sentCount, link, 0);
555 : }
556 : }
557 : }
558 0 : closeEvent_();
559 : }
560 :
561 0 : if (ticksToWait > 100)
562 : {
563 0 : usleep(ticksToWait);
564 : }
565 0 : sentCount++;
566 : }
567 0 : std::bitset<32> ctrlReg(registers_[0x9100]);
568 0 : ctrlReg[30] = 0;
569 0 : registers_[0x9100] = ctrlReg.to_ulong();
570 0 : }
571 :
572 0 : unsigned mu2esim::delta_(int chn, int dir)
573 : {
574 0 : if (chn == 0) return 0;
575 0 : TLOG(TLVL_DeltaChn) << "delta_ " << chn << " " << dir << " = 0";
576 0 : unsigned hw = hwIdx_[chn];
577 0 : unsigned sw = swIdx_[chn];
578 0 : TLOG(TLVL_DeltaChn) << "mu2esim::delta_ chn=" << chn << " dir=" << dir << " hw=" << hw << " sw=" << sw
579 0 : << " num_buffs=" << SIM_BUFFCOUNT;
580 0 : if (dir == C2S)
581 0 : return ((hw >= sw) ? hw - sw : SIM_BUFFCOUNT + hw - sw);
582 : else
583 0 : return ((sw >= hw) ? SIM_BUFFCOUNT - (sw - hw) : hw - sw);
584 : }
585 :
586 0 : void mu2esim::clearBuffer_(int chn, bool increment)
587 : {
588 0 : TLOG(TLVL_ClearBuffer2) << "mu2esim::clearBuffer_(" << chn << ", " << increment << "): NOP";
589 0 : }
590 :
591 0 : void mu2esim::openEvent_(DTCLib::DTC_EventWindowTag ts)
592 : {
593 0 : TLOG(TLVL_OpenEvent) << "mu2esim::openEvent_ Checking timestamp " << ts.GetEventWindowTag(true) << " vs current timestamp "
594 0 : << (event_ ? std::to_string(event_->GetEventWindowTag().GetEventWindowTag(true)) : std::string(" NONE"));
595 0 : if (event_ && ts == event_->GetEventWindowTag()) return;
596 0 : if (event_) closeEvent_();
597 :
598 0 : TLOG(TLVL_OpenEvent) << "mu2esim::openEvent_: Setting up initial buffer";
599 :
600 0 : event_ = std::make_unique<DTCLib::DTC_Event>();
601 0 : event_->SetEventWindowTag(ts);
602 0 : event_->SetEventMode(getEventMode_());
603 :
604 0 : sub_event_ = std::make_unique<DTCLib::DTC_SubEvent>();
605 0 : sub_event_->SetEventWindowTag(ts);
606 0 : sub_event_->SetEventMode(getEventMode_());
607 : }
608 :
609 0 : void mu2esim::closeSubEvent_()
610 : {
611 0 : if (!event_ || !sub_event_ || sub_event_->GetDataBlockCount() == 0) return;
612 :
613 0 : event_->AddSubEvent(*(sub_event_.release()));
614 :
615 0 : sub_event_ = std::make_unique<DTCLib::DTC_SubEvent>();
616 0 : sub_event_->SetEventWindowTag(event_->GetEventWindowTag());
617 0 : sub_event_->SetEventMode(getEventMode_());
618 : }
619 :
620 0 : DTCLib::DTC_EventMode mu2esim::getEventMode_()
621 : {
622 0 : DTCLib::DTC_EventMode event_mode;
623 :
624 0 : event_mode.mode0 = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF);
625 0 : event_mode.mode1 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF00) >> 8);
626 0 : event_mode.mode2 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF0000) >> 16);
627 0 : event_mode.mode3 = static_cast<uint8_t>((registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF000000) >> 24);
628 0 : event_mode.mode4 = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode2] & 0xFF);
629 :
630 0 : return event_mode;
631 : }
632 :
633 0 : void mu2esim::closeEvent_()
634 : {
635 0 : TLOG(TLVL_CloseEvent) << "mu2esim::closeEvent_: Checking current event";
636 0 : if (sub_event_) closeSubEvent_();
637 0 : if (event_ && ddrFile_)
638 : {
639 0 : event_->WriteEvent(*ddrFile_, false);
640 0 : ddrFile_->flush();
641 :
642 0 : event_.reset(nullptr);
643 0 : sub_event_.reset(nullptr);
644 : }
645 0 : TLOG(TLVL_CloseEvent) << "mu2esim::closeEvent_ FINISH";
646 0 : }
647 :
648 0 : void mu2esim::dcsPacketSimulator_(DTCLib::DTC_DCSRequestPacket in, DTCLib::DTC_Link_ID rocLink)
649 : {
650 0 : auto packetCount = 0;
651 0 : if (in.GetType() == DTCLib::DTC_DCSOperationType_BlockRead)
652 : {
653 0 : packetCount = 1;
654 : }
655 0 : TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: Constructing DCS Response";
656 0 : DTCLib::DTC_DMAPacket packet(DTCLib::DTC_PacketType_DCSReply, in.GetLinkID(), (1 + packetCount) * 16, true);
657 :
658 0 : TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: copying response into new buffer";
659 0 : auto dataPacket = packet.ConvertToDataPacket();
660 :
661 0 : dataPacket.SetByte(4, static_cast<int>(in.GetType()) + (in.RequestsAck() ? 0x8 : 0) + (in.IsDoubleOp() ? 0x4 : 0) +
662 0 : ((packetCount & 0x2) << 6));
663 0 : dataPacket.SetByte(5, (packetCount & 0x3FC) >> 2);
664 :
665 0 : auto request1 = in.GetRequest(false);
666 0 : dataPacket.SetByte(6, request1.first & 0xFF);
667 0 : dataPacket.SetByte(7, (request1.first & 0xFF00) >> 8);
668 0 : dataPacket.SetByte(8, rocRegisters_[rocLink][request1.first] & 0xFF);
669 0 : dataPacket.SetByte(9, (rocRegisters_[rocLink][request1.first] & 0xFF00) >> 8);
670 :
671 0 : if (in.GetType() != DTCLib::DTC_DCSOperationType_BlockRead)
672 : {
673 0 : auto request2 = in.GetRequest(true);
674 0 : dataPacket.SetByte(10, request2.first & 0xFF);
675 0 : dataPacket.SetByte(11, (request2.first & 0xFF00) >> 8);
676 0 : dataPacket.SetByte(12, rocRegisters_[rocLink][request2.first] & 0xFF);
677 0 : dataPacket.SetByte(13, (rocRegisters_[rocLink][request2.first] & 0xFF00) >> 8);
678 : }
679 : else
680 : {
681 0 : for (int ii = 10; ii < dataPacket.GetSize(); ++ii)
682 : {
683 0 : dataPacket.SetByte(ii, ii);
684 : }
685 : }
686 :
687 0 : TLOG(TLVL_DCSPacketSimulator) << "in.toJSON() " << in.toJSON();
688 0 : TLOG(TLVL_DCSPacketSimulator) << "dataPacket.toJSON() " << dataPacket.toJSON();
689 :
690 0 : size_t packetSize = dataPacket.GetSize();
691 0 : TLOG(TLVL_DCSPacketSimulator) << "packetSize = " << packetSize << " into buffer hw=" << hwIdx_[1] << " sw=" << swIdx_[1];
692 0 : *reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]) = packetSize;
693 0 : memcpy(reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]) + 1, dataPacket.GetData(), packetSize);
694 0 : TLOG(TLVL_DCSPacketSimulator) << "mu2esim::dcsPacketSimulator_: copied packetSize=" << packetSize << " into buffer #" << hwIdx_[1] << " data = 0x" << std::hex << *reinterpret_cast<uint64_t *>(dmaData_[1][hwIdx_[1]]);
695 0 : hwIdx_[1] = (hwIdx_[1] + 1) % SIM_BUFFCOUNT;
696 :
697 0 : TLOG(TLVL_DCSPacketSimulator) << "After... hw=" << hwIdx_[1] << " sw=" << swIdx_[1];
698 0 : }
699 :
700 0 : void mu2esim::eventSimulator_(DTCLib::DTC_EventWindowTag ts)
701 : {
702 0 : openEvent_(ts);
703 :
704 0 : auto num_trk_dtcs = ceil(event_mode_num_tracker_blocks_ / 6);
705 0 : auto num_calo_dtcs = ceil(event_mode_num_calo_blocks_ / 6);
706 0 : auto num_crv_dtcs = ceil(event_mode_num_crv_blocks_ / 6);
707 :
708 0 : size_t generated_trk_blocks = 0;
709 0 : size_t generated_calo_blocks = 0;
710 0 : size_t generated_crv_blocks = 0;
711 :
712 0 : int DTCID = 0;
713 :
714 0 : for (auto ii = 0; ii < num_trk_dtcs; ++ii, ++DTCID)
715 : {
716 0 : TLOG(TLVL_EventSimulator) << "Generating Tracker data, DTCID " << DTCID << ", TRK DTC " << ii + 1 << "/" << num_trk_dtcs;
717 0 : sub_event_->SetDTCMAC(DTCID);
718 0 : sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_Tracker);
719 :
720 0 : for (auto link : DTCLib::DTC_ROC_Links)
721 : {
722 0 : TLOG(TLVL_EventSimulator) << "Generating Tracker data block for DTC " << DTCID << " link " << static_cast<int>(link);
723 0 : trackerBlockSimulator_(ts, link, ii);
724 0 : if (++generated_trk_blocks >= event_mode_num_tracker_blocks_) break;
725 : }
726 0 : closeSubEvent_();
727 : }
728 0 : for (auto ii = 0; ii < num_calo_dtcs; ++ii, ++DTCID)
729 : {
730 0 : TLOG(TLVL_EventSimulator) << "Generating Calorimeter data, DTCID " << DTCID << ", Calo DTC " << ii + 1 << "/" << num_calo_dtcs;
731 0 : sub_event_->SetDTCMAC(DTCID);
732 0 : sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_Calorimeter);
733 :
734 0 : for (auto link : DTCLib::DTC_ROC_Links)
735 : {
736 0 : TLOG(TLVL_EventSimulator) << "Generating Calorimeter data block for DTC " << DTCID << " link " << static_cast<int>(link);
737 0 : calorimeterBlockSimulator_(ts, link, ii);
738 0 : if (++generated_calo_blocks >= event_mode_num_calo_blocks_) break;
739 : }
740 0 : closeSubEvent_();
741 : }
742 0 : for (auto ii = 0; ii < num_crv_dtcs; ++ii, ++DTCID)
743 : {
744 0 : TLOG(TLVL_EventSimulator) << "Generating CRV data, DTCID " << DTCID << ", CRV DTC " << ii + 1 << "/" << num_crv_dtcs;
745 0 : sub_event_->SetDTCMAC(DTCID);
746 0 : sub_event_->SetSourceDTC(DTCID, DTCLib::DTC_Subsystem_CRV);
747 :
748 0 : for (auto link : DTCLib::DTC_ROC_Links)
749 : {
750 0 : TLOG(TLVL_EventSimulator) << "Generating CRV data block for DTC " << DTCID << " link " << static_cast<int>(link);
751 0 : crvBlockSimulator_(ts, link, ii);
752 0 : if (++generated_crv_blocks >= event_mode_num_crv_blocks_) break;
753 : }
754 0 : closeSubEvent_();
755 : }
756 :
757 0 : closeEvent_();
758 0 : }
759 :
760 0 : void mu2esim::trackerBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
761 : {
762 : uint16_t buffer[24];
763 :
764 0 : size_t nPackets = 2;
765 0 : DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_Tracker, CURRENT_EMULATED_TRACKER_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
766 0 : memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
767 :
768 0 : uint16_t strawID = ((static_cast<int>(link) + (DTCID * 6)) << 7) + 1;
769 0 : buffer[8] = strawID;
770 : // TDC set to EventWindowTag
771 0 : buffer[9] = (ts.GetEventWindowTag(true) & 0xFFFF);
772 0 : buffer[10] = 0x1000 + 0xF00 + ((ts.GetEventWindowTag(true) & 0xFF0000) >> 16);
773 :
774 0 : buffer[11] = (ts.GetEventWindowTag(true) & 0xFFFF);
775 0 : buffer[12] = 0xF00 + ((ts.GetEventWindowTag(true) & 0xFF0000) >> 16);
776 :
777 0 : buffer[13] = (0x7 << 6) + 0x1; // PMP = 7, 1 ADC packet
778 :
779 0 : buffer[14] = 0x1 + (0x2 << 10);
780 0 : buffer[15] = 0x3 << 4;
781 :
782 0 : buffer[16] = 0x4 + (0x5 << 10);
783 0 : buffer[17] = 0x6 << 4;
784 0 : buffer[18] = 0x7 + (0x8 << 10);
785 0 : buffer[19] = 0x9 << 4;
786 0 : buffer[20] = 0xA + (0xB << 10);
787 0 : buffer[21] = 0xC << 4;
788 0 : buffer[22] = 0xD + (0xE << 10);
789 0 : buffer[23] = 0xF << 4;
790 :
791 0 : DTCLib::DTC_DataBlock block(sizeof(buffer));
792 0 : memcpy(&(*block.allocBytes)[0], buffer, sizeof(buffer));
793 0 : sub_event_->AddDataBlock(block);
794 0 : }
795 :
796 0 : void mu2esim::calorimeterBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
797 : {
798 0 : std::vector<uint16_t> buffer(9);
799 :
800 : // Index Packet
801 0 : buffer[8] = event_mode_num_calo_hits_;
802 :
803 0 : for (size_t idx = 0; idx < event_mode_num_calo_hits_; ++idx)
804 : {
805 0 : buffer.push_back(2 /* num hits */ + 2 * event_mode_num_calo_hits_ /* hit offsets */ + 4 /* board ID */ + idx * 24 /* hit readout */); // Index of hit from start of index packet
806 : }
807 :
808 : // Board ID
809 0 : uint16_t roc_id = static_cast<uint8_t>(link) + (DTCID * 6);
810 0 : uint8_t board_number = (roc_id) & 0x3F; // 6 bits
811 0 : buffer.push_back(0xFC00 + (board_number << 3));
812 0 : buffer.push_back(0x3FFF);
813 :
814 0 : auto t0Step = 2000 / event_mode_num_calo_hits_;
815 :
816 0 : for (size_t idx = 0; idx < event_mode_num_calo_hits_; ++idx)
817 : {
818 : // Hit readout
819 0 : buffer.push_back(board_number);
820 0 : buffer.push_back(10 * roc_id); // DIRAC B...do we need to put something here?
821 :
822 0 : buffer.push_back(0); // No error flags
823 0 : buffer.push_back((idx * t0Step) & 0xFFFF); // Time
824 0 : buffer.push_back(0x0607); // Max sample/num samples
825 :
826 : // Digitizer samples
827 0 : buffer.push_back(0x1111);
828 0 : buffer.push_back(0x2222);
829 0 : buffer.push_back(0x3333);
830 0 : buffer.push_back(0x4444);
831 0 : buffer.push_back(0x5555);
832 0 : buffer.push_back(0x6666);
833 0 : buffer.push_back(0x7777);
834 : }
835 :
836 0 : while (buffer.size() % 8 != 0)
837 : {
838 0 : buffer.push_back(0);
839 : }
840 :
841 0 : size_t nPackets = (buffer.size() / 8) - 1;
842 0 : DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_Calorimeter, CURRENT_EMULATED_CALORIMETER_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
843 0 : memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
844 :
845 0 : DTCLib::DTC_DataBlock block(buffer.size() * sizeof(uint16_t));
846 0 : memcpy(&(*block.allocBytes)[0], &buffer[0], buffer.size() * sizeof(uint16_t));
847 0 : sub_event_->AddDataBlock(block);
848 0 : }
849 :
850 0 : void mu2esim::crvBlockSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, int DTCID)
851 : {
852 : uint16_t buffer[24];
853 :
854 0 : size_t nPackets = 2;
855 0 : DTCLib::DTC_DataHeaderPacket header(link, nPackets, DTCLib::DTC_DataStatus_Valid, DTCID, DTCLib::DTC_Subsystem_CRV, CURRENT_EMULATED_CRV_VERSION, ts, static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF));
856 0 : memcpy(&buffer[0], header.ConvertToDataPacket().GetData(), 16);
857 :
858 : // ROC Status packet
859 0 : uint8_t board_number = static_cast<uint8_t>(link) + (DTCID * 6);
860 0 : buffer[8] = 0x60 + (board_number << 8);
861 0 : buffer[9] = 28;
862 0 : buffer[10] = 0;
863 0 : buffer[11] = 1;
864 0 : buffer[12] = 0;
865 0 : buffer[13] = 1;
866 0 : buffer[14] = 0;
867 0 : buffer[15] = static_cast<uint8_t>(registers_[DTCLib::DTC_Register_CFOEmulation_EventMode1] & 0xFF) << 8;
868 :
869 : // Hit Readout
870 0 : buffer[16] = 0;
871 0 : buffer[17] = 0;
872 0 : buffer[18] = 0x2211;
873 0 : buffer[19] = 0x4433;
874 0 : buffer[20] = 0x6655;
875 0 : buffer[21] = 0x8877;
876 0 : buffer[22] = 0; // Zero padding
877 0 : buffer[23] = 0;
878 :
879 0 : DTCLib::DTC_DataBlock block(sizeof(buffer));
880 0 : memcpy(&(*block.allocBytes)[0], buffer, sizeof(buffer));
881 0 : sub_event_->AddDataBlock(block);
882 0 : }
883 :
884 0 : void mu2esim::reopenDDRFile_()
885 : {
886 0 : if (!ddrFile_)
887 : {
888 0 : TLOG(TLVL_INFO) << "Going to open simulated RAM file " << ddrFileName_;
889 0 : ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::in | std::fstream::out));
890 : }
891 : else
892 : {
893 0 : ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::trunc | std::fstream::binary | std::fstream::out | std::ios::in));
894 : }
895 :
896 0 : if (!ddrFile_->is_open() || ddrFile_->fail())
897 : {
898 0 : TLOG(TLVL_INFO) << "File " << ddrFileName_ << " does not exist, creating";
899 0 : ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::trunc | std::fstream::out));
900 : // Reopen with original flags
901 0 : ddrFile_.reset(new std::fstream(ddrFileName_, std::fstream::binary | std::fstream::in | std::fstream::out));
902 : }
903 0 : }
904 :
905 0 : void mu2esim::packetSimulator_(DTCLib::DTC_EventWindowTag ts, DTCLib::DTC_Link_ID link, uint16_t packetCount)
906 : {
907 0 : if (!sub_event_) return;
908 :
909 0 : TLOG(TLVL_PacketSimulator) << "mu2esim::packetSimulator_: Generating data for timestamp " << ts.GetEventWindowTag(true);
910 :
911 0 : if (mode_ == DTCLib::DTC_SimMode_Performance)
912 : {
913 0 : std::vector<uint8_t> packet(16 + packetCount * 16);
914 :
915 : // Add a Data Header packet to the reply
916 0 : packet[0] = static_cast<uint8_t>(packet.size());
917 0 : packet[1] = static_cast<uint8_t>(packet.size() >> 8);
918 0 : packet[2] = 0x50;
919 0 : packet[3] = 0x80 + (link & 0x0F);
920 0 : packet[4] = static_cast<uint8_t>(packetCount & 0xFF);
921 0 : packet[5] = static_cast<uint8_t>(packetCount >> 8);
922 0 : ts.GetEventWindowTag(&packet[0], 6);
923 0 : packet[12] = 0;
924 0 : packet[13] = 0;
925 0 : packet[14] = 0;
926 0 : packet[15] = 0;
927 :
928 0 : size_t offset = 16;
929 :
930 0 : for (uint16_t ii = 0; ii < packetCount; ++ii)
931 : {
932 0 : packet[offset] = static_cast<uint8_t>(ii);
933 0 : packet[offset + 1] = 0x11;
934 0 : packet[offset + 2] = 0x22;
935 0 : packet[offset + 3] = 0x33;
936 0 : packet[offset + 4] = 0x44;
937 0 : packet[offset + 5] = 0x55;
938 0 : packet[offset + 6] = 0x66;
939 0 : packet[offset + 7] = 0x77;
940 0 : packet[offset + 8] = 0x88;
941 0 : packet[offset + 9] = 0x99;
942 0 : packet[offset + 10] = 0xaa;
943 0 : packet[offset + 11] = 0xbb;
944 0 : packet[offset + 12] = 0xcc;
945 0 : packet[offset + 13] = 0xdd;
946 0 : packet[offset + 14] = 0xee;
947 0 : packet[offset + 15] = 0xff;
948 :
949 0 : offset += 16;
950 : }
951 :
952 0 : DTCLib::DTC_DataBlock block(packet.size());
953 0 : memcpy(&(*block.allocBytes)[0], &packet[0], packet.size());
954 0 : sub_event_->AddDataBlock(block);
955 0 : }
956 0 : else if (mode_ == DTCLib::DTC_SimMode_Timeout)
957 : {
958 : uint8_t packet[16];
959 :
960 0 : packet[0] = 0xfe;
961 0 : packet[1] = 0xca;
962 0 : packet[2] = 0xfe;
963 0 : packet[3] = 0xca;
964 0 : packet[4] = 0xfe;
965 0 : packet[5] = 0xca;
966 0 : packet[6] = 0xfe;
967 0 : packet[7] = 0xca;
968 0 : packet[8] = 0xfe;
969 0 : packet[9] = 0xca;
970 0 : packet[10] = 0xfe;
971 0 : packet[11] = 0xca;
972 0 : packet[12] = 0xfe;
973 0 : packet[13] = 0xca;
974 0 : packet[14] = 0xfe;
975 0 : packet[15] = 0xca;
976 :
977 0 : TLOG(TLVL_PacketSimulator) << "mu2esim::packetSimulator_ Writing Data Header packet to memory file, chn=0, packet=" << (void *)packet;
978 :
979 0 : DTCLib::DTC_DataBlock block(sizeof(packet));
980 0 : memcpy(&(*block.allocBytes)[0], packet, sizeof(packet));
981 0 : sub_event_->AddDataBlock(block);
982 0 : }
983 :
984 0 : ddrFile_->flush();
985 : }
|