REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
cblock.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 <block/cblock.h>
6#include <utils/logging.h>
7
8FLASHMEM blocks::CBlock::CBlock(CBlockHAL *hardware) : FunctionBlock("C", hardware), hardware(hardware) {}
9
10FLASHMEM blocks::CBlock::CBlock() : CBlock(new CBlockHALDummy()) {}
11
12FLASHMEM float blocks::CBlock::get_factor(uint8_t idx) {
13 if (idx >= NUM_COEFF)
14 return 0.0f;
15 return factors_[idx];
16}
17
18FLASHMEM const std::array<float, blocks::CBlock::NUM_COEFF> &blocks::CBlock::get_factors() const {
19 return factors_;
20}
21
22FLASHMEM bool blocks::CBlock::set_factor(uint8_t idx, float factor) {
23 if (idx >= NUM_COEFF)
24 return false;
25 if (factor > MAX_FACTOR or factor < MIN_FACTOR)
26 return false;
27
28 factors_[idx] = factor;
29 return true;
30}
31
32FLASHMEM void blocks::CBlock::set_factors(const std::array<float, NUM_COEFF> &factors) { factors_ = factors; }
33
34FLASHMEM utils::status blocks::CBlock::write_to_hardware() {
35 if (!write_factors_to_hardware()) {
36 LOG(ANABRID_PEDANTIC, __PRETTY_FUNCTION__);
37 return utils::status::failure();
38 }
39 return utils::status::success();
40}
41
42FLASHMEM bool blocks::CBlock::write_factors_to_hardware() {
43 for (size_t i = 0; i < factors_.size(); i++) {
44 if (!hardware->write_factor(i, factors_[i] * gain_corrections_[i]))
45 return false;
46 }
47 return true;
48}
49
50FLASHMEM void blocks::CBlock::reset(entities::ResetAction action) {
51 FunctionBlock::reset(action);
52
53 if (action.has(entities::ResetAction::CIRCUIT_RESET))
54 for (size_t i = 0; i < NUM_COEFF; i++)
55 (void)set_factor(i, 1.0f);
56
57 if (action.has(entities::ResetAction::CALIBRATION_RESET))
58 reset_gain_corrections();
59}
60
61FLASHMEM float blocks::CBlock::get_gain_correction(uint8_t idx) const {
62 if (idx > NUM_COEFF)
63 return -2.0f;
64 return gain_corrections_[idx];
65}
66
67FLASHMEM const std::array<float, blocks::CBlock::NUM_COEFF> &blocks::CBlock::get_gain_corrections() const {
68 return gain_corrections_;
69}
70
71FLASHMEM void blocks::CBlock::reset_gain_corrections() {
72 std::fill(gain_corrections_.begin(), gain_corrections_.end(), 1.0f);
73}
74
75FLASHMEM void blocks::CBlock::set_gain_corrections(const std::array<float, NUM_COEFF> &corrections) {
76 gain_corrections_ = corrections;
77};
78
79FLASHMEM bool blocks::CBlock::set_gain_correction(const uint8_t coeff_idx, const float correction) {
80 if (coeff_idx > NUM_COEFF)
81 return false;
82 // Gain correction must be positive and close to 1
83 if (fabs(1.0f - correction) > MAX_GAIN_CORRECTION_ABS)
84 return false;
85 gain_corrections_[coeff_idx] = correction;
86 return true;
87};
88
89FLASHMEM utils::status blocks::CBlock::config_self_from_json(JsonObjectConst cfg) {
90#ifdef ANABRID_DEBUG_ENTITY_CONFIG
91 Serial.println(__PRETTY_FUNCTION__);
92#endif
93 for (auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
94 if (cfgItr->key() == "elements") {
95 auto res = _config_elements_form_json(cfgItr->value());
96 if (!res)
97 return res;
98 } else {
99 return utils::status("CBlock: Unknown configuration key");
100 }
101 }
102 return utils::status::success();
103}
104
105FLASHMEM utils::status blocks::CBlock::_config_elements_form_json(const JsonVariantConst &cfg) {
106 // Handle an array of factors
107 if (cfg.is<JsonArrayConst>()) {
108 auto factors = cfg.as<JsonArrayConst>();
109 if (factors.size() != NUM_COEFF)
110 return utils::status("Expecting %d elements in CBlock", NUM_COEFF);
111 uint8_t idx = 0;
112 for (JsonVariantConst factor : factors) {
113 if (!factor.is<float>())
114 return utils::status("CBlock: Cannot convert '%s' to float", factor.as<const char *>());
115 if (!set_factor(idx++, factor.as<float>()))
116 return utils::status("CBlock factor %f is out of valid bounds", factor.as<float>());
117 }
118 return utils::status::success();
119 }
120 // Handle a mapping of factors
121 else if (cfg.is<JsonObjectConst>()) {
122 serializeJson(cfg, Serial);
123 for (JsonPairConst keyval : cfg.as<JsonObjectConst>()) {
124 // Keys define index of factor to change
125 // TODO: Check conversion from string to number
126 auto idx = std::stoul(keyval.key().c_str());
127 // Values can either be direct factor float values or {"factor": 0.42} objects
128 if (keyval.value().is<JsonObjectConst>() and
129 keyval.value().as<JsonObjectConst>().containsKey("factor")) {
130 if (!set_factor(idx, keyval.value().as<JsonObjectConst>()["factor"].as<float>()))
131 return utils::status("CBlock factor value is not a float or not within range");
132 } else if (keyval.value().is<float>()) {
133 if (!set_factor(idx, keyval.value().as<float>()))
134 return utils::status("CBlock factor value is not within range");
135 } else {
136 return utils::status("CBlock factor value is not a float");
137 }
138 }
139 return utils::status::success();
140 }
141 return utils::status("CBlock configuration must be an object or array.");
142}
143
144FLASHMEM void blocks::CBlock::config_self_to_json(JsonObject &cfg) {
145 Entity::config_self_to_json(cfg);
146 auto factors_cfg = cfg.createNestedArray("elements");
147 for (auto idx = 0u; idx < factors_.size(); idx++) {
148 factors_cfg.add(get_factor(idx));
149 }
150}