7#include <block/ublock.h>
8#include <utils/logging.h>
10FLASHMEM
void utils::shift_5_left(uint8_t *buffer,
size_t size) {
11 for (
size_t idx = 0; idx <
size - 1; idx++) {
12 auto next = buffer[idx + 1];
15 buffer[idx] |= (next >> 3) & 0x1F;
17 buffer[
size - 1] <<= 5;
20FLASHMEM blocks::UBlock::UBlock(UBlockHAL *hardware)
21 : FunctionBlock(
"U", hardware), hardware(hardware), output_input_map{} {
22 classifier.class_enum = CLASS_;
26FLASHMEM metadata::eui_t blocks::UBlock::get_entity_eui()
const {
28 return hardware->get_entity_eui();
32FLASHMEM
bool blocks::UBlock::_i_sanity_check(
const uint8_t input) {
return input < NUM_OF_INPUTS; }
34FLASHMEM
bool blocks::UBlock::_o_sanity_check(
const uint8_t output) {
return output < NUM_OF_OUTPUTS; }
36FLASHMEM
bool blocks::UBlock::_io_sanity_check(
const uint8_t input,
const uint8_t output) {
37 return _i_sanity_check(input) && _o_sanity_check(output);
40FLASHMEM
void blocks::UBlock::_connect(
const uint8_t input,
const uint8_t output) {
41 output_input_map[output] = input;
44FLASHMEM
bool blocks::UBlock::connect(
const uint8_t input,
const uint8_t output,
bool force) {
45 if (!_io_sanity_check(input, output))
49 if (!force and _is_output_connected(output))
54 if (a_side_mode != Transmission_Mode::ANALOG_INPUT &&
55 ((output < 16 && input != 15) || (output >= 16 && input != 14))) {
57 if (is_input_connected(input))
59 change_a_side_transmission_mode(Transmission_Mode::ANALOG_INPUT);
62 if (b_side_mode != Transmission_Mode::ANALOG_INPUT &&
63 ((output < 16 && input == 15) || (output >= 16 && input == 14))) {
65 if (is_input_connected(input))
67 change_b_side_transmission_mode(Transmission_Mode::ANALOG_INPUT);
70 _connect(input, output);
74FLASHMEM
bool blocks::UBlock::connect_alternative(Transmission_Mode signal_mode,
const uint8_t output,
75 bool force,
bool use_a_side) {
76 if (!_o_sanity_check(output))
80 if (signal_mode == Transmission_Mode::ANALOG_INPUT)
84 if ((signal_mode == Transmission_Mode::POS_REF or signal_mode == Transmission_Mode::NEG_REF) and
85 ref_magnitude != Reference_Magnitude::ONE and !force)
89 if (!force and _is_output_connected(output))
94 if (a_side_mode != signal_mode && use_a_side) {
99 change_a_side_transmission_mode(signal_mode);
102 if (b_side_mode != signal_mode && !use_a_side) {
104 if (is_input_connected(14) || is_input_connected(15))
106 change_b_side_transmission_mode(signal_mode);
115 else if (output == 15)
117 else if (output == 30)
128 _connect(input, output);
132FLASHMEM
void blocks::UBlock::_disconnect(
const uint8_t output) { output_input_map[output] = -1; }
134FLASHMEM
bool blocks::UBlock::disconnect(
const uint8_t input,
const uint8_t output) {
135 if (!_io_sanity_check(input, output))
138 if (_is_connected(input, output)) {
146FLASHMEM
bool blocks::UBlock::disconnect(
const uint8_t output) {
147 if (!_o_sanity_check(output))
153FLASHMEM
bool blocks::UBlock::_is_connected(
const uint8_t input,
const uint8_t output)
const {
154 return output_input_map[output] == input;
157FLASHMEM
bool blocks::UBlock::is_connected(
const uint8_t input,
const uint8_t output)
const {
158 if (!_io_sanity_check(input, output))
161 return _is_connected(input, output);
164FLASHMEM
bool blocks::UBlock::_is_output_connected(
const uint8_t output)
const {
165 return output_input_map[output] >= 0;
168FLASHMEM
bool blocks::UBlock::is_output_connected(
const uint8_t output)
const {
169 if (!_o_sanity_check(output))
172 return _is_output_connected(output);
175FLASHMEM
bool blocks::UBlock::_is_input_connected(
const uint8_t input)
const {
176 for (
const auto &output : output_input_map)
182FLASHMEM
bool blocks::UBlock::is_input_connected(
const uint8_t input)
const {
183 if (!_i_sanity_check(input))
185 return _is_input_connected(input);
188FLASHMEM
bool blocks::UBlock::is_anything_connected()
const {
189 for (
auto output : OUTPUT_IDX_RANGE())
190 if (_is_output_connected(output))
195FLASHMEM
void blocks::UBlock::change_a_side_transmission_mode(
const Transmission_Mode
mode) {
199FLASHMEM
void blocks::UBlock::change_b_side_transmission_mode(
const Transmission_Mode
mode) {
203FLASHMEM
void blocks::UBlock::change_all_transmission_modes(
const Transmission_Mode
mode) {
204 change_a_side_transmission_mode(
mode);
205 change_b_side_transmission_mode(
mode);
209blocks::UBlock::change_all_transmission_modes(
const std::pair<Transmission_Mode, Transmission_Mode> modes) {
210 change_a_side_transmission_mode(modes.first);
211 change_b_side_transmission_mode(modes.second);
214FLASHMEM std::pair<blocks::UBlock::Transmission_Mode, blocks::UBlock::Transmission_Mode>
215blocks::UBlock::get_all_transmission_modes()
const {
216 return std::make_pair(a_side_mode, b_side_mode);
219FLASHMEM blocks::UBlock::Reference_Magnitude blocks::UBlock::get_reference_magnitude() {
220 return ref_magnitude;
223FLASHMEM
void blocks::UBlock::change_reference_magnitude(blocks::UBlock::Reference_Magnitude ref) {
227FLASHMEM utils::status blocks::UBlock::write_to_hardware() {
228 if (!hardware->write_outputs(output_input_map) or
229 !hardware->write_transmission_modes_and_ref({a_side_mode, b_side_mode}, ref_magnitude)) {
230 LOG(ANABRID_PEDANTIC, __PRETTY_FUNCTION__);
231 return utils::status::failure();
233 return utils::status::success();
236FLASHMEM
void blocks::UBlock::reset_connections() {
237 std::fill(begin(output_input_map), end(output_input_map), -1);
240FLASHMEM
void blocks::UBlock::reset(entities::ResetAction action) {
241 FunctionBlock::reset(action);
243 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
244 change_all_transmission_modes(blocks::UBlock::Transmission_Mode::ANALOG_INPUT);
246 reset_reference_magnitude();
251utils::status blocks::UBlock::config_self_from_json(JsonObjectConst cfg) {
252#ifdef ANABRID_DEBUG_ENTITY_CONFIG
253 Serial.println(__PRETTY_FUNCTION__);
255 for (
auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
256 if (cfgItr->key() ==
"outputs") {
257 auto ret = _config_outputs_from_json(cfgItr->value());
260 }
else if (cfgItr->key() ==
"constant") {
261 auto ret = _config_constants_from_json(cfgItr->value());
265 return utils::status::failure();
267 return utils::status(
"UBlock: Unknown configuration key");
270 return utils::status::success();
274utils::status blocks::UBlock::_config_outputs_from_json(
const JsonVariantConst &cfg) {
277 if (cfg.is<JsonArrayConst>()) {
278 auto outputs = cfg.as<JsonArrayConst>();
279 if (outputs.size() != NUM_OF_OUTPUTS)
280 return utils::status(
"Nblock: Wrong number of configuration elements. Given %d, expected %d",
281 outputs.size(), NUM_OF_OUTPUTS);
284 for (JsonVariantConst input : outputs) {
285 if (input.isNull()) {
288 }
else if (!input.is<uint8_t>()) {
289 return utils::status(
"UBlock: Input is not an integer");
291 if (!connect(input.as<uint8_t>(), idx++))
292 return utils::status(
"UBlock: Cannot connect input at idx");
294 return utils::status::success();
299 else if (cfg.is<JsonObjectConst>()) {
300 for (JsonPairConst keyval : cfg.as<JsonObjectConst>()) {
302 if (!(keyval.value().is<uint8_t>() or keyval.value().isNull()))
303 return utils::status(
"UBlock: Given input is not a number '%s'", keyval.value().as<
const char *>());
305 auto output = std::stoul(keyval.key().c_str());
308 for (JsonPairConst keyval : cfg.as<JsonObjectConst>()) {
310 auto output = std::stoul(keyval.key().c_str());
312 if (keyval.value().isNull())
314 auto input = keyval.value().as<uint8_t>();
315 if (!connect(input, output))
316 return utils::status(
"UBlock: Could not connect %d -> %d", input, output);
318 return utils::status::success();
320 return utils::status(
"UBlock either requires array or object configuration");
324utils::status blocks::UBlock::_config_constants_from_json(
const JsonVariantConst &cfg) {
325 float constant = cfg.as<
float>();
327 constant = cfg.as<
bool>() ? 1 : 0;
333 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::ANALOG_INPUT);
334 reset_reference_magnitude();
335 utils::status::success();
338 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::POS_REF);
340 change_b_side_transmission_mode(blocks::UBlock::Transmission_Mode::NEG_REF);
341 if (abs(constant) == 0.1f)
342 change_reference_magnitude(blocks::UBlock::Reference_Magnitude::ONE_TENTH);
343 else if (abs(constant) == 1.0f)
344 change_reference_magnitude(blocks::UBlock::Reference_Magnitude::ONE);
346 return utils::status(
"UBlock::config_self_from_json: Pass +-0.1 or +-1.");
347 return utils::status::success();
350FLASHMEM
void blocks::UBlock::config_self_to_json(JsonObject &cfg) {
351 Entity::config_self_to_json(cfg);
353 auto outputs_cfg = cfg.createNestedArray(
"outputs");
354 for (
const auto &output : output_input_map) {
356 outputs_cfg.add(output);
358 outputs_cfg.add(
nullptr);
361 if (b_side_mode == blocks::UBlock::Transmission_Mode::ANALOG_INPUT) {
362 cfg[
"constant"] =
false;
367 switch (b_side_mode) {
368 case blocks::UBlock::Transmission_Mode::POS_REF:
371 case blocks::UBlock::Transmission_Mode::NEG_REF:
374 case blocks::UBlock::Transmission_Mode::GROUND:
380 if (ref_magnitude == blocks::UBlock::Reference_Magnitude::ONE_TENTH) {
383 cfg[
"constant"] = val;
387FLASHMEM
void blocks::UBlock::reset_reference_magnitude() { ref_magnitude = Reference_Magnitude::ONE; }
389FLASHMEM
bool blocks::UBlockHAL_Dummy::write_outputs(std::array<int8_t, 32> outputs) {
return true; }
391FLASHMEM
bool blocks::UBlockHAL_Dummy::write_transmission_modes_and_ref(
392 std::pair<Transmission_Mode, Transmission_Mode> modes, blocks::UBlockHAL::Reference_Magnitude ref) {
396FLASHMEM
void blocks::UBlockHAL_Dummy::reset_transmission_modes_and_ref() {}