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 configuration
10 : #ifndef SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
11 : #define SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
12 :
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 :
274 0 : device = devman.OpenDevice(fDeviceId);
275 :
276 0 : if (!device) {
277 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Unable to get handle to device; giving up!" << std::endl;
278 0 : throw(ENoSuchDevice());
279 : }
280 :
281 0 : fDevice = device;
282 :
283 : // Reset timing endpoint
284 0 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
285 :
286 0 : unsigned int pdts_status = 0;
287 0 : unsigned int pdts_control = 0;
288 0 : unsigned int dsp_clock_control = 0;
289 :
290 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
291 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec << std::endl;
292 0 : fDevice->DeviceRead(duneReg.pdts_control, &pdts_control);
293 0 : TLOG() << "The pdts_control read back as 0x" << std::hex << pdts_control << std::dec << std::endl;
294 0 : fDevice->DeviceRead(duneReg.dsp_clock_control, &dsp_clock_control);
295 0 : TLOG() << "The dsp_clock_control read back as 0x" << std::hex << dsp_clock_control << std::dec << std::endl;
296 :
297 0 : unsigned int presentTimingAddress = (pdts_control >> 16) & 0xFF;
298 0 : unsigned int presentTimingPartition = pdts_control & 0x3;
299 :
300 0 : TLOG() << "SSP HW presently on partition " << presentTimingPartition << ", address 0x" << std::hex
301 0 : << presentTimingAddress << " with endpoint status 0x" << (pdts_status & 0xF)
302 0 : << " and dsp_clock_control at 0x" << dsp_clock_control << std::dec << std::endl;
303 :
304 : //if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8 && presentTimingAddress == fTimingAddress &&
305 : // presentTimingPartition == fPartitionNumber && dsp_clock_control == 0x31) {
306 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8 && presentTimingAddress == fTimingAddress &&
307 0 : presentTimingPartition == fPartitionNumber && (dsp_clock_control & 0xF) == 0x1) { //NOTE THAT THIS WAS CHANGED SO THAT IF THE DSP_CLOCK_STATUS LOWEST BIT IS STILL HIGH 0x1
308 : //THEN THE CLOCK ALREADY IS ASSUMED TO BE GOOD, AND WE DON'T TRY TO RESYNCH WITH THE PDTS
309 :
310 0 : TLOG() << "Clock already looks ok... skipping endpoint reset." << std::endl;
311 0 : } else {
312 :
313 0 : TLOG() << "Syncing SSP LED Calib to PDTS (partition " << fPartitionNumber << ", endpoint address 0x"
314 0 : << std::hex << fTimingAddress << std::dec << ")" << std::endl;
315 :
316 0 : unsigned int nTries = 0;
317 :
318 0 : while (nTries < 5) {
319 0 : fDevice->DeviceWrite(duneReg.dsp_clock_control, 0x30);
320 0 : TLOG() << "The dsp_clock_control was set to 0x" << std::hex << 0x30 << std::dec
321 0 : << std::endl; // setting the lowest bit to 0 sets the DSP clock to internal.
322 0 : fDevice->DeviceWrite(duneReg.pdts_control, 0x80000000 + fPartitionNumber + fTimingAddress * 0x10000);
323 0 : TLOG() << "The pdts_control value was set to 0x" << std::hex << 0x80000000 + fPartitionNumber + fTimingAddress * 0x10000
324 0 : << std::dec << std::endl; // setting the highest bit (0x80000000) to 1 puts the SSP in Reset mode for the PDTS.
325 :
326 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
327 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec
328 0 : << std::endl;
329 0 : fDevice->DeviceRead(duneReg.pdts_control, &pdts_control);
330 0 : TLOG() << "The pdts_control read back as 0x" << std::hex << pdts_control << std::dec
331 0 : << 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
334 0 : << std::endl;
335 :
336 0 : fDevice->DeviceWrite(duneReg.pdts_control, 0x00000000 + fPartitionNumber + fTimingAddress * 0x10000);
337 0 : TLOG() << "The pdts_status value was set to 0x" << std::hex
338 0 : << 0x00000000 + fPartitionNumber + fTimingAddress * 0x10000 << std::dec << std::endl;
339 0 : usleep(2000000); // setting the highest bit (0x80000000) to zero puts the SSP in run mode for the PDTS.
340 0 : fDevice->DeviceWrite(duneReg.dsp_clock_control,
341 : 0x31); // setting the lowest bit to 1 sets the DSP clock to external.
342 0 : TLOG() << "The dsp_clock_control was set to 0x" << std::hex << 0x31 << std::dec << std::endl;
343 0 : usleep(2000000);
344 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
345 0 : TLOG() << "The pdts_status read back as 0x" << std::hex << pdts_status << std::dec
346 0 : << std::endl;
347 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8)
348 : break;
349 0 : TLOG() << "Timing endpoint sync failed (try " << nTries << ")" << std::endl;
350 0 : ++nTries;
351 : }
352 :
353 0 : if ((pdts_status & 0xF) >= 0x6 && (pdts_status & 0xF) <= 0x8) {
354 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status
355 0 : << " and the 0xF bit masked value is 0x" << (pdts_status & 0xF) << std::dec
356 0 : << std::endl;
357 0 : TLOG() << "Timing endpoint synced!" << std::endl;
358 : } else {
359 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status
360 0 : << " and the 0xF bit masked value is 0x" << (pdts_status & 0xF) << std::dec
361 0 : << std::endl;
362 0 : TLOG() << "Giving up on endpoint sync after 5 tries. Value of pdts_status register was 0x"
363 0 : << std::hex << pdts_status << std::dec << std::endl;
364 : }
365 : }
366 :
367 0 : TLOG() << "Woke up from 2 seconds of sleep and Waiting for endpoint to reach status 0x8..."
368 0 : << std::endl;
369 : // Wait until pdts_status reaches exactly 0x8 before resolving.
370 0 : if ((pdts_status & 0xF) != 0x8) {
371 0 : TLOG() << "Waiting for endpoint to reach status 0x8..." << std::endl;
372 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status
373 0 : << " and the 0xF bit masked value is 0x" << (pdts_status & 0xF) << std::dec << std::endl;
374 : }
375 : int nTries = 0;
376 0 : while ((pdts_status & 0xF) != 0x8) {
377 0 : if (nTries == 2) {
378 0 : TLOG() << "Wrong PDTS status!" << std::endl;
379 0 : throw DeviceInterfacePDTSStatus(ERS_HERE);
380 : }
381 0 : usleep(2000000);
382 0 : TLOG() << "Woke up from 2 seconds of sleep and Waiting for endpoint to reach status 0x8..."
383 0 : << std::endl;
384 0 : fDevice->DeviceRead(duneReg.pdts_status, &pdts_status);
385 0 : TLOG() << "The pdts_status value is 0x" << std::hex << pdts_status
386 0 : << " and the 0xF bit masked value is 0x" << (pdts_status & 0xF) << std::dec << std::endl;
387 0 : nTries++;
388 : }
389 :
390 0 : TLOG() << "Endpoint is in running state, continuing with configuration!" << std::endl;
391 0 : TLOG() << "SSP LED Calib Device Interface Configured complete.";
392 0 : } // NOLINT(readability/fn_size)
393 :
394 : std::string
395 0 : dunedaq::sspmodules::DeviceInterface::GetIdentifier()
396 : {
397 0 : std::string ident;
398 0 : boost::asio::ip::address ip = boost::asio::ip::address_v4(fDeviceId);
399 0 : std::string ipString = ip.to_string();
400 0 : ident += "(";
401 0 : ident += ipString;
402 0 : ident += "):";
403 0 : return ident;
404 0 : }
405 : void
406 0 : dunedaq::sspmodules::DeviceInterface::PrintHardwareState()
407 : {
408 :
409 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "===SSP DIAGNOSTIC REGISTERS===" << std::endl;
410 :
411 0 : dunedaq::sspmodules::RegMap& duneReg = dunedaq::sspmodules::RegMap::Get();
412 0 : unsigned int val;
413 :
414 0 : fDevice->DeviceRead(duneReg.dp_clock_status, &val);
415 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "dsp_clock_status: 0x" << std::hex << val << std::endl;
416 0 : fDevice->DeviceRead(duneReg.live_timestamp_msb, &val);
417 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "live_timestamp_msb: " << val << std::endl;
418 0 : fDevice->DeviceRead(duneReg.live_timestamp_lsb, &val);
419 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "live_timestamp_lsb: " << val << std::endl;
420 0 : fDevice->DeviceRead(duneReg.sync_delay, &val);
421 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "sync_delay: " << val << std::endl;
422 0 : fDevice->DeviceRead(duneReg.sync_count, &val);
423 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "sync_count: " << val << std::dec << std::endl;
424 0 : }
425 :
426 : #endif // SSPMODULES_SRC_ANLBOARD_DEVICEINTERFACE_CXX_
|