Line data Source code
1 : /**
2 : * @file DeviceInterface.cxx
3 : *
4 : * This is part of the DUNE DAQ , copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : // FIXME: This code implementation is a mess, with most parameters hardcoded instead of taking them from the
10 : // configuration
11 : #ifndef SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
12 : #define SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
13 :
14 : #include "DeviceInterface.hpp"
15 : #include "RegMap.hpp"
16 : #include "SSPIssues.hpp"
17 : #include "anlExceptions.hpp"
18 :
19 : #include "boost/asio.hpp"
20 :
21 : #include <algorithm>
22 : #include <ctime>
23 : #include <memory>
24 : #include <string>
25 : #include <utility>
26 : #include <vector>
27 :
28 : enum
29 : {
30 : TLVL_ENTER_EXIT_METHODS = 5,
31 : TLVL_WORK_STEPS = 10,
32 : TLVL_BOOKKEEPING = 15,
33 : TLVL_FULL_DEBUG = 63
34 : };
35 :
36 0 : dunedaq::sspmodules::DeviceInterface::DeviceInterface()
37 0 : : fDeviceId(0)
38 0 : , fState(dunedaq::sspmodules::DeviceInterface::kUninitialized)
39 0 : , fUseExternalTimestamp(true)
40 0 : , fHardwareClockRateInMHz(128)
41 0 : , fDummyPeriod(-1)
42 0 : , fSlowControlOnly(false)
43 0 : , fPartitionNumber(0)
44 0 : , fTimingAddress(0)
45 0 : , exception_(false)
46 : {
47 0 : }
48 :
49 : void
50 0 : dunedaq::sspmodules::DeviceInterface::OpenSlowControl()
51 : {
52 :
53 0 : TLOG_DEBUG(TLVL_FULL_DEBUG) << "SSP Device Interface OpenSlowControl called.";
54 : // Ask device manager for a pointer to the specified device
55 0 : dunedaq::sspmodules::DeviceManager& devman = dunedaq::sspmodules::DeviceManager::Get();
56 0 : dunedaq::sspmodules::Device* device = 0;
57 :
58 0 : device = devman.OpenDevice(fDeviceId, true); // slow control only
59 :
60 0 : if (!device) {
61 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Unable to get handle to device; giving up!" << std::endl;
62 0 : throw(ENoSuchDevice());
63 : }
64 :
65 0 : fDevice = device;
66 0 : fSlowControlOnly = true;
67 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface OpenSlowControl completed.";
68 0 : }
69 :
70 : /*
71 : void
72 : dunedaq::sspmodules::DeviceInterface::Initialize(const nlohmann::json& args)
73 : {
74 :
75 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Initialize called.";
76 : fState = kInitialized;
77 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Initailize complete.";
78 : }
79 :
80 : void
81 : dunedaq::sspmodules::DeviceInterface::Stop()
82 : {
83 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Stop called.";
84 :
85 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
86 :
87 : fDevice->DeviceWrite(duneReg.eventDataControl, 0x0013001F);
88 : fDevice->DeviceClear(duneReg.master_logic_control, 0x00000101);
89 : // Clear the FIFOs
90 : fDevice->DeviceWrite(duneReg.fifo_control, 0x08000000);
91 : fDevice->DeviceWrite(duneReg.PurgeDDR, 0x00000001);
92 : // Reset the links and flags
93 : fDevice->DeviceWrite(duneReg.event_data_control, 0x00020001);
94 : // Flush RX buffer
95 : fDevice->DevicePurgeData();
96 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Hardware set to stopped state" << std::endl;
97 : fState = kStopped;
98 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Stop complete.";
99 : }
100 :
101 :
102 : void
103 : dunedaq::sspmodules::DeviceInterface::Start()
104 : {
105 :
106 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Start called.";
107 :
108 :
109 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Device interface starting hardware run..." << std::endl;
110 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
111 : // This script enables all logic and FIFOs and starts data acquisition in the device
112 : // Operations MUST be performed in this order
113 :
114 : // Load window settings, charge injection settings and bias voltage into channels
115 : fDevice->DeviceWrite(duneReg.channel_pulsed_control, 0x1);
116 : fDevice->DeviceWrite(duneReg.bias_control, 0x1);
117 : fDevice->DeviceWriteMask(duneReg.vmon_control, 0x1, 0x1);
118 : fDevice->DeviceWriteMask(duneReg.imon_control, 0x1, 0x1);
119 : fDevice->DeviceWriteMask(duneReg.qi_dac_control, 0x1, 0x1);
120 : fDevice->DeviceWriteMask(duneReg.qi_pulsed, 0x00030000, 0x00030000);
121 :
122 : fDevice->DeviceWrite(duneReg.event_data_control, 0x00000000);
123 : // Release the FIFO reset
124 : fDevice->DeviceWrite(duneReg.fifo_control, 0x00000000);
125 : // Registers in the Zynq FPGA (Comm)
126 : // Reset the links and flags (note eventDataControl!=event_data_control)
127 : fDevice->DeviceWrite(duneReg.eventDataControl, 0x00000000);
128 : // Registers in the Artix FPGA (DSP)
129 : // Release master logic reset & enable active channels
130 :
131 : fDevice->DeviceWrite(duneReg.master_logic_control, 0x00000041);
132 : fState = kRunning;
133 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Start complete.";
134 : }
135 :
136 : void
137 : dunedaq::sspmodules::DeviceInterface::Shutdown()
138 : {
139 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Shutdown called.";
140 :
141 : fDevice->Close();
142 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP Device Interface Shutdown complete.";
143 : }
144 : */
145 :
146 : void
147 0 : dunedaq::sspmodules::DeviceInterface::SetRegister(unsigned int address, unsigned int value, unsigned int mask)
148 : {
149 :
150 0 : if (mask == 0xFFFFFFFF) {
151 0 : fDevice->DeviceWrite(address, value);
152 : } else {
153 0 : fDevice->DeviceWriteMask(address, mask, value);
154 : }
155 0 : }
156 :
157 : void
158 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterArray(unsigned int address, std::vector<unsigned int> value)
159 : {
160 :
161 0 : this->SetRegisterArray(address, &(value[0]), value.size());
162 0 : }
163 :
164 : void
165 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterArray(unsigned int address, unsigned int* value, unsigned int size)
166 : {
167 :
168 0 : fDevice->DeviceArrayWrite(address, size, value);
169 0 : }
170 :
171 : void
172 0 : dunedaq::sspmodules::DeviceInterface::ReadRegister(unsigned int address, unsigned int& value, unsigned int mask)
173 : {
174 :
175 0 : if (mask == 0xFFFFFFFF) {
176 0 : fDevice->DeviceRead(address, &value);
177 : } else {
178 0 : fDevice->DeviceReadMask(address, mask, &value);
179 : }
180 0 : }
181 :
182 : void
183 0 : dunedaq::sspmodules::DeviceInterface::ReadRegisterArray(unsigned int address,
184 : std::vector<unsigned int>& value,
185 : unsigned int size)
186 : {
187 :
188 0 : value.resize(size);
189 0 : this->ReadRegisterArray(address, &(value[0]), size);
190 0 : }
191 :
192 : void
193 0 : dunedaq::sspmodules::DeviceInterface::ReadRegisterArray(unsigned int address, unsigned int* value, unsigned int size)
194 : {
195 :
196 0 : fDevice->DeviceArrayRead(address, size, value);
197 0 : }
198 : void
199 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterByName(std::string name, unsigned int value)
200 : {
201 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name];
202 :
203 0 : this->SetRegister(reg, value, reg.WriteMask());
204 0 : }
205 :
206 : void
207 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterElementByName(std::string name, unsigned int index, unsigned int value)
208 : {
209 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name][index];
210 :
211 0 : this->SetRegister(reg, value, reg.WriteMask());
212 0 : }
213 :
214 : void
215 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterArrayByName(std::string name, unsigned int value)
216 : {
217 0 : unsigned int regSize = (dunedaq::sspmodules::RegMap::Get())[name].Size();
218 0 : std::vector<unsigned int> arrayContents(regSize, value);
219 :
220 0 : this->SetRegisterArrayByName(name, arrayContents);
221 0 : }
222 :
223 : void
224 0 : dunedaq::sspmodules::DeviceInterface::SetRegisterArrayByName(std::string name, std::vector<unsigned int> values)
225 : {
226 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name];
227 0 : if (reg.Size() != values.size()) {
228 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Request to set named register array " << name << ", length " << reg.Size()
229 0 : << "with vector of " << values.size() << " values!" << std::endl;
230 0 : throw(std::invalid_argument(""));
231 : }
232 0 : this->SetRegisterArray(reg[0], values);
233 0 : }
234 :
235 : void
236 0 : dunedaq::sspmodules::DeviceInterface::ReadRegisterByName(std::string name, unsigned int& value)
237 : {
238 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name];
239 :
240 0 : this->ReadRegister(reg, value, reg.ReadMask());
241 0 : }
242 :
243 : void
244 0 : dunedaq::sspmodules::DeviceInterface::ReadRegisterElementByName(std::string name,
245 : unsigned int index,
246 : unsigned int& value)
247 : {
248 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name][index];
249 :
250 0 : this->ReadRegister(reg, value, reg.ReadMask());
251 0 : }
252 :
253 : void
254 0 : dunedaq::sspmodules::DeviceInterface::ReadRegisterArrayByName(std::string name, std::vector<unsigned int>& values)
255 : {
256 0 : dunedaq::sspmodules::RegMap::Register reg = (dunedaq::sspmodules::RegMap::Get())[name];
257 0 : this->ReadRegisterArray(reg[0], values, reg.Size());
258 0 : }
259 :
260 : void
261 0 : dunedaq::sspmodules::DeviceInterface::ConfigureLEDCalib(const appmodel::SSPLEDCalibModule* conf)
262 : {
263 :
264 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSP LED Calib Device Interface Configure called.";
265 :
266 0 : std::stringstream ss;
267 0 : fDeviceId = inet_network(conf->get_board_ip().c_str()); // inet_network("10.73.137.56");
268 0 : TLOG() << "DeviceInterface: trying to connect to " << boost::asio::ip::address_v4(fDeviceId).to_string();
269 : // Ask device manager for a pointer to the specified device
270 0 : dunedaq::sspmodules::DeviceManager& devman = dunedaq::sspmodules::DeviceManager::Get();
271 0 : dunedaq::sspmodules::Device* device = 0;
272 :
273 0 : device = devman.OpenDevice(fDeviceId);
274 :
275 0 : if (!device) {
276 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Unable to get handle to device; giving up!" << std::endl;
277 0 : throw(ENoSuchDevice());
278 : }
279 :
280 0 : fDevice = device;
281 :
282 : // Reset timing endpoint
283 0 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
284 :
285 0 : unsigned int pdts_status = 0;
286 0 : unsigned int pdts_control = 0;
287 0 : unsigned int dsp_clock_control = 0;
288 :
289 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
290 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec << std::endl;
291 0 : fDevice->DeviceRead(duneReg.pdts_control, &pdts_control);
292 0 : TLOG() << "The pdts_control read back as 0x" << std::hex << pdts_control << std::dec << std::endl;
293 0 : fDevice->DeviceRead(duneReg.dsp_clock_control, &dsp_clock_control);
294 0 : TLOG() << "The dsp_clock_control read back as 0x" << std::hex << dsp_clock_control << std::dec << std::endl;
295 :
296 0 : unsigned int presentTimingAddress = (pdts_control >> 16) & 0xFF;
297 0 : unsigned int presentTimingPartition = pdts_control & 0x3;
298 :
299 0 : TLOG() << "SSP HW presently on partition " << presentTimingPartition << ", address 0x" << std::hex
300 0 : << presentTimingAddress << " with endpoint status 0x" << (pdts_status & 0xF) << " and dsp_clock_control at 0x"
301 0 : << dsp_clock_control << std::dec << std::endl;
302 :
303 : // if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8 && presentTimingAddress == fTimingAddress &&
304 : // presentTimingPartition == fPartitionNumber && dsp_clock_control == 0x31) {
305 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8 && presentTimingAddress == fTimingAddress &&
306 0 : presentTimingPartition == fPartitionNumber &&
307 0 : (dsp_clock_control & 0xF) ==
308 : 0x1) { // NOTE THAT THIS WAS CHANGED SO THAT IF THE DSP_CLOCK_STATUS LOWEST BIT IS STILL HIGH 0x1
309 : // THEN THE CLOCK ALREADY IS ASSUMED TO BE GOOD, AND WE DON'T TRY TO RESYNCH WITH THE PDTS
310 :
311 0 : TLOG() << "Clock already looks ok... skipping endpoint reset." << std::endl;
312 0 : } else {
313 :
314 0 : TLOG() << "Syncing SSP LED Calib to PDTS (partition " << fPartitionNumber << ", endpoint address 0x" << std::hex
315 0 : << fTimingAddress << std::dec << ")" << std::endl;
316 :
317 0 : unsigned int nTries = 0;
318 :
319 0 : while (nTries < 5) {
320 0 : fDevice->DeviceWrite(duneReg.dsp_clock_control, 0x30);
321 0 : TLOG() << "The dsp_clock_control was set to 0x" << std::hex << 0x30 << std::dec
322 0 : << std::endl; // setting the lowest bit to 0 sets the DSP clock to internal.
323 0 : fDevice->DeviceWrite(duneReg.pdts_control, 0x80000000 + fPartitionNumber + fTimingAddress * 0x10000);
324 0 : TLOG() << "The pdts_control value was set to 0x" << std::hex
325 0 : << 0x80000000 + fPartitionNumber + fTimingAddress * 0x10000 << std::dec
326 0 : << std::endl; // setting the highest bit (0x80000000) to 1 puts the SSP in Reset mode for the PDTS.
327 :
328 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
329 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec << std::endl;
330 0 : fDevice->DeviceRead(duneReg.pdts_control, &pdts_control);
331 0 : TLOG() << "The pdts_control read back as 0x" << std::hex << pdts_control << std::dec << std::endl;
332 0 : fDevice->DeviceRead(duneReg.dsp_clock_control, &dsp_clock_control);
333 0 : TLOG() << "The dsp_clock_control read back as 0x" << std::hex << dsp_clock_control << std::dec << std::endl;
334 :
335 0 : fDevice->DeviceWrite(duneReg.pdts_control, 0x00000000 + fPartitionNumber + fTimingAddress * 0x10000);
336 0 : TLOG() << "The pdts_status value was set to 0x" << std::hex
337 0 : << 0x00000000 + fPartitionNumber + fTimingAddress * 0x10000 << std::dec << std::endl;
338 0 : usleep(2000000); // setting the highest bit (0x80000000) to zero puts the SSP in run mode for the PDTS.
339 0 : fDevice->DeviceWrite(duneReg.dsp_clock_control,
340 : 0x31); // setting the lowest bit to 1 sets the DSP clock to external.
341 0 : TLOG() << "The dsp_clock_control was set to 0x" << std::hex << 0x31 << std::dec << std::endl;
342 0 : usleep(2000000);
343 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
344 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec << std::endl;
345 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8)
346 : break;
347 0 : TLOG() << "Timing endpoint sync failed (try " << nTries << ")" << std::endl;
348 0 : ++nTries;
349 : }
350 :
351 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8) {
352 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status << " and the 0xF bit masked value is 0x"
353 0 : << (pdts_status & 0xF) << std::dec << std::endl;
354 0 : TLOG() << "Timing endpoint synced!" << std::endl;
355 : } else {
356 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status << " and the 0xF bit masked value is 0x"
357 0 : << (pdts_status & 0xF) << std::dec << std::endl;
358 0 : TLOG() << "Giving up on endpoint sync after 5 tries. Value of pdts_status register was 0x" << std::hex
359 0 : << pdts_status << std::dec << std::endl;
360 : }
361 : }
362 :
363 0 : TLOG() << "Woke up from 2 seconds of sleep and Waiting for endpoint to reach status 0x8..." << std::endl;
364 : // Wait until pdts_status reaches exactly 0x8 before resolving.
365 0 : if ((pdts_status & 0xF) != 0x8) {
366 0 : TLOG() << "Waiting for endpoint to reach status 0x8..." << std::endl;
367 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status << " and the 0xF bit masked value is 0x"
368 0 : << (pdts_status & 0xF) << std::dec << std::endl;
369 : }
370 : int nTries = 0;
371 0 : while ((pdts_status & 0xF) != 0x8) {
372 0 : if (nTries == 2) {
373 0 : TLOG() << "Wrong PDTS status!" << std::endl;
374 0 : throw DeviceInterfacePDTSStatus(ERS_HERE);
375 : }
376 0 : usleep(2000000);
377 0 : TLOG() << "Woke up from 2 seconds of sleep and Waiting for endpoint to reach status 0x8..." << std::endl;
378 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
379 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status << " and the 0xF bit masked value is 0x"
380 0 : << (pdts_status & 0xF) << std::dec << std::endl;
381 0 : nTries++;
382 : }
383 :
384 0 : TLOG() << "Endpoint is in running state, continuing with configuration!" << std::endl;
385 0 : TLOG() << "SSP LED Calib Device Interface Configured complete.";
386 0 : } // NOLINT(readability/fn_size)
387 :
388 : std::string
389 0 : dunedaq::sspmodules::DeviceInterface::GetIdentifier()
390 : {
391 0 : std::string ident;
392 0 : boost::asio::ip::address ip = boost::asio::ip::address_v4(fDeviceId);
393 0 : std::string ipString = ip.to_string();
394 0 : ident += "(";
395 0 : ident += ipString;
396 0 : ident += "):";
397 0 : return ident;
398 0 : }
399 : void
400 0 : dunedaq::sspmodules::DeviceInterface::PrintHardwareState()
401 : {
402 :
403 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "===SSP DIAGNOSTIC REGISTERS===" << std::endl;
404 :
405 0 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
406 0 : unsigned int val;
407 :
408 0 : fDevice->DeviceRead(duneReg.dp_clock_status, &val);
409 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "dsp_clock_status: 0x" << std::hex << val << std::endl;
410 0 : fDevice->DeviceRead(duneReg.live_timestamp_msb, &val);
411 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "live_timestamp_msb: " << val << std::endl;
412 0 : fDevice->DeviceRead(duneReg.live_timestamp_lsb, &val);
413 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "live_timestamp_lsb: " << val << std::endl;
414 0 : fDevice->DeviceRead(duneReg.sync_delay, &val);
415 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "sync_delay: " << val << std::endl;
416 0 : fDevice->DeviceRead(duneReg.sync_count, &val);
417 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "sync_count: " << val << std::dec << std::endl;
418 0 : }
419 :
420 : #endif // SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
|