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