REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
tblock.cpp
Go to the documentation of this file.
1#include <entity/visitor.h>
2#include <proto/main.pb.h>
3
4#include <redac/tblock.h>
5
6using namespace blocks;
7
8TBlock::TBlock(TBlockHAL *hardware) : FunctionBlock("T", hardware), hardware(hardware) { classifier.class_enum = CLASS_; }
9
10ConfigResult TBlock::config(const pb_Config &cfg) {
11 if (cfg.which_kind == pb_Config_switch_config_tag) {
12 auto &switch_config = cfg.kind.switch_config;
13 return apply_muxes(switch_config.muxes);
14 }
15
16 if (cfg.which_kind == pb_UseConfig_uses_tag) {
17 auto &use_config = cfg.kind.use_config;
18 return apply_uses(use_config.uses);
19 }
20
21 // unhandled
22 return ConfigResult::ok(false);
23}
24
25ConfigResult TBlock::apply_muxes(const pb_Mux (&muxes)[TBlockHAL::NUM_SWITCHES]) {
26 size_t idx = -1;
27 for (auto &mux : muxes) {
28 idx++;
29 if (!mux.has_state)
30 // Mux is not required for this configuration, keep it in previous configuration.
31 // The rest of the configuration must ensure that this is not a problem.
32 continue;
33
34 auto mux_value = mux.state;
35 if (mux_value < 0 || 4 <= mux_value)
36 return ConfigResult::err("TBlock: Mux must be interval [0, 3]");
37 connections[idx] = mux_value;
38 }
39
40 return ConfigResult::ok(true);
41}
42
43ConfigResult TBlock::apply_uses(const pb_Use (&uses)[TBlockHAL::NUM_SWITCHES]) {
44 for (auto &use : uses) {
45 external_signal_sources[use.idx] = use.has_source ? static_cast<int32_t>(use.source) : -1;
46 external_target_upscaling[use.idx] = use.upscaled;
47 }
48
49 return ConfigResult::ok(true);
50}
51
52std::array<uint8_t, TBlockHAL::NUM_SWITCHES> TBlock::get_connections() const { return connections; }
53
54void TBlock::set_connections(const std::array<uint8_t, TBlockHAL::NUM_SWITCHES> &connections) { this->connections = connections; }
55
56void TBlock::extract(entities::ExtractVisitor &collector) {
57 auto &cfg = collector.create(pb_Config_switch_config_tag);
58 auto &switch_config = cfg.kind.switch_config = pb_SwitchConfig_init_default;
59
60 auto &idx = switch_config.muxes_count = 0;
61 for (; idx < connections.size(); ++idx) {
62 switch_config.muxes[idx] = {
63 .has_state = true,
64 .state = connections[idx],
65 };
66 }
67}
68
69status TBlock::connect(Sector src_sector, Sector dst_sector, uint8_t lane_idx) {
70 if (lane_idx > 23)
71 return status("Invalid lane. Remember that TBlock lanes are allways counted from 0 to 23");
72
73 connections[lane_idx * 4 + dst_sector] = src_sector;
74
75 return status::success();
76}
77
78TBlock::Sector TBlock::src_of_signal(Sector dst_sector, uint8_t lane_idx) const {
79 if (lane_idx > 23)
80 return Sector::BPL;
81
82 return static_cast<Sector>(connections[lane_idx * 4 + dst_sector]);
83}
84
86
87void TBlock::reset(entities::ResetAction action) {
88 Entity::reset(action);
89 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
90 reset_connections();
92 }
93 if (action.has(entities::ResetAction::EVERYTHING))
94 enabled = true;
95}
96
97void TBlock::reset_external_signal_infos() {
98 external_signal_sources = {};
99 external_target_upscaling = {};
100}
101
102void TBlock::reset_connections() {
103 // Note that the T-block always has connections, unless it is completely disabled (powered-off).
104 // The least surprising default connection is to have signals stay in their originating cluster.
105 connections = {Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
106 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
107 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
108 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
109 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
110 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
111 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
112 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
113 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
114 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2};
115}
116
117status TBlock::write_to_hardware() {
118 RETURN_IF_FAILED(Entity::write_to_hardware());
119 if (!hardware->write_muxes(connections))
120 return status("Error writing mux settings to hardware.");
121 if (enabled)
122 hardware->reset_mux_disable();
123 else
124 hardware->set_mux_disable();
125 return status::success();
126}
127
128bool TBlock::is_enabled() const { return enabled; }
129
130void TBlock::set_enabled(bool enabled_) { enabled = enabled_; }
131
132int32_t TBlock::get_external_signal_source_entity_id(Sector dst_sector, uint8_t lane_idx) {
133 // Lane is elem [0, 23]
134 if (lane_idx > 23)
135 return -1;
136 return external_signal_sources[lane_idx * 4 + dst_sector];
137}
138
139bool TBlock::is_external_target_upscaled(uint8_t lane) {
140 if (lane >= 24)
141 return false;
142 return external_target_upscaling[lane];
143}
144
145TBlockBackplane::TBlockBackplane(TBlockBackplaneHAL *hardware) : FunctionBlock("T_BPL", hardware), hardware(hardware) {
146 classifier.class_enum = CLASS_;
147}
148
149utils::status TBlockBackplane::connect(Sector src_sector, Sector dst_sector, uint8_t lane_idx) {
150 if (lane_idx > 7)
151 return "lane_idx is invalid! Maximum is 7!";
152
153 if (src_sector == dst_sector)
154 return "src_sector is equal to dst_sector! This connection is impossible!";
155
156
157 uint8_t switch_setting = src_sector;
158 if (src_sector == Sector::EXT0)
159 switch_setting = dst_sector;
160
161 connections[dst_sector + lane_idx * 9] = switch_setting;
162
163 return status::success();
164}
165
166TBlockBackplane::Sector TBlockBackplane::src_of_signal(Sector dst_sector, uint8_t lane_idx) const {
167 if (lane_idx > 7)
168 return Sector::EXT0;
169
170 uint8_t switch_setting = connections[dst_sector + lane_idx * 9];
171 if (switch_setting == dst_sector)
172 return EXT0;
173
174 return static_cast<Sector>(switch_setting);
175}
176
177void TBlockBackplane::reset(entities::ResetAction action) {
178 Entity::reset(action);
179 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
180 reset_connections();
181 }
182 if (action.has(entities::ResetAction::EVERYTHING))
183 enabled = true;
184}
185
186void TBlockBackplane::reset_connections() {
187 // Resetting probably doesnt make much sense, because there really is no default way of connecting the redacs on the backplane
188 // Because of that and because all connections are always active after a reset the tblock gets a random configuration, to make spotting routing
189 // errors easier
190 std::fill(connections.begin(), connections.end(), random() % 9);
191}
192
193status TBlockBackplane::write_to_hardware() {
194 RETURN_IF_FAILED(Entity::write_to_hardware());
195 if (!hardware->write_muxes(connections))
196 return status("Error writing mux settings to hardware.");
197 if (enabled)
198 hardware->reset_mux_disable();
199 else
200 hardware->set_mux_disable();
201 return status::success();
202}
203
204std::array<uint8_t, TBlockBackplaneHAL::NUM_SWITCHES> TBlockBackplane::get_connections() const { return connections; }
205
206void TBlockBackplane::set_connections(const std::array<uint8_t, TBlockBackplaneHAL::NUM_SWITCHES> &connections_) { connections = connections_; }
207
208bool TBlockBackplane::is_enabled() const { return enabled; }
209
210void TBlockBackplane::set_enabled(bool enabled_) { enabled = enabled_; }
211
212ConfigResult TBlockBackplane::config(const pb_Config &cfg) {
213 if (cfg.which_kind == pb_Config_bpl_switch_config_tag) {
214 auto &switch_config = cfg.kind.bpl_switch_config;
215 return apply_muxes(switch_config.muxes);
216 }
217
218 return ConfigResult::ok(false);
219}
220
221ConfigResult TBlockBackplane::apply_muxes(const pb_Mux (&muxes)[TBlockBackplaneHAL::NUM_SWITCHES]) {
222 for (size_t i = 0; i < TBlockBackplaneHAL::NUM_SWITCHES; i++) {
223 if (!muxes[i].has_state)
224 continue;
225
226 auto mux_value = muxes[i].state;
227 if (mux_value > 7)
228 return ConfigResult::err("TBlockBackplane::apply_muxes: mux value is invalid, must be between [0, 7]!");
229 connections[i] = mux_value;
230 }
231
232 return ConfigResult::ok(true);
233}
234
235void TBlockBackplane::extract(entities::ExtractVisitor &collector) {
236 auto &cfg = collector.create(pb_Config_bpl_switch_config_tag);
237 auto &switch_config = cfg.kind.bpl_switch_config = pb_BPLSwitchConfig_init_default;
238
239 auto &idx = switch_config.muxes_count = 0;
240 for (; idx < connections.size(); ++idx) {
241 switch_config.muxes[idx] = {.has_state = true, .state = connections[idx]};
242 }
243}
void reset_external_signal_infos()
Definition tblock.cpp:97
utils::status status
Definition daq.h:21