7#include <proto/main.pb.h>
9#include <block/iblock.h>
10#include <entity/visitor.h>
11#include <utils/is_number.h>
12#include <utils/logging.h>
14blocks::IBlock::IBlock(IBlockHAL *hardware) : FunctionBlock(
"I", hardware), hardware(hardware), outputs{0} {
15 classifier.class_enum = CLASS_;
18blocks::IBlock::IBlock() : IBlock(new IBlockHALDummy(
bus::NULL_ADDRESS)) {}
20metadata::eui_t blocks::IBlock::get_entity_eui()
const {
22 return hardware->get_entity_eui();
26bool blocks::IBlock::write_to_hardware() {
27 return hardware->write_upscaling(scaling_factors) && hardware->write_outputs(outputs);
30bool blocks::IBlock::init() {
31 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
33 return FunctionBlock::init() && write_to_hardware();
36bool blocks::IBlock::_is_connected(uint8_t input, uint8_t output)
const {
37 return outputs[output] & INPUT_BITMASK(input);
40bool blocks::IBlock::_is_output_connected(uint8_t output)
const {
return outputs[output]; }
42bool blocks::IBlock::is_connected(uint8_t input, uint8_t output)
const {
43 if (output >= NUM_OUTPUTS or input >= NUM_INPUTS)
45 return _is_connected(input, output);
48bool blocks::IBlock::is_anything_connected()
const {
49 for (
auto &output : OUTPUT_IDX_RANGE())
50 if (_is_output_connected(output))
55UnitResult blocks::IBlock::connect(uint8_t input, uint8_t output,
bool exclusive,
bool allow_input_splitting) {
56 if (output >= NUM_OUTPUTS)
57 return UnitResult::err_fmt(
"Error i-block connect output idx out of range: %d", output);
58 if (input >= NUM_INPUTS)
59 return UnitResult::err_fmt(
"Error i-block connect input idx out of range: %d", input);
62 if (!allow_input_splitting) {
63 for (
size_t other_output_idx = 0; other_output_idx < outputs.size(); other_output_idx++) {
64 if (output == other_output_idx)
66 if (is_connected(input, other_output_idx)) {
67 return UnitResult::err_fmt(
"Error i-block connect input is already used: %d", input);
73 outputs[output] = INPUT_BITMASK(input);
75 outputs[output] |= INPUT_BITMASK(input);
76 return UnitResult::ok();
79void blocks::IBlock::reset_outputs() {
83void blocks::IBlock::reset(entities::ResetAction action) {
84 FunctionBlock::reset(action);
86 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
92bool blocks::IBlock::disconnect(uint8_t input, uint8_t output) {
94 if (!is_connected(input, output))
96 outputs[output] &= ~INPUT_BITMASK(input);
100bool blocks::IBlock::disconnect(uint8_t output) {
101 if (output >= NUM_OUTPUTS)
107bool blocks::IBlock::set_upscaling(uint8_t input,
bool upscale) {
108 if (input >= NUM_INPUTS)
110 scaling_factors[input] = upscale;
114void blocks::IBlock::set_upscaling(std::bitset<NUM_INPUTS> scales) { scaling_factors = scales; }
116void blocks::IBlock::reset_upscaling() { scaling_factors.reset(); }
118bool blocks::IBlock::get_upscaling(uint8_t input)
const {
122 return scaling_factors[input];
125const std::array<uint32_t, blocks::IBlock::NUM_OUTPUTS> &blocks::IBlock::get_outputs()
const {
129void blocks::IBlock::set_outputs(
const std::array<uint32_t, NUM_OUTPUTS> &outputs_) {
134void blocks::IBlock::extract(entities::ExtractVisitor &collector) {
135 Entity::extract(collector);
137 if (!collector.include_configuration())
return;
138 auto& item = collector.create(pb_Item_sum_config_tag);
139 auto& sum_config = item.kind.sum_config = pb_SumConfig_init_default;
140 auto& sum_connection_idx = sum_config.connections_count;
141 for (
size_t out_idx = 0; out_idx < NUM_OUTPUTS; ++out_idx) {
142 auto &connection_config = sum_config.connections[sum_connection_idx];
143 connection_config.output = out_idx;
144 for (
size_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
145 if (!_is_connected(in_idx, out_idx))
147 connection_config.inputs[connection_config.inputs_count++] = in_idx;
150 if (connection_config.inputs_count > 0)
151 ++sum_connection_idx;
154 for (uint32_t in_idx = 0; in_idx < NUM_INPUTS; ++in_idx) {
155 sum_config.upscales[sum_config.upscales_count++] = {
156 .lane =
static_cast<uint8_t
>(in_idx),
157 .enabled = get_upscaling(in_idx)
162ConfigResult blocks::IBlock::config(
const pb_Item &item) {
163#ifdef ANABRID_DEBUG_ENTITY_CONFIG
164 Serial.println(__PRETTY_FUNCTION__);
166 if (item.which_kind != pb_Item_sum_config_tag) {
167 return ConfigResult::err(
"expected i block config");
170 auto& sum_coef = item.kind.sum_config;
171 auto res = apply_outputs(sum_coef);
175 auto res2 = apply_upscaling(sum_coef);
179 return ConfigResult::ok(
true);
182ConfigResult blocks::IBlock::apply_outputs(
const pb_SumConfig &item) {
186 reset(entities::ResetAction::CIRCUIT_RESET);
187 for (
size_t elem_idx = 0; elem_idx < item.connections_count; ++elem_idx) {
188 auto& connection = item.connections[elem_idx];
189 for (
size_t input_idx = 0; input_idx < connection.inputs_count; ++input_idx) {
190 auto input = connection.inputs[input_idx];
191 if (!connect(input, connection.output)) {
192 return ConfigResult::err_fmt(
"IBlock: Unable to connect input %d to output %d", input, connection.output);
197 return ConfigResult::ok(
true);
200ConfigResult blocks::IBlock::apply_upscaling(
const pb_SumConfig &item) {
201 for (
auto upscale : item.upscales) {
202 set_upscaling(upscale.lane, upscale.enabled);
204 return ConfigResult::ok(
true);