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_Item &item) {
11 if (item.which_kind == pb_Item_switch_config_tag) {
12 auto &switch_config = item.kind.switch_config;
13 return apply_muxes(switch_config.muxes);
14 }
15
16 // unhandled
17 return ConfigResult::ok(false);
18}
19
20ConfigResult TBlock::apply_muxes(const pb_Mux (&muxes)[TBlockHAL::NUM_SWITCHES]) {
21 size_t idx = -1;
22 for (auto &mux : muxes) {
23 idx++;
24 if (!mux.has_state)
25 // Mux is not required for this configuration, keep it in previous configuration.
26 // The rest of the configuration must ensure that this is not a problem.
27 continue;
28
29 auto mux_value = mux.state;
30 if (mux_value < 0 || 4 <= mux_value)
31 return ConfigResult::err("TBlock: Mux must be interval [0, 3]");
32 connections[idx] = mux_value;
33 }
34
35 return ConfigResult::ok(true);
36}
37
38std::array<uint8_t, TBlockHAL::NUM_SWITCHES> TBlock::get_connections() const { return connections; }
39
40void TBlock::set_connections(const std::array<uint8_t, TBlockHAL::NUM_SWITCHES> &connections) { this->connections = connections; }
41
42void TBlock::extract(entities::ExtractVisitor &collector) {
43
44 if (!collector.include_configuration()) return;
45 auto &item = collector.create(pb_Item_switch_config_tag);
46 auto &switch_config = item.kind.switch_config = pb_SwitchConfig_init_default;
47
48 auto &idx = switch_config.muxes_count = 0;
49 for (; idx < connections.size(); ++idx) {
50 switch_config.muxes[idx] = {
51 .has_state = true,
52 .state = connections[idx],
53 };
54 }
55}
56
57inline uint32_t mux_idx(TBlock::Sector dst_sector, uint8_t lane_idx) {
58 return lane_idx * 4 + dst_sector;
59}
60
61UnitResult TBlock::connect(Sector src_sector, Sector dst_sector, uint8_t lane_idx) {
62 if (lane_idx > 23)
63 return UnitResult::err("Invalid lane. Remember that TBlock lanes are allways counted from 0 to 23");
64
65 connections[mux_idx(dst_sector, lane_idx)] = src_sector;
66 return UnitResult::ok();
67}
68
69TBlock::Sector TBlock::src_of_signal(Sector dst_sector, uint8_t lane_idx) const {
70 if (lane_idx > 23)
71 return Sector::BPL;
72
73 return static_cast<Sector>(connections[mux_idx(dst_sector, lane_idx)]);
74}
75
76void TBlock::reset(entities::ResetAction action) {
77 Entity::reset(action);
78 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
79 reset_connections();
80 }
81 if (action.has(entities::ResetAction::EVERYTHING))
82 enabled = true;
83}
84
85void TBlock::reset_connections() {
86 // Note that the T-block always has connections, unless it is completely disabled (powered-off).
87 // The least surprising default connection is to have signals stay in their originating cluster.
88 connections = {Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
89 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
90 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
91 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
92 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
93 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
94 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
95 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2,
96 Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0,
97 Sector::CL1, Sector::CL2, Sector::BPL, Sector::CL0, Sector::CL1, Sector::CL2};
98}
99
100UnitResult TBlock::write_to_hardware() {
101 TRY(Entity::write_to_hardware());
102 if (!hardware->write_muxes(connections))
103 return UnitResult::err("Error writing mux settings to hardware.");
104 if (enabled)
105 hardware->reset_mux_disable();
106 else
107 hardware->set_mux_disable();
108 return UnitResult::ok();
109}
110
111bool TBlock::is_enabled() const { return enabled; }
112
113void TBlock::set_enabled(bool enabled_) { enabled = enabled_; }
114
115TBlockBackplane::TBlockBackplane(TBlockBackplaneHAL *hardware) : FunctionBlock("T_BPL", hardware), hardware(hardware) {
116 classifier.class_enum = CLASS_;
117}
118
119UnitResult TBlockBackplane::connect(Sector src_sector, Sector dst_sector, uint8_t lane_idx) {
120 if (lane_idx > 7)
121 return UnitResult::err("lane_idx is invalid! Maximum is 7!");
122
123 if (src_sector == dst_sector)
124 return UnitResult::err("src_sector is equal to dst_sector! This connection is impossible!");
125
126
127 uint8_t switch_setting = src_sector;
128 if (src_sector == Sector::EXT0)
129 switch_setting = dst_sector;
130
131 connections[dst_sector + lane_idx * 9] = switch_setting;
132
133 return UnitResult::ok();
134}
135
136TBlockBackplane::Sector TBlockBackplane::src_of_signal(Sector dst_sector, uint8_t lane_idx) const {
137 if (lane_idx > 7)
138 return Sector::EXT0;
139
140 uint8_t switch_setting = connections[dst_sector + lane_idx * 9];
141 if (switch_setting == dst_sector)
142 return EXT0;
143
144 return static_cast<Sector>(switch_setting);
145}
146
147void TBlockBackplane::reset(entities::ResetAction action) {
148 Entity::reset(action);
149 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
150 reset_connections();
151 }
152 if (action.has(entities::ResetAction::EVERYTHING))
153 enabled = true;
154}
155
156void TBlockBackplane::reset_connections() {
157 // Resetting probably doesnt make much sense, because there really is no default way of connecting the redacs on the backplane
158 // Because of that and because all connections are always active after a reset the tblock gets a random configuration, to make spotting routing
159 // errors easier
160 std::fill(connections.begin(), connections.end(), random() % 9);
161}
162
163UnitResult TBlockBackplane::write_to_hardware() {
164 TRY(Entity::write_to_hardware());
165 if (!hardware->write_muxes(connections))
166 return UnitResult::err("Error writing mux settings to hardware.");
167 if (enabled)
168 hardware->reset_mux_disable();
169 else
170 hardware->set_mux_disable();
171 return UnitResult::ok();
172}
173
174std::array<uint8_t, TBlockBackplaneHAL::NUM_SWITCHES> TBlockBackplane::get_connections() const { return connections; }
175
176void TBlockBackplane::set_connections(const std::array<uint8_t, TBlockBackplaneHAL::NUM_SWITCHES> &connections_) { connections = connections_; }
177
178bool TBlockBackplane::is_enabled() const { return enabled; }
179
180void TBlockBackplane::set_enabled(bool enabled_) { enabled = enabled_; }
181
182ConfigResult TBlockBackplane::config(const pb_Item &item) {
183 if (item.which_kind == pb_Item_bpl_switch_config_tag) {
184 auto &switch_config = item.kind.bpl_switch_config;
185 return apply_muxes(switch_config.muxes);
186 }
187
188 return ConfigResult::ok(false);
189}
190
191ConfigResult TBlockBackplane::apply_muxes(const pb_Mux (&muxes)[TBlockBackplaneHAL::NUM_SWITCHES]) {
192 for (size_t i = 0; i < TBlockBackplaneHAL::NUM_SWITCHES; i++) {
193 if (!muxes[i].has_state)
194 continue;
195
196 auto mux_value = muxes[i].state;
197 if (mux_value > 7)
198 return ConfigResult::err("TBlockBackplane::apply_muxes: mux value is invalid, must be between [0, 7]!");
199 connections[i] = mux_value;
200 }
201
202 return ConfigResult::ok(true);
203}
204
205void TBlockBackplane::extract(entities::ExtractVisitor &collector) {
206 if (!collector.include_configuration()) return;
207 auto &item = collector.create(pb_Item_bpl_switch_config_tag);
208 auto &switch_config = item.kind.bpl_switch_config = pb_BPLSwitchConfig_init_default;
209
210 auto &idx = switch_config.muxes_count = 0;
211 for (; idx < connections.size(); ++idx) {
212 switch_config.muxes[idx] = {.has_state = true, .state = connections[idx]};
213 }
214}
uint32_t mux_idx(TBlock::Sector dst_sector, uint8_t lane_idx)
Definition tblock.cpp:57
uint32_t
Definition flasher.cpp:195