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
26utils::status blocks::IBlock::write_to_hardware() {
27 return utils::status(hardware->write_upscaling(scaling_factors) and hardware->write_outputs(outputs));
28}
29
30bool blocks::IBlock::init() {
31 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
32 if (!FunctionBlock::init()) {
33 return false;
34 };
35 // I-Block matrix is not reset on power-cycle, apparently.
36 if (!write_to_hardware())
37 return false;
38 return true;
39}
40
41bool blocks::IBlock::_is_connected(uint8_t input, uint8_t output) const {
42 return outputs[output] & INPUT_BITMASK(input);
43}
44
45bool blocks::IBlock::_is_output_connected(uint8_t output) const { return outputs[output]; }
46
47bool blocks::IBlock::is_connected(uint8_t input, uint8_t output) const {
48 if (output >= NUM_OUTPUTS or input >= NUM_INPUTS)
49 return false;
50 return _is_connected(input, output);
51}
52
53bool blocks::IBlock::is_anything_connected() const {
54 for (auto &output : OUTPUT_IDX_RANGE())
55 if (_is_output_connected(output))
56 return true;
57 return false;
58}
59
60bool blocks::IBlock::connect(uint8_t input, uint8_t output, bool exclusive,
61 bool allow_input_splitting) {
62 if (output >= NUM_OUTPUTS or input >= NUM_INPUTS)
63 return false;
64
65 // Usually, we don't want to connect one input to multiple outputs, so check for other connections
66 if (!allow_input_splitting) {
67 for (size_t other_output_idx = 0; other_output_idx < outputs.size(); other_output_idx++) {
68 if (output == other_output_idx)
69 continue;
70 if (is_connected(input, other_output_idx)) {
71 return false;
72 }
73 }
74 }
75
76 if (exclusive)
77 outputs[output] = INPUT_BITMASK(input);
78 else
79 outputs[output] |= INPUT_BITMASK(input);
80 return true;
81}
82
83void blocks::IBlock::reset_outputs() {
84 for (auto &output : outputs) {
85 output = 0;
86 }
87}
88
89void blocks::IBlock::reset(entities::ResetAction action) {
90 FunctionBlock::reset(action);
91
92 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
93 reset_outputs();
94 reset_upscaling();
95 }
96}
97
98
99
100
101
102bool blocks::IBlock::disconnect(uint8_t input, uint8_t output) {
103 // Fail if input was not connected
104 if (!is_connected(input, output))
105 return false;
106 outputs[output] &= ~INPUT_BITMASK(input);
107 return true;
108}
109
110bool blocks::IBlock::disconnect(uint8_t output) {
111 if (output >= NUM_OUTPUTS)
112 return false;
113 outputs[output] = 0;
114 return true;
115}
116
117bool blocks::IBlock::set_upscaling(uint8_t input, bool upscale) {
118 if (input >= NUM_INPUTS)
119 return false;
120 scaling_factors[input] = upscale;
121 return true;
122}
123
124void blocks::IBlock::set_upscaling(std::bitset<NUM_INPUTS> scales) { scaling_factors = scales; }
125
126void blocks::IBlock::reset_upscaling() { scaling_factors.reset(); }
127
128bool blocks::IBlock::get_upscaling(uint8_t input) const {
129 if (input > 32)
130 return false;
131 else
132 return scaling_factors[input];
133}
134
135const std::array<uint32_t, blocks::IBlock::NUM_OUTPUTS> &blocks::IBlock::get_outputs() const {
136 return outputs;
137}
138
139void blocks::IBlock::set_outputs(const std::array<uint32_t, NUM_OUTPUTS> &outputs_) {
140 outputs = outputs_;
141}
142
143
144void blocks::IBlock::extract(entities::ExtractVisitor &collector) {
145 Entity::extract(collector);
146 auto& cfg = collector.create(pb_Config_sum_config_tag);
147 auto& sum_config = cfg.kind.sum_config = pb_SumConfig_init_default;
148 auto& sum_connection_idx = sum_config.connections_count;
149 for (size_t out_idx = 0; out_idx < NUM_OUTPUTS; ++out_idx) {
150 auto &connection_config = sum_config.connections[sum_connection_idx];
151 connection_config.output = out_idx;
152 for (size_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
153 if (!_is_connected(in_idx, out_idx))
154 continue;
155 connection_config.inputs[connection_config.inputs_count++] = in_idx;
156 }
157
158 if (connection_config.inputs_count > 0)
159 ++sum_connection_idx;
160 }
161
162 for (uint32_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
163 sum_config.upscales[sum_config.upscales_count++] = {
164 .lane = in_idx,
165 .enabled = get_upscaling(in_idx)
166 };
167 }
168}
169
170ConfigResult blocks::IBlock::config(const pb_Config &cfg) {
171#ifdef ANABRID_DEBUG_ENTITY_CONFIG
172 Serial.println(__PRETTY_FUNCTION__);
173#endif
174 if (cfg.which_kind != pb_Config_sum_config_tag) {
175 return ConfigResult::err("expected i block config");
176 }
177
178 auto& sum_coef = cfg.kind.sum_config;
179 auto res = apply_outputs(sum_coef);
180 if (res.is_err())
181 return res;
182
183 auto res2 = apply_upscaling(sum_coef);
184 if (res2.is_err())
185 return res2;
186
187 return ConfigResult::ok(true);
188}
189
190ConfigResult blocks::IBlock::apply_outputs(const pb_SumConfig &cfg) {
191 // Handle a mapping of output to list of inputs
192 // This only overrides outputs that are specifically mentioned
193
194 reset(entities::ResetAction::CIRCUIT_RESET);
195 for (size_t elem_idx = 0; elem_idx < cfg.connections_count; ++elem_idx) {
196 auto& connection = cfg.connections[elem_idx];
197 for (size_t input_idx = 0; input_idx < connection.inputs_count; ++input_idx) {
198 auto input = connection.inputs[input_idx];
199 if (!connect(input, connection.output)) {
200 return ConfigResult::err_fmt("IBlock: Unable to connect input %d to output %d", input, connection.output);
201 }
202 }
203 }
204
205 return ConfigResult::ok(true);
206}
207
208ConfigResult blocks::IBlock::apply_upscaling(const pb_SumConfig &cfg) {
209 for (auto upscale : cfg.upscales) {
210 set_upscaling(upscale.lane, upscale.enabled);
211 }
212 return ConfigResult::ok(true);
213}
uint32_t
Definition flasher.cpp:195
Definition bus.h:21