5#include <proto/main.pb.h>
9#include <block/ublock.h>
10#include <entity/visitor.h>
11#include <utils/logging.h>
13void utils::shift_5_left(uint8_t *buffer,
size_t size) {
14 for (
size_t idx = 0; idx <
size - 1; idx++) {
15 auto next = buffer[idx + 1];
18 buffer[idx] |= (next >> 3) & 0x1F;
20 buffer[
size - 1] <<= 5;
23blocks::UBlock::UBlock(UBlockHAL *hardware)
24 : FunctionBlock(
"U", hardware), hardware(hardware), output_input_map{} {
25 classifier.class_enum = CLASS_;
29metadata::eui_t blocks::UBlock::get_entity_eui()
const {
31 return hardware->get_entity_eui();
35bool blocks::UBlock::_i_sanity_check(
const uint8_t input) {
36 return input < NUM_OF_INPUTS;
39bool blocks::UBlock::_o_sanity_check(
const uint8_t output) {
return output < NUM_OF_OUTPUTS; }
41bool blocks::UBlock::_io_sanity_check(
const uint8_t input,
const uint8_t output) {
42 return _i_sanity_check(input) && _o_sanity_check(output);
45UnitResult blocks::UBlock::connect(
const uint8_t input,
const uint8_t output,
bool force) {
46 if (!_i_sanity_check(input))
47 return UnitResult::err_fmt(
"Error u-block connect input %d", input);
48 if (!_o_sanity_check(output))
49 return UnitResult::err_fmt(
"Error u-block connect output %d", output);
50 output_input_map[output] = input;
51 return UnitResult::ok();
54UnitResult blocks::UBlock::connect_alternative(Transmission_Mode signal_mode,
const uint8_t output,
bool force,
bool use_a_side) {
55 if (!_o_sanity_check(output))
56 return UnitResult::err_fmt(
"Error u-block connect output %d", output);
59 if (signal_mode == Transmission_Mode::ANALOG_INPUT)
60 return UnitResult::err(
"Do not consider Transmission_Mode::ANALOG_INPUT a valid mode for connect alternative");
63 if (!force and _is_output_connected(output))
64 return UnitResult::err(
"Check for other connections on the same output, unless we don't care if we overwrite them");
68 if (a_side_mode != signal_mode && use_a_side) {
72 return UnitResult::err(
"alternative signal, you have to use force or set the correct signal mode");
73 change_a_side_transmission_mode(signal_mode);
76 if (b_side_mode != signal_mode && !use_a_side) {
78 if (is_input_connected(14) || is_input_connected(15))
79 return UnitResult::err(
"no 14 or 15?");
80 change_b_side_transmission_mode(signal_mode);
89 else if (output == 15)
91 else if (output == 30)
102 return connect(input, output);
105void blocks::UBlock::_disconnect(
const uint8_t output) { output_input_map[output] = -1; }
107bool blocks::UBlock::disconnect(
const uint8_t input,
const uint8_t output) {
108 if (!_io_sanity_check(input, output))
111 if (_is_connected(input, output)) {
119bool blocks::UBlock::disconnect(
const uint8_t output) {
120 if (!_o_sanity_check(output))
126bool blocks::UBlock::_is_connected(
const uint8_t input,
const uint8_t output)
const {
127 return output_input_map[output] == input;
130bool blocks::UBlock::is_connected(
const uint8_t input,
const uint8_t output)
const {
131 if (!_io_sanity_check(input, output))
134 return _is_connected(input, output);
137bool blocks::UBlock::_is_output_connected(
const uint8_t output)
const {
138 return output_input_map[output] >= 0;
141bool blocks::UBlock::is_output_connected(
const uint8_t output)
const {
142 if (!_o_sanity_check(output))
145 return _is_output_connected(output);
148bool blocks::UBlock::_is_input_connected(
const uint8_t input)
const {
149 for (
const auto &output : output_input_map)
155bool blocks::UBlock::is_input_connected(
const uint8_t input)
const {
156 if (!_i_sanity_check(input))
158 return _is_input_connected(input);
161bool blocks::UBlock::is_anything_connected()
const {
162 for (
auto output : OUTPUT_IDX_RANGE())
163 if (_is_output_connected(output))
168void blocks::UBlock::change_a_side_transmission_mode(
const Transmission_Mode
mode) {
172void blocks::UBlock::change_b_side_transmission_mode(
const Transmission_Mode
mode) {
176void blocks::UBlock::change_all_transmission_modes(
const Transmission_Mode
mode) {
177 change_a_side_transmission_mode(
mode);
178 change_b_side_transmission_mode(
mode);
182blocks::UBlock::change_all_transmission_modes(
const std::pair<Transmission_Mode, Transmission_Mode> modes) {
183 change_a_side_transmission_mode(modes.first);
184 change_b_side_transmission_mode(modes.second);
187std::pair<blocks::UBlock::Transmission_Mode, blocks::UBlock::Transmission_Mode>
188blocks::UBlock::get_all_transmission_modes()
const {
189 return std::make_pair(a_side_mode, b_side_mode);
192blocks::UBlock::Reference_Magnitude blocks::UBlock::get_reference_magnitude() {
193 return ref_magnitude;
196void blocks::UBlock::change_reference_magnitude(blocks::UBlock::Reference_Magnitude ref) {
200UnitResult blocks::UBlock::write_to_hardware() {
201 if (!hardware->write_outputs(output_input_map))
202 return UnitResult::err(
"Writing u block outputs failed");
204 if (!hardware->write_transmission_modes_and_ref({a_side_mode, b_side_mode}, ref_magnitude))
205 return UnitResult::err(
"Writing u block transmission modes failed");
207 return UnitResult::ok();
210void blocks::UBlock::reset_connections() {
211 std::fill(begin(output_input_map), end(output_input_map), -1);
214void blocks::UBlock::reset(entities::ResetAction action) {
215 FunctionBlock::reset(action);
217 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
218 change_all_transmission_modes(blocks::UBlock::Transmission_Mode::ANALOG_INPUT);
220 reset_reference_magnitude();
224ConfigResult blocks::UBlock::config(
const pb_Item &item) {
225#ifdef ANABRID_DEBUG_ENTITY_CONFIG
226 Serial.println(__PRETTY_FUNCTION__);
228 if (item.which_kind != pb_Item_select_config_tag)
229 return ConfigResult::err(
"expected select block config");
231 auto& select_config = item.kind.select_config;
233 auto res = apply_outputs(select_config);
237 TRY(apply_constants(select_config));
238 return ConfigResult::ok(
true);
241ConfigResult blocks::UBlock::apply_outputs(
const pb_SelectConfig &item) {
245 for (
size_t idx = 0; idx < item.connections_count; ++idx) {
246 auto& connection = item.connections[idx];
247 if (!connect(connection.input, connection.output))
248 return ConfigResult::err(
"UBlock: Cannot connect input at idx");
250 return ConfigResult::ok(
true);
253ConfigResult blocks::UBlock::apply_constants(
const pb_SelectConfig &item) {
254 if (item.constant == pb_SelectConfig_ConstantConfig_GROUND) {
257 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::ANALOG_INPUT);
258 reset_reference_magnitude();
259 return ConfigResult::ok(
true);
260 }
else if (item.constant == pb_SelectConfig_ConstantConfig_POS_REF) {
261 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::POS_REF);
263 else if (item.constant == pb_SelectConfig_ConstantConfig_NEG_REF) {
264 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::NEG_REF);
267 return ConfigResult::err_fmt(
"UBlock::config_self_from_pb: Ground, pos_ref or neg_ref");
269 if (item.magnitude == pb_SelectConfig_Magnitude_ONE_TENTH)
270 change_reference_magnitude(blocks::UBlock::Reference_Magnitude::ONE_TENTH);
271 else if (item.magnitude == pb_SelectConfig_Magnitude_ONE) {
272 change_reference_magnitude(blocks::UBlock::Reference_Magnitude::ONE);
275 return ConfigResult::err_fmt(
"UBlock::config_self_from_pb: Pass +-0.1 or +-1.");
278 return ConfigResult::ok(
true);
281void blocks::UBlock::extract(entities::ExtractVisitor &collector) {
282 Entity::extract(collector);
284 if (!collector.include_configuration())
return;
285 auto& item = collector.create(pb_Item_select_config_tag);
288 auto& select_config = item.kind.select_config = pb_SelectConfig_init_default;
289 for (uint8_t idx = 0; idx < NUM_OF_OUTPUTS; ++idx) {
290 auto input = output_input_map[idx];
294 select_config.connections[select_config.connections_count++] = {
295 .input=
static_cast<uint8_t
>(output_input_map[idx]),
303 switch (b_side_mode) {
304 case Transmission_Mode::POS_REF:
305 select_config.constant = pb_SelectConfig_ConstantConfig_POS_REF;
307 case Transmission_Mode::NEG_REF:
308 select_config.constant = pb_SelectConfig_ConstantConfig_NEG_REF;
311 select_config.constant = pb_SelectConfig_ConstantConfig_GROUND;
315 if (ref_magnitude == Reference_Magnitude::ONE_TENTH) {
316 select_config.magnitude = pb_SelectConfig_Magnitude_ONE_TENTH;
318 select_config.magnitude = pb_SelectConfig_Magnitude_ONE;
322void blocks::UBlock::reset_reference_magnitude() { ref_magnitude = Reference_Magnitude::ONE; }
324bool blocks::UBlockHAL_Dummy::write_outputs(std::array<int8_t, 32> outputs) {
return true; }
326bool blocks::UBlockHAL_Dummy::write_transmission_modes_and_ref(
327 std::pair<Transmission_Mode, Transmission_Mode> modes, blocks::UBlockHAL::Reference_Magnitude ref) {
331void blocks::UBlockHAL_Dummy::reset_transmission_modes_and_ref() {}