REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
iblock.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
5#include "pb_encode.h"
6
7#include <proto/main.pb.h>
8
9#include <block/iblock.h>
10#include <entity/visitor.h>
11#include <utils/is_number.h>
12#include <utils/logging.h>
13
14blocks::IBlock::IBlock(IBlockHAL *hardware) : FunctionBlock("I", hardware), hardware(hardware), outputs{0} {
15 classifier.class_enum = CLASS_;
16}
17
18blocks::IBlock::IBlock() : IBlock(new IBlockHALDummy(bus::NULL_ADDRESS)) {}
19
20metadata::eui_t blocks::IBlock::get_entity_eui() const {
21 if (hardware)
22 return hardware->get_entity_eui();
23 return {};
24}
25
26UnitResult blocks::IBlock::write_to_hardware() {
27 if (!hardware->write_upscaling(scaling_factors))
28 return UnitResult::err("Writing i block scaling factors failed!");
29
30 if (!hardware->write_outputs(outputs))
31 return UnitResult::err("Writing i block outputs failed!");
32
33 return UnitResult::ok();
34}
35
36UnitResult blocks::IBlock::init() {
37 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
38 TRY(FunctionBlock::init());
39 // I-Block matrix is not reset on power-cycle, apparently.
40 return write_to_hardware();
41}
42
43bool blocks::IBlock::_is_connected(uint8_t input, uint8_t output) const {
44 return outputs[output] & INPUT_BITMASK(input);
45}
46
47bool blocks::IBlock::_is_output_connected(uint8_t output) const { return outputs[output]; }
48
49bool blocks::IBlock::is_connected(uint8_t input, uint8_t output) const {
50 if (output >= NUM_OUTPUTS or input >= NUM_INPUTS)
51 return false;
52 return _is_connected(input, output);
53}
54
55bool blocks::IBlock::is_anything_connected() const {
56 for (auto &output : OUTPUT_IDX_RANGE())
57 if (_is_output_connected(output))
58 return true;
59 return false;
60}
61
62UnitResult blocks::IBlock::connect(uint8_t input, uint8_t output, bool exclusive, bool allow_input_splitting) {
63 if (output >= NUM_OUTPUTS)
64 return UnitResult::err_fmt("Error i-block connect output idx out of range: %d", output);
65 if (input >= NUM_INPUTS)
66 return UnitResult::err_fmt("Error i-block connect input idx out of range: %d", input);
67
68 // Usually, we don't want to connect one input to multiple outputs, so check for other connections
69 if (!allow_input_splitting) {
70 for (size_t other_output_idx = 0; other_output_idx < outputs.size(); other_output_idx++) {
71 if (output == other_output_idx)
72 continue;
73 if (is_connected(input, other_output_idx)) {
74 return UnitResult::err_fmt("Error i-block connect input is already used: %d", input);
75 }
76 }
77 }
78
79 if (exclusive)
80 outputs[output] = INPUT_BITMASK(input);
81 else
82 outputs[output] |= INPUT_BITMASK(input);
83 return UnitResult::ok();
84}
85
86void blocks::IBlock::reset_outputs() {
87 for (auto &output : outputs) {
88 output = 0;
89 }
90}
91
92void blocks::IBlock::reset(entities::ResetAction action) {
93 FunctionBlock::reset(action);
94
95 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
96 reset_outputs();
97 reset_upscaling();
98 }
99}
100
101
102
103
104
105bool blocks::IBlock::disconnect(uint8_t input, uint8_t output) {
106 // Fail if input was not connected
107 if (!is_connected(input, output))
108 return false;
109 outputs[output] &= ~INPUT_BITMASK(input);
110 return true;
111}
112
113bool blocks::IBlock::disconnect(uint8_t output) {
114 if (output >= NUM_OUTPUTS)
115 return false;
116 outputs[output] = 0;
117 return true;
118}
119
120bool blocks::IBlock::set_upscaling(uint8_t input, bool upscale) {
121 if (input >= NUM_INPUTS)
122 return false;
123 scaling_factors[input] = upscale;
124 return true;
125}
126
127void blocks::IBlock::set_upscaling(std::bitset<NUM_INPUTS> scales) { scaling_factors = scales; }
128
129void blocks::IBlock::reset_upscaling() { scaling_factors.reset(); }
130
131bool blocks::IBlock::get_upscaling(uint8_t input) const {
132 if (input > 32)
133 return false;
134 else
135 return scaling_factors[input];
136}
137
138const std::array<uint32_t, blocks::IBlock::NUM_OUTPUTS> &blocks::IBlock::get_outputs() const {
139 return outputs;
140}
141
142void blocks::IBlock::set_outputs(const std::array<uint32_t, NUM_OUTPUTS> &outputs_) {
143 outputs = outputs_;
144}
145
146
147void blocks::IBlock::extract(entities::ExtractVisitor &collector) {
148 Entity::extract(collector);
149
150 if (!collector.include_configuration()) return;
151 auto& item = collector.create(pb_Item_sum_config_tag);
152 auto& sum_config = item.kind.sum_config = pb_SumConfig_init_default;
153 auto& sum_connection_idx = sum_config.connections_count;
154 for (size_t out_idx = 0; out_idx < NUM_OUTPUTS; ++out_idx) {
155 auto &connection_config = sum_config.connections[sum_connection_idx];
156 connection_config.output = out_idx;
157 for (size_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
158 if (!_is_connected(in_idx, out_idx))
159 continue;
160 connection_config.inputs[connection_config.inputs_count++] = in_idx;
161 }
162
163 if (connection_config.inputs_count > 0)
164 ++sum_connection_idx;
165 }
166
167 for (uint32_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
168 sum_config.upscales[sum_config.upscales_count++] = {
169 .lane = static_cast<uint8_t>(in_idx),
170 .enabled = get_upscaling(in_idx)
171 };
172 }
173}
174
175ConfigResult blocks::IBlock::config(const pb_Item &item) {
176#ifdef ANABRID_DEBUG_ENTITY_CONFIG
177 Serial.println(__PRETTY_FUNCTION__);
178#endif
179 if (item.which_kind != pb_Item_sum_config_tag) {
180 return ConfigResult::err("expected i block config");
181 }
182
183 auto& sum_coef = item.kind.sum_config;
184 auto res = apply_outputs(sum_coef);
185 if (res.is_err())
186 return res;
187
188 auto res2 = apply_upscaling(sum_coef);
189 if (res2.is_err())
190 return res2;
191
192 return ConfigResult::ok(true);
193}
194
195ConfigResult blocks::IBlock::apply_outputs(const pb_SumConfig &item) {
196 // Handle a mapping of output to list of inputs
197 // This only overrides outputs that are specifically mentioned
198
199 reset(entities::ResetAction::CIRCUIT_RESET);
200 for (size_t elem_idx = 0; elem_idx < item.connections_count; ++elem_idx) {
201 auto& connection = item.connections[elem_idx];
202 for (size_t input_idx = 0; input_idx < connection.inputs_count; ++input_idx) {
203 auto input = connection.inputs[input_idx];
204 if (!connect(input, connection.output)) {
205 return ConfigResult::err_fmt("IBlock: Unable to connect input %d to output %d", input, connection.output);
206 }
207 }
208 }
209
210 return ConfigResult::ok(true);
211}
212
213ConfigResult blocks::IBlock::apply_upscaling(const pb_SumConfig &item) {
214 for (auto upscale : item.upscales) {
215 set_upscaling(upscale.lane, upscale.enabled);
216 }
217 return ConfigResult::ok(true);
218}
uint32_t
Definition flasher.cpp:195
Definition bus.h:21