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