DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
PC059IONode.cpp
Go to the documentation of this file.
1
10
11#include "logging/Logging.hpp"
12
13#include <string>
14
15namespace dunedaq {
16namespace timing {
17
18UHAL_REGISTER_DERIVED_NODE(PC059IONode)
19
20//-----------------------------------------------------------------------------
21PC059IONode::PC059IONode(const uhal::Node& node)
22 : SFPMuxIONode(node, "i2c", "i2c", "SI5345", { "PLL", "CDR" }, { "usfp_i2c", "i2c" })
23{}
24//-----------------------------------------------------------------------------
25
26//-----------------------------------------------------------------------------
28//-----------------------------------------------------------------------------
29
30//-----------------------------------------------------------------------------
31std::string
33{
34 return "FMC_UID_PROM";
35}
36//-----------------------------------------------------------------------------
37
38//-----------------------------------------------------------------------------
39std::string
40PC059IONode::get_status(bool print_out) const
41{
42 std::stringstream status;
43 auto subnodes = read_sub_nodes(getNode("csr.stat"));
44 status << format_reg_table(subnodes, "PC059 IO state");
45
46 if (print_out)
47 TLOG() << std::endl << status.str();
48 return status.str();
49}
50//-----------------------------------------------------------------------------
51
52//-----------------------------------------------------------------------------
53void
54PC059IONode::reset(const std::string& clock_config_file) const
55{
56 // Soft reset
58
59 millisleep(1000);
60
61 // Reset PLL and I2C
62 getNode("csr.ctrl.pll_rst").write(0x1);
63 getNode("csr.ctrl.pll_rst").write(0x0);
64
65 getNode("csr.ctrl.rst_i2c").write(0x1);
66 getNode("csr.ctrl.rst_i2c").write(0x0);
67
68 getNode("csr.ctrl.rst_i2cmux").write(0x1);
69 getNode("csr.ctrl.rst_i2cmux").write(0x0);
70
71 getClient().dispatch();
72
73 // enclustra i2c switch stuff
74 try {
75 getNode<I2CMasterNode>(m_uid_i2c_bus).get_slave("AX3_Switch").write_i2c(0x01, 0x7f);
76 } catch (const std::exception& e) {
77 ers::warning(EnclustraSwitchFailure(ERS_HERE, e));
78 }
79
80 // Upload config file to PLL
81 configure_pll(clock_config_file);
82
83 // Reset mmcm
84 getNode("csr.ctrl.rst").write(0x1);
85 getNode("csr.ctrl.rst").write(0x0);
86 getClient().dispatch();
87
88 getNode("csr.ctrl.mux").write(0);
89 getClient().dispatch();
90
91 auto sfp_expander = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "SFPExpander");
92
93 // Set invert registers to default for both banks
94 sfp_expander->set_inversion(0, 0x00);
95 sfp_expander->set_inversion(1, 0x00);
96
97 // Bank 0 output, bank 1 input
98 sfp_expander->set_io(0, 0x00);
99 sfp_expander->set_io(1, 0xff);
100
101 // Bank 0 - enable all SFPGs (enable low)
102 sfp_expander->set_outputs(0, 0x00);
103 TLOG_DEBUG(0) << "SFPs 0-7 enabled";
104
105 // To be removed from firmware address maps also
106 //getNode("csr.ctrl.rst_lock_mon").write(0x1);
107 //getNode("csr.ctrl.rst_lock_mon").write(0x0);
108 //getClient().dispatch();
109
110 TLOG() << "Reset done";
111}
112//-----------------------------------------------------------------------------
113
114//-----------------------------------------------------------------------------
115void
117{
118}
119//-----------------------------------------------------------------------------
120
121//-----------------------------------------------------------------------------
122void
123PC059IONode::switch_sfp_mux_channel(uint32_t mux_channel) const // NOLINT(build/unsigned)
124{
125 getNode("csr.ctrl.mux").write(mux_channel);
126 getClient().dispatch();
127
128 TLOG_DEBUG(3) << "SFP input mux set to " << format_reg_value(read_active_sfp_mux_channel());
129}
130//-----------------------------------------------------------------------------
131
132//-----------------------------------------------------------------------------
133uint32_t // NOLINT(build/unsigned)
135{
136 auto active_sfp_mux_channel = getNode("csr.ctrl.mux").read();
137 getClient().dispatch();
138 return active_sfp_mux_channel.value();
139}
140//-----------------------------------------------------------------------------
141
142//-----------------------------------------------------------------------------
143void
144PC059IONode::switch_sfp_i2c_mux_channel(uint32_t sfp_id) const // NOLINT(build/unsigned)
145{
146
147 getNode("csr.ctrl.rst_i2cmux").write(0x1);
148 getClient().dispatch();
149 getNode("csr.ctrl.rst_i2cmux").write(0x0);
150 getClient().dispatch();
151 millisleep(100);
152
153 uint8_t channel_select_byte = 1UL << sfp_id; // NOLINT(build/unsigned)
154 getNode<I2CMasterNode>(m_pll_i2c_bus).get_slave("SFP_Switch").write_i2cPrimitive({ channel_select_byte });
155 TLOG_DEBUG(3) << "PC059 SFP I2C mux set to " << format_reg_value(sfp_id);
156}
157//-----------------------------------------------------------------------------
158
159//-----------------------------------------------------------------------------
160std::string
161PC059IONode::get_sfp_status(uint32_t sfp_id, bool print_out) const // NOLINT(build/unsigned)
162{
163 // on this board the upstream sfp has its own i2c bus, and the 8 downstream sfps are muxed onto the main i2c bus
164 std::stringstream status;
165 uint32_t sfp_bus_index; // NOLINT(build/unsigned)
166 if (sfp_id == 0) {
167 sfp_bus_index = 0;
168 status << "Upstream SFP:" << std::endl;
169 } else if (sfp_id > 0 && sfp_id < 9) {
170 switch_sfp_i2c_mux_channel(sfp_id - 1);
171 status << "Fanout SFP " << sfp_id - 1 << ":" << std::endl;
172 sfp_bus_index = 1;
173 } else {
174 throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
175 }
176 auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(sfp_bus_index), "SFP_EEProm");
177
178 status << sfp->get_status();
179
180 if (print_out)
181 TLOG() << status.str();
182 return status.str();
183}
184//-----------------------------------------------------------------------------
185
186//-----------------------------------------------------------------------------
187bool
189{
190 std::stringstream status;
191
192 auto states = read_sub_nodes(getNode("csr.stat"));
193 bool pll_ok = states.find("pll_ok")->second.value();
194 bool mmcm_ok = states.find("mmcm_ok")->second.value();
195
196 TLOG_DEBUG(5) << "pll ok: " << pll_ok << ", mmcm ok: " << mmcm_ok;
197
198 return pll_ok && mmcm_ok;
199}
200//-----------------------------------------------------------------------------
201
202//-----------------------------------------------------------------------------
203void
204PC059IONode::switch_sfp_soft_tx_control_bit(uint32_t sfp_id, bool turn_on) const // NOLINT(build/unsigned)
205{
206 // on this board the upstream sfp has its own i2c bus, and the 8 downstream sfps are muxed onto the main i2c bus
207 uint32_t sfp_bus_index; // NOLINT(build/unsigned)
208 if (sfp_id == 0) {
209 sfp_bus_index = 0;
210 } else if (sfp_id > 0 && sfp_id < 9) {
211 switch_sfp_i2c_mux_channel(sfp_id - 1);
212 sfp_bus_index = 1;
213 } else {
214 throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
215 }
216 auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(sfp_bus_index), "SFP_EEProm");
217 sfp->switch_soft_tx_control_bit(turn_on);
218}
219//-----------------------------------------------------------------------------
220
221//-----------------------------------------------------------------------------
222void
223PC059IONode::switch_sfp_tx(uint32_t sfp_id, bool turn_on) const { // NOLINT(build/unsigned)
224
225 validate_sfp_id(sfp_id);
226
227 auto sfp_expander = get_i2c_device<I2CExpanderSlave>(m_uid_i2c_bus, "SFPExpander");
228 uint8_t current_sfp_tx_control_flags = sfp_expander->read_outputs_config(0); // NOLINT(build/unsigned)
229
230 uint8_t new_sfp_tx_control_flags; // NOLINT(build/unsigned)
231 if (turn_on)
232 {
233 new_sfp_tx_control_flags = current_sfp_tx_control_flags & ~(1UL << sfp_id);
234 }
235 else
236 {
237 new_sfp_tx_control_flags = current_sfp_tx_control_flags | (1UL << sfp_id);
238 }
239
240 sfp_expander->set_outputs(0, new_sfp_tx_control_flags);
241}
242//-----------------------------------------------------------------------------
243
244//-----------------------------------------------------------------------------
245void
246PC059IONode::validate_sfp_id(uint32_t sfp_id) const // NOLINT(build/unsigned)
247{
248 // on this board we have 8 downstream SFPs
249 if (sfp_id > 7)
250 {
251 throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id));
252 }
253}
254//-----------------------------------------------------------------------------
255
256//-----------------------------------------------------------------------------
257// void
258// PC059IONode::get_info(timinghardwareinfo::TimingPC059MonitorData& mon_data) const
259// {
260// auto subnodes = read_sub_nodes(getNode("csr.stat"));
261
262// mon_data.cdr_lol = subnodes.at("cdr_lol").value();
263// mon_data.cdr_los = subnodes.at("cdr_los").value();
264
265// mon_data.mmcm_ok = subnodes.at("mmcm_ok").value();
266// mon_data.mmcm_sticky = subnodes.at("mmcm_sticky").value();
267
268// mon_data.pll_lol = subnodes.at("pll_lol").value();
269// mon_data.pll_ok = subnodes.at("pll_ok").value();
270// mon_data.pll_sticky = subnodes.at("pll_sticky").value();
271
272// mon_data.sfp_los = subnodes.at("sfp_los").value();
273
274// mon_data.ucdr_lol = subnodes.at("ucdr_lol").value();
275// mon_data.ucdr_los = subnodes.at("ucdr_los").value();
276
277// mon_data.usfp_flt = subnodes.at("usfp_flt").value();
278// mon_data.usfp_los = subnodes.at("usfp_los").value();
279// }
280//-----------------------------------------------------------------------------
281
282//-----------------------------------------------------------------------------
283// void
284// PC059IONode::get_info(opmonlib::InfoCollector& ci, int level) const
285// {
286// if (level >= 2)
287// {
288// timinghardwareinfo::TimingPLLMonitorData pll_mon_data;
289// this->get_pll()->get_info(pll_mon_data);
290// ci.add(pll_mon_data);
291
292// timinghardwareinfo::TimingSFPMonitorData upstream_sfp_mon_data;
293// auto upstream_sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(0), "SFP_EEProm");
294// try {
295// upstream_sfp->get_info(upstream_sfp_mon_data);
296// opmonlib::InfoCollector upstream_sfp_ic;
297// upstream_sfp_ic.add(upstream_sfp_mon_data);
298// ci.add("upstream_sfp", upstream_sfp_ic);
299// }
300// catch (timing::SFPUnreachable& e) {
301// // It is valid that an SFP may not be installed, currently no good way of knowing whether they it should be
302// TLOG_DEBUG(2) << "Failed to communicate with upstream SFP on i2c bus" << m_sfp_i2c_buses.at(0);
303// }
304
305
306// for (uint sfp_id=0; sfp_id < 8; ++sfp_id) {
307// TLOG_DEBUG(5) << "checking sfp: " << sfp_id;
308// switch_sfp_i2c_mux_channel(sfp_id);
309
310// auto sfp = get_i2c_device<I2CSFPSlave>(m_sfp_i2c_buses.at(1), "SFP_EEProm");
311// timinghardwareinfo::TimingSFPMonitorData sfp_data;
312
313// try {
314// sfp->get_info(sfp_data);
315// } catch (timing::SFPUnreachable& e) {
316// // It is valid that an SFP may not be installed, currently no good way of knowing whether they it should be
317// TLOG_DEBUG(2) << "Failed to communicate with downstream SFP: " << sfp_id << " on i2c bus" << m_sfp_i2c_buses.at(1);
318// continue;
319// }
320
321// opmonlib::InfoCollector sfp_ic;
322// sfp_ic.add(sfp_data);
323// ci.add("sfp_"+std::to_string(sfp_id), sfp_ic);
324// }
325// }
326
327// if (level >= 1) {
328// timinghardwareinfo::TimingPC059MonitorData mon_data;
329// this->get_info(mon_data);
330// ci.add(mon_data);
331// }
332// }
333//-----------------------------------------------------------------------------
334
335} // namespace timing
336} // namespace dunedaq
#define ERS_HERE
virtual void write_soft_reset_register() const
Write soft reset register.
Definition IONode.cpp:287
const std::string m_uid_i2c_bus
Definition IONode.hpp:210
virtual void configure_pll(const std::string &clock_config_file="") const
Configure clock chip.
Definition IONode.cpp:238
std::unique_ptr< const T > get_i2c_device(const std::string &i2c_bus_name, const std::string &i2c_device_name) const
Get the an I2C chip.
Definition IONode.hxx:6
Class for the PC059 board.
uint32_t read_active_sfp_mux_channel() const override
Read the active SFP mux channel.
void switch_sfp_soft_tx_control_bit(uint32_t sfp_id, bool turn_on) const override
control tx laser of on-board SFP softly (I2C command)
bool clocks_ok() const override
Clocks ready?
void switch_sfp_mux_channel(uint32_t mux_channel) const override
Switch the SFP mux channel.
void validate_sfp_id(uint32_t sfp_id) const
Fill hardware monitoring structure.
std::string get_uid_address_parameter_name() const override
Get the UID address parameter name.
std::string get_sfp_status(uint32_t sfp_id, bool print_out=false) const override
Print status of on-board SFP.
std::string get_status(bool print_out=false) const override
Get status string, optionally print.
void switch_sfp_i2c_mux_channel(uint32_t sfp_id) const
Switch the SFP I2C mux channel.
void switch_sfp_tx(uint32_t sfp_id, bool turn_on) const override
control tx laser of on-board SFP softly (I2C command)
void reset(const std::string &clock_config_file) const override
Reset pc059 node.
void reset_pll() const override
Reset PLL.
Base class for boards which have a physical SFP mux.
std::map< std::string, uhal::ValWord< uint32_t > > read_sub_nodes(const uhal::Node &node, bool dispatch=true) const
Read subnodes.
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
#define TLOG(...)
Definition macro.hpp:22
std::string format_reg_table(T data, std::string title, std::vector< std::string > headers)
Format reg-value table.
Definition toolbox.hxx:166
std::string format_reg_value(T reg_value, uint32_t base)
Definition toolbox.hxx:117
void millisleep(const double &time_in_milliseconds)
Definition toolbox.cpp:83
The DUNE-DAQ namespace.
Definition DataStore.hpp:57
void warning(const Issue &issue)
Definition ers.hpp:115