Line data Source code
1 : /**
2 : * @file SSPLEDCalibWrapper.cpp SSP library wrapper implementation
3 : *
4 : * This is part of the DUNE DAQ , copyright 2022.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #ifndef SSPMODULES_SRC_SSPLEDCALIBWRAPPER_CPP_
9 : #define SSPMODULES_SRC_SSPLEDCALIBWRAPPER_CPP_
10 :
11 : // From Module
12 : #include "SSPLEDCalibWrapper.hpp"
13 : /**
14 : * @brief TRACE debug levels used in this source file
15 : */
16 : #define TRACE_NAME "SSPLEDCalibWrapper" // NOLINT
17 :
18 : enum
19 : {
20 : TLVL_ENTER_EXIT_METHODS = 5,
21 : TLVL_WORK_STEPS = 10,
22 : TLVL_BOOKKEEPING = 15,
23 : TLVL_FULL_DEBUG = 63
24 : };
25 :
26 : namespace dunedaq {
27 : namespace sspmodules {
28 :
29 0 : SSPLEDCalibWrapper::SSPLEDCalibWrapper()
30 0 : : m_device_interface(0)
31 0 : , m_run_marker{ false }
32 : {
33 0 : }
34 :
35 0 : SSPLEDCalibWrapper::~SSPLEDCalibWrapper() {}
36 :
37 : void
38 0 : SSPLEDCalibWrapper::init(const appmodel::SSPLEDCalibModule* conf)
39 : {
40 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::init called." << std::endl;
41 :
42 0 : m_number_channels = conf->get_number_channels();
43 0 : m_channel_mask = conf->get_channel_mask();
44 0 : m_burst_count = conf->get_burst_count();
45 0 : m_double_pulse_delay_ticks = conf->get_double_pulse_delay_ticks();
46 0 : m_pulse1_width_ticks = conf->get_pulse1_width_ticks();
47 0 : m_pulse2_width_ticks = conf->get_pulse2_width_ticks();
48 0 : m_pulse_bias_percent_270nm = conf->get_pulse_bias_percent_270nm();
49 0 : m_pulse_bias_percent_367nm = conf->get_pulse_bias_percent_367nm();
50 :
51 0 : m_board_id = conf->get_board_id();
52 0 : m_module_id = conf->get_module_id();
53 0 : m_instance_name_for_metrics = "SSP LED Calib " + std::to_string(m_board_id);
54 0 : m_partition_number = conf->get_partition_number(); // this should be 0-3
55 :
56 0 : m_timing_address = conf->get_timing_address(); // 0x20 is default for 101, 0x2B for 304, and 0x36 for 603
57 0 : if (m_timing_address > 0xff) {
58 0 : std::stringstream ss;
59 0 : ss << "Error: Incorrect timing address set (" << m_timing_address << ")!" << std::endl;
60 0 : TLOG() << ss.str();
61 0 : throw ConfigurationError(ERS_HERE, ss.str());
62 0 : }
63 :
64 0 : TLOG_DEBUG(TLVL_WORK_STEPS) << "Board ID is listed as: " << m_board_id << std::endl
65 0 : << "Partition Number is: " << m_partition_number << std::endl
66 0 : << "Timing Address is: " << m_timing_address << std::endl
67 0 : << "Module ID is: " << m_module_id << std::endl;
68 :
69 0 : try {
70 0 : m_device_interface = new dunedaq::sspmodules::DeviceInterface();
71 0 : m_device_interface->SetPartitionNumber(m_partition_number);
72 0 : m_device_interface->SetTimingAddress(m_timing_address);
73 0 : } catch (const std::exception& e) {
74 0 : throw FailedLEDCalibrationInit(ERS_HERE, e);
75 0 : }
76 :
77 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::init complete.";
78 0 : }
79 :
80 : void
81 0 : SSPLEDCalibWrapper::conf(const appmodel::SSPLEDCalibModule* conf)
82 : {
83 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::conf called." << std::endl;
84 :
85 0 : try {
86 0 : m_device_interface->ConfigureLEDCalib(
87 : conf); // This sets up the ethernet interface and make sure that the pdts is synched
88 0 : m_device_interface->SetRegisterByName("module_id", m_module_id);
89 : // m_device_interface->SetRegisterByName("eventDataInterfaceSelect", m_cfg.interface_type);
90 0 : } catch (const std::exception& e) {
91 0 : throw FailedLEDCalibrationConf(ERS_HERE, e);
92 0 : }
93 :
94 0 : if (conf->get_pulse_mode() == "single") {
95 0 : m_single_pulse = true;
96 0 : TLOG(TLVL_FULL_DEBUG) << "SSPLEDCalibWrapper: I think that you want SSP LED Calib module to be in single pulse..."
97 0 : << std::endl;
98 0 : } else if (conf->get_pulse_mode() == "burst") {
99 0 : m_burst_mode = true;
100 0 : TLOG(TLVL_FULL_DEBUG) << "SSPLEDCalibWrapper: I think that you want SSP LED Calib module to be in BURST MODE..."
101 0 : << std::endl;
102 : }
103 :
104 0 : if ((m_single_pulse && m_burst_mode)) {
105 0 : std::stringstream ss;
106 0 : ss << "ERROR: SOMEHOW ENDED UP WITH SEVERAL PULSE MODES SET ON!!!!" << std::endl;
107 0 : TLOG() << ss.str();
108 0 : throw ConfigurationError(ERS_HERE, ss.str());
109 0 : }
110 :
111 0 : if (m_burst_mode) {
112 0 : TLOG(TLVL_FULL_DEBUG) << "SSPLEDCalibWrapper: Configuring for BURST MODE..." << std::endl;
113 0 : this->configure_burst_mode();
114 0 : } else if (m_single_pulse) {
115 0 : TLOG(TLVL_FULL_DEBUG) << "SSPLEDCalibWrapper: Configuring for single pulse mode..." << std::endl;
116 0 : this->configure_single_pulse();
117 : } else {
118 0 : std::stringstream ss;
119 0 : ss << "ERROR: SOMEHOW ENDED UP WITH NO PULSE MODES SET ON!!!!" << std::endl;
120 0 : TLOG() << ss.str();
121 0 : throw ConfigurationError(ERS_HERE, ss.str());
122 0 : }
123 :
124 : // if there are "literal" entries in the configuration they are explicit writes to the specified register with given
125 : // value these literal entries are paresed and applied last after any other parameters so this method call needs to be
126 : // after the other configuration calls
127 0 : this->manual_configure_device(conf->get_hardware_configuration());
128 :
129 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::conf complete.";
130 0 : }
131 :
132 : void
133 0 : SSPLEDCalibWrapper::start(const data_t& /*args*/)
134 : {
135 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Start pulsing SSPLEDCalibWrapper of card " << m_board_id << "...";
136 :
137 0 : if (m_run_marker.load()) {
138 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Run Marker says that SSPLEDCalibWrapper card " << m_board_id
139 0 : << " is already pulsing...";
140 0 : return;
141 : }
142 :
143 0 : unsigned int base_bias_regAddress = 0x40000340;
144 0 : unsigned int base_timing_regAddress = 0x800003C0;
145 :
146 0 : if (m_number_channels == 5) {
147 0 : base_bias_regAddress = 0x4000035C;
148 0 : base_timing_regAddress = 0x800003DC;
149 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Configuring board with 5 channels...";
150 0 : } else if (m_number_channels == 12) {
151 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Configuring board with 12 channels...";
152 : } else {
153 0 : std::stringstream ss;
154 0 : ss << "ERROR: SOMEHOW ENDED UP WITHOUT NUMBER OF CHANNELS SET!!!!" << std::endl;
155 0 : TLOG() << ss.str();
156 0 : throw ConfigurationError(ERS_HERE, ss.str());
157 0 : }
158 :
159 0 : unsigned int pulse_bias_setting_270nm = (m_pulse_bias_percent_270nm);
160 0 : unsigned int pulse_bias_setting_367nm = (m_pulse_bias_percent_367nm / 2);
161 :
162 0 : for (unsigned int counter = 0; counter < m_number_channels; counter++) {
163 0 : unsigned int bias_regAddress = base_bias_regAddress + 0x4 * (counter); // 0x40000340 - 0x4000036C
164 0 : unsigned int bias_regVal = 0x00040000;
165 0 : unsigned int timing_regAddress = base_timing_regAddress + 0x4 * (counter); // 0x80003C0 - 0x800003EC
166 0 : unsigned int timing_regVal = 0x0; // the highest byte sets 8 (pdts trigger) + 1 (953.5 Hz) for burst mode, but 8
167 : // (pdts trigger) + 7 (single shot) for single
168 0 : if (m_single_pulse) {
169 0 : timing_regVal = 0xF0000000;
170 0 : } else if (m_burst_mode) {
171 0 : timing_regVal = 0x90000000;
172 : }
173 :
174 0 : TLOG(TLVL_FULL_DEBUG) << "Channel map is 0x" << std::hex << m_channel_mask << " and the comparison is 0x"
175 0 : << (1 << counter) << std::endl;
176 0 : if ((m_channel_mask & ((unsigned int)1 << counter)) == ((unsigned int)1 << counter)) {
177 0 : if (counter < 6) {
178 0 : bias_regVal = bias_regVal + pulse_bias_setting_270nm;
179 : } else {
180 0 : bias_regVal = bias_regVal + pulse_bias_setting_367nm;
181 : }
182 0 : timing_regVal = timing_regVal + m_pulse1_width_ticks;
183 0 : timing_regVal = timing_regVal + (m_pulse2_width_ticks << 8);
184 0 : timing_regVal = timing_regVal + (m_double_pulse_delay_ticks << 16);
185 0 : TLOG(TLVL_FULL_DEBUG) << "Will turn on " << std::dec << counter << " channel at bias register 0x" << std::hex
186 0 : << bias_regAddress << " with bias value 0x" << bias_regVal << std::endl;
187 0 : TLOG(TLVL_FULL_DEBUG) << " and set the width regsiter 0x" << std::hex << timing_regAddress << " to value of 0x"
188 0 : << timing_regVal << std::dec << std::endl;
189 0 : m_device_interface->SetRegister(bias_regAddress, bias_regVal); // BIAS_DAC_CONFIG_N
190 0 : if ((counter == 7) && !((m_channel_mask & ((unsigned int)1 << counter)) == ((unsigned int)1 << (counter - 1)))) {
191 : // this is a really convoluted situation where for the very specific 12 channel board that arrived at CERN in
192 : // June 2022 the bias for channel 7 was not working and so the bias is taken from channel 6 which means that if
193 : // channel 7 is to be turned on while channel 6 is masked off you still have to bias channel 6 in order for the
194 : // led on channel 7 to emmit light
195 0 : m_device_interface->SetRegister((bias_regAddress - 0x4), bias_regVal); // BIAS_DAC_CONFIG_N
196 : }
197 :
198 0 : m_device_interface->SetRegister(timing_regAddress, timing_regVal); // cal_CONFIG_N
199 : } else {
200 0 : TLOG(TLVL_FULL_DEBUG) << "Will turn off channel " << std::dec << counter << " at timing register 0x" << std::hex
201 0 : << timing_regAddress << std::dec << std::endl;
202 0 : m_device_interface->SetRegister(bias_regAddress, 0x0); // BIAS_DAC_CONFIG_N
203 0 : m_device_interface->SetRegister(timing_regAddress, 0x0); // cal_CONFIG_N
204 : }
205 : }
206 :
207 0 : m_device_interface->SetRegister(0x40000300, 0x1); // writing 0x1 to this register applies the bias voltage settings
208 :
209 0 : m_run_marker = true;
210 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Start pulsing SSPLEDCalibWrapper of card " << m_board_id << " complete.";
211 : }
212 :
213 : void
214 0 : SSPLEDCalibWrapper::stop(const data_t& /*args*/)
215 : {
216 :
217 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Stop pulsing SSPLEDCalibWrapper of card " << m_board_id << "...";
218 0 : if (!m_run_marker.load()) {
219 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "The run_marker says that SSPLEDCalibWrapper card " << m_board_id
220 0 : << " is already stopped, but stopping anyways...";
221 : }
222 :
223 0 : for (unsigned int counter = 0; counter < 12; counter++) { // switch this to 12 for a 12 channel SSP
224 0 : unsigned int bias_regAddress = 0x40000340 + 0x4 * (counter);
225 0 : unsigned int timing_regAddress = 0x800003c0 + 0x4 * (counter);
226 0 : m_device_interface->SetRegister(bias_regAddress, 0x00000000); // BIAS_DAC_CONFIG_N
227 0 : m_device_interface->SetRegister(timing_regAddress, 0x00000000); // cal_CONFIG_N
228 : }
229 :
230 0 : m_device_interface->SetRegister(0x40000300, 0x1); // writing 0x1 to this register applies the bias voltage settings
231 :
232 0 : m_run_marker = false;
233 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "Stop pulsing SSPLEDCalibWrapper of card " << m_board_id << " complete.";
234 0 : }
235 :
236 : void
237 0 : SSPLEDCalibWrapper::configure_single_pulse()
238 : {
239 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureSinglePulse called.";
240 :
241 0 : m_device_interface->SetRegister(0x80000464, 0x000002E7); // pdts_cmd_control_1
242 0 : m_device_interface->SetRegister(0x80000940, 0x00030036); // pdts_cmd_delay_0
243 0 : m_device_interface->SetRegister(0x80000944, 0x00030036); // pdts_cmd_delay_1
244 0 : m_device_interface->SetRegister(0x80000948, 0x00030036); // pdts_cmd_delay_2
245 0 : m_device_interface->SetRegister(0x8000094C, 0x00030036); // pdts_cmd_delay_3
246 0 : m_device_interface->SetRegister(0x80000950, 0x00030036); // pdts_cmd_delay_4
247 0 : m_device_interface->SetRegister(0x80000954, 0x00030036); // pdts_cmd_delay_5
248 0 : m_device_interface->SetRegister(0x80000958, 0x00030036); // pdts_cmd_delay_6
249 0 : m_device_interface->SetRegister(0x8000095C, 0x00030036); // pdts_cmd_delay_7
250 0 : m_device_interface->SetRegister(0x80000960, 0x00030036); // pdts_cmd_delay_8
251 0 : m_device_interface->SetRegister(0x80000964, 0x00030036); // pdts_cmd_delay_9
252 0 : m_device_interface->SetRegister(0x80000968, 0x00030036); // pdts_cmd_delay_10
253 0 : m_device_interface->SetRegister(0x8000096C, 0x00030036); // pdts_cmd_delay_11
254 0 : m_device_interface->SetRegister(0x80000970, 0x00030036); // pdts_cmd_delay_12
255 0 : m_device_interface->SetRegister(0x80000974, 0x00030036); // pdts_cmd_delay_13
256 0 : m_device_interface->SetRegister(0x80000978, 0x00030036); // pdts_cmd_delay_14
257 0 : m_device_interface->SetRegister(0x8000097C, 0x00030036); // pdts_cmd_delay_15
258 0 : m_device_interface->SetRegister(0x80000468, 0x80000000); // pdts_cmd_control_2
259 0 : m_device_interface->SetRegister(0x80000520, 0x00000011); // pulser_mode_control
260 0 : m_device_interface->SetRegister(0x80000448, 0x00000001); // cal_count
261 :
262 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureSinglePulse completed.";
263 0 : }
264 :
265 : void
266 0 : SSPLEDCalibWrapper::configure_burst_mode()
267 : {
268 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureBurstMode called.";
269 :
270 0 : m_device_interface->SetRegister(0x80000464, 0x000002E7); // pdts_cmd_control_1
271 0 : m_device_interface->SetRegister(0x80000940, 0x00030036); // pdts_cmd_delay_0
272 0 : m_device_interface->SetRegister(0x80000944, 0x00030036); // pdts_cmd_delay_1
273 0 : m_device_interface->SetRegister(0x80000948, 0x00030036); // pdts_cmd_delay_2
274 0 : m_device_interface->SetRegister(0x8000094C, 0x00030036); // pdts_cmd_delay_3
275 0 : m_device_interface->SetRegister(0x80000950, 0x00030036); // pdts_cmd_delay_4
276 0 : m_device_interface->SetRegister(0x80000954, 0x00030036); // pdts_cmd_delay_5
277 0 : m_device_interface->SetRegister(0x80000958, 0x00030036); // pdts_cmd_delay_6
278 0 : m_device_interface->SetRegister(0x8000095C, 0x00030036); // pdts_cmd_delay_7
279 0 : m_device_interface->SetRegister(0x80000960, 0x00030036); // pdts_cmd_delay_8
280 0 : m_device_interface->SetRegister(0x80000964, 0x00030036); // pdts_cmd_delay_9
281 0 : m_device_interface->SetRegister(0x80000968, 0x00030036); // pdts_cmd_delay_10
282 0 : m_device_interface->SetRegister(0x8000096C, 0x00030036); // pdts_cmd_delay_11
283 0 : m_device_interface->SetRegister(0x80000970, 0x00030036); // pdts_cmd_delay_12
284 0 : m_device_interface->SetRegister(0x80000974, 0x00030036); // pdts_cmd_delay_13
285 0 : m_device_interface->SetRegister(0x80000978, 0x00030036); // pdts_cmd_delay_14
286 0 : m_device_interface->SetRegister(0x8000097C, 0x00030036); // pdts_cmd_delay_15
287 0 : m_device_interface->SetRegister(0x80000468, 0x80000000); // pdts_cmd_control_2
288 0 : m_device_interface->SetRegister(0x80000520, 0x00000011); // pulser_mode_control
289 0 : m_device_interface->SetRegister(0x80000448, m_burst_count); // cal_count
290 :
291 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureBurstMode completed.";
292 0 : }
293 :
294 : void
295 0 : SSPLEDCalibWrapper::manual_configure_device(const std::vector<const appmodel::SSPRegister*>& hw_conf)
296 : {
297 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureDevice called.";
298 0 : TLOG(TLVL_FULL_DEBUG) << "SSPLEDCalibWrapper: Processing the Hardware Configuration list..." << std::endl;
299 0 : for (auto regValuesIter : hw_conf) {
300 0 : std::string m_name = regValuesIter->get_name();
301 0 : unsigned int regAddr = regValuesIter->get_address();
302 0 : unsigned int regVal = regValuesIter->get_value();
303 0 : unsigned int regMask = regValuesIter->get_mask();
304 0 : m_device_interface->SetRegister(regAddr, regVal, regMask);
305 0 : }
306 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::ConfigureDevice complete.";
307 0 : } // NOLINT(readability/fn_size)
308 :
309 : void
310 0 : SSPLEDCalibWrapper::validate_config(const data_t& /*args*/)
311 : {
312 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::validate_config called.";
313 :
314 0 : if (!((m_number_channels == 5) || (m_number_channels == 12))) {
315 0 : std::stringstream ss;
316 0 : ss << "ERROR: Incorrect number_channels value " << m_number_channels << " is not equal to 5 or 12!!!" << std::endl;
317 0 : TLOG() << ss.str();
318 0 : throw ConfigurationError(ERS_HERE, ss.str());
319 0 : }
320 :
321 0 : if (m_channel_mask > 4095) {
322 0 : std::stringstream ss;
323 0 : ss << "ERROR: Incorrect channel_maks value " << m_channel_mask << " is higher than the limit of 4095!!!"
324 0 : << std::endl;
325 0 : TLOG() << ss.str();
326 0 : throw ConfigurationError(ERS_HERE, ss.str());
327 0 : }
328 :
329 0 : if (!(m_single_pulse || m_burst_mode)) {
330 0 : std::stringstream ss;
331 0 : ss << "ERROR: Incorrect pulse_mode value. Neither single or burst." << std::endl;
332 0 : TLOG() << ss.str();
333 0 : throw ConfigurationError(ERS_HERE, ss.str());
334 0 : }
335 :
336 0 : if (m_double_pulse_delay_ticks > 4095) {
337 0 : std::stringstream ss;
338 0 : ss << "ERROR: Strange!! double_pulse_delay_ticks value is " << m_double_pulse_delay_ticks
339 0 : << ", which is greater than the limit of 4095" << std::endl;
340 0 : TLOG() << ss.str();
341 : // throw ConfigurationError(ERS_HERE, ss.str());
342 0 : }
343 :
344 0 : if (m_burst_count > 10000) {
345 0 : std::stringstream ss;
346 0 : ss << "ERROR: Strange!! burst_count value is " << m_burst_count
347 0 : << ", which is more time than in a drift readout window" << std::endl;
348 0 : TLOG() << ss.str();
349 : // throw ConfigurationError(ERS_HERE, ss.str());
350 0 : }
351 :
352 0 : if (m_pulse1_width_ticks > 255) {
353 0 : std::stringstream ss;
354 0 : ss << "ERROR: Incorrect pulse1_width_ticks value is " << m_pulse1_width_ticks
355 0 : << ", which is greater than the limit of 255!!!" << std::endl;
356 0 : TLOG() << ss.str();
357 0 : throw ConfigurationError(ERS_HERE, ss.str());
358 0 : }
359 :
360 0 : if (m_pulse2_width_ticks > 255) {
361 0 : std::stringstream ss;
362 0 : ss << "ERROR: Incorrect pulse2_width_ticks value is " << m_pulse2_width_ticks
363 0 : << ", which is greater than the limit of 255!!!" << std::endl;
364 0 : TLOG() << ss.str();
365 0 : throw ConfigurationError(ERS_HERE, ss.str());
366 0 : }
367 :
368 0 : if (m_pulse_bias_percent_270nm > 4095) {
369 0 : std::stringstream ss;
370 0 : ss << "ERROR: Incorrect pulse_bias_percent_270nm value is " << m_pulse_bias_percent_270nm
371 0 : << ", which is greater than 100 percent!!!" << std::endl;
372 0 : TLOG() << ss.str();
373 0 : throw ConfigurationError(ERS_HERE, ss.str());
374 0 : }
375 :
376 0 : if (m_pulse_bias_percent_367nm > 4095) {
377 0 : std::stringstream ss;
378 0 : ss << "ERROR: Incorrect pulse_bias_percent_367nm value is " << m_pulse_bias_percent_367nm
379 0 : << ", which is greater than 100 percent!!!" << std::endl;
380 0 : TLOG() << ss.str();
381 0 : throw ConfigurationError(ERS_HERE, ss.str());
382 0 : }
383 :
384 0 : TLOG_DEBUG(TLVL_ENTER_EXIT_METHODS) << "SSPLEDCalibWrapper::validate_config complete.";
385 0 : }
386 :
387 : } // namespace sspmodules
388 : } // namespace dunedaq
389 :
390 : #endif // SSPMODULES_SRC_SSPLEDCALIBWRAPPER_CPP_
|