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
7#include "utils/logging.h"
8
9FLASHMEM blocks::CBlock::CBlock(CBlockHAL *hardware) : FunctionBlock("C"), hardware(hardware) {
10 classifier.class_enum = CLASS_;
11}
12
14
15FLASHMEM float blocks::CBlock::get_factor(uint8_t idx) {
16 if (idx >= NUM_COEFF)
17 return 0.0f;
18 return factors_[idx];
19}
20
22 if (hardware)
23 return hardware->get_entity_eui();
24 return {};
25}
26
27FLASHMEM const std::array<float, blocks::CBlock::NUM_COEFF> &blocks::CBlock::get_factors() const {
28 return factors_;
29}
30
31FLASHMEM bool blocks::CBlock::set_factor(uint8_t idx, float factor) {
32 if (idx >= NUM_COEFF)
33 return false;
34 if (factor > MAX_FACTOR or factor < MIN_FACTOR)
35 return false;
36
37 factors_[idx] = factor;
38 return true;
39}
40
41FLASHMEM void blocks::CBlock::set_factors(const std::array<float, NUM_COEFF> &factors) { factors_ = factors; }
42
44 if (!write_factors_to_hardware()) {
45 LOG(ANABRID_PEDANTIC, __PRETTY_FUNCTION__);
47 }
49}
50
52 for (size_t i = 0; i < factors_.size(); i++) {
53 if (!hardware->write_factor(i, factors_[i] * gain_corrections_[i]))
54 return false;
55 }
56 return true;
57}
58
61
63 for (size_t i = 0; i < NUM_COEFF; i++)
64 (void)set_factor(i, 1.0f);
65
67 reset_gain_corrections();
68}
69
70FLASHMEM float blocks::CBlock::get_gain_correction(uint8_t idx) const {
71 if (idx > NUM_COEFF)
72 return -2.0f;
73 return gain_corrections_[idx];
74}
75
76FLASHMEM const std::array<float, blocks::CBlock::NUM_COEFF> &blocks::CBlock::get_gain_corrections() const {
77 return gain_corrections_;
78}
79
81 std::fill(gain_corrections_.begin(), gain_corrections_.end(), 1.0f);
82}
83
84FLASHMEM void blocks::CBlock::set_gain_corrections(const std::array<float, NUM_COEFF> &corrections) {
85 gain_corrections_ = corrections;
86};
87
88FLASHMEM bool blocks::CBlock::set_gain_correction(const uint8_t coeff_idx, const float correction) {
89 if (coeff_idx > NUM_COEFF)
90 return false;
91 // Gain correction must be positive and close to 1
92 if (fabs(1.0f - correction) > MAX_GAIN_CORRECTION_ABS)
93 return false;
94 gain_corrections_[coeff_idx] = correction;
95 return true;
96};
97
99#ifdef ANABRID_DEBUG_ENTITY_CONFIG
100 Serial.println(__PRETTY_FUNCTION__);
101#endif
102 for (auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
103 if (cfgItr->key() == "elements") {
104 auto res = _config_elements_form_json(cfgItr->value());
105 if (!res)
106 return res;
107 } else {
108 return utils::status("CBlock: Unknown configuration key");
109 }
110 }
111 return utils::status::success();
112}
113
114FLASHMEM utils::status blocks::CBlock::_config_elements_form_json(const JsonVariantConst &cfg) {
115 // Handle an array of factors
116 if (cfg.is<JsonArrayConst>()) {
117 auto factors = cfg.as<JsonArrayConst>();
118 if (factors.size() != NUM_COEFF)
119 return utils::status("Expecting %d elements in CBlock", NUM_COEFF);
120 uint8_t idx = 0;
121 for (JsonVariantConst factor : factors) {
122 if (!factor.is<float>())
123 return utils::status("CBlock: Cannot convert '%s' to float", factor.as<const char *>());
124 if (!set_factor(idx++, factor.as<float>()))
125 return utils::status("CBlock factor %f is out of valid bounds", factor.as<float>());
126 }
127 return utils::status::success();
128 }
129 // Handle a mapping of factors
130 else if (cfg.is<JsonObjectConst>()) {
131 serializeJson(cfg, Serial);
132 for (JsonPairConst keyval : cfg.as<JsonObjectConst>()) {
133 // Keys define index of factor to change
134 // TODO: Check conversion from string to number
135 auto idx = std::stoul(keyval.key().c_str());
136 // Values can either be direct factor float values or {"factor": 0.42} objects
137 if (keyval.value().is<JsonObjectConst>() and
138 keyval.value().as<JsonObjectConst>().containsKey("factor")) {
139 if (!set_factor(idx, keyval.value().as<JsonObjectConst>()["factor"].as<float>()))
140 return utils::status("CBlock factor value is not a float or not within range");
141 } else if (keyval.value().is<float>()) {
142 if (!set_factor(idx, keyval.value().as<float>()))
143 return utils::status("CBlock factor value is not within range");
144 } else {
145 return utils::status("CBlock factor value is not a float");
146 }
147 }
148 return utils::status::success();
149 }
150 return utils::status("CBlock configuration must be an object or array.");
151}
152
153FLASHMEM void blocks::CBlock::config_self_to_json(JsonObject &cfg) {
154 Entity::config_self_to_json(cfg);
155 auto factors_cfg = cfg.createNestedArray("elements");
156 for (auto idx = 0u; idx < factors_.size(); idx++) {
157 factors_cfg.add(get_factor(idx));
158 }
159}
160
161FLASHMEM blocks::CBlock *blocks::CBlock::from_entity_classifier(entities::EntityClassifier classifier,
162 const bus::addr_t block_address) {
163 if (!classifier or classifier.class_enum != CLASS_ or classifier.type != TYPE)
164 return nullptr;
165
166 if (classifier.version < entities::Version(1, 0))
167 return nullptr;
168 if (classifier.version < entities::Version(1, 1)) {
169 auto *new_block = new CBlock(new CBlockHAL_V_1_0_X(block_address));
170 new_block->classifier = classifier;
171 return new_block;
172 }
173 if (classifier.version < entities::Version(1, 2)) {
174 auto *new_block = new CBlock(new CBlockHAL_V_1_1_X(block_address));
175 new_block->classifier = classifier;
176 return new_block;
177 }
178
179 // Any unknown versuin results in a nullptr here.
180 return nullptr;
181}
182
183std::array<const functions::AD5452, 32> FLASHMEM
184blocks::CBlockHAL_Common::make_f_coeffs(bus::addr_t block_address, std::array<const uint8_t, 32> f_coeffs_cs) {
185 return {functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[0])),
186 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[1])),
187 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[2])),
188 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[3])),
189 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[4])),
190 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[5])),
191 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[6])),
192 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[7])),
193 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[8])),
194 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[9])),
195 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[10])),
196 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[11])),
197 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[12])),
198 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[13])),
199 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[14])),
200 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[15])),
201 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[16])),
202 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[17])),
203 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[18])),
204 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[19])),
205 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[20])),
206 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[21])),
207 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[22])),
208 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[23])),
209 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[24])),
210 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[25])),
211 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[26])),
212 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[27])),
213 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[28])),
214 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[29])),
215 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[30])),
216 functions::AD5452(bus::replace_function_idx(block_address, f_coeffs_cs[31]))};
217}
218
220 std::array<const uint8_t, 32> f_coeffs_cs)
221 : f_meta(block_address), f_coeffs(make_f_coeffs(block_address, f_coeffs_cs)) {}
222
223FLASHMEM bool blocks::CBlockHAL_Common::write_factor(uint8_t idx, float value) {
224 if (idx >= 32)
225 return false;
226 // NOTE: The current hardware does not allow any error detection here.
227 f_coeffs[idx].set_scale(value);
228 return true;
229}
230
232 /*
233 * Wrong oder of connection on IC2 was fixed, the addresses are
234 * - FADDR[0...35] = CS[0...35]
235 * - but also FADDR[32+4+0...32+4+3] = FADDR[32+8+0...32+8+3] = FADDR[32+8+4+0...32+8+4+3] = CS[32..35],
236 * because 2nd & 3rd bit of FADDR is not decoded
237 * - FADDR >= 48 are decoded correctly but not used
238 */
239 : CBlockHAL_Common(block_address, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
240 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}) {}
241
243 /*
244 * Due to wrong order of connections on IC2, the addresses are mixed up
245 * - FADDR[0...15] = CS[0...15] = [EEPROM, Coeffs[0...14]]
246 * - FADDR[32+0...32+15] = CS[16...31] = Coeffs[15...30]
247 * - FADDR[16+0...16+3] = CS[32+0...32+3] = [Coeff31, TMP127, UNUSED, UNUSED]
248 * - but also FADDR[16+4+0...16+4+3] = FADDR[16+8+0...16+8+3] = FADDR[16+8+4+0...16+8+4+3],
249 * because 2nd & 3rd bit of FADDR is not decoded
250 * - FADDR >= 48 are decoded correctly but not used
251 */
252 : CBlockHAL_Common(block_address, {1, 2, 3, 4, 5, 6, 7, 8,
253 9, 10, 11, 12, 13, 14, 15, 32 + 0,
254 32 + 1, 32 + 2, 32 + 3, 32 + 4, 32 + 5, 32 + 6, 32 + 7, 32 + 8,
255 32 + 9, 32 + 10, 32 + 11, 32 + 12, 32 + 13, 32 + 14, 32 + 15, 16}) {}
CBlockHAL_Common(bus::addr_t block_address, std::array< const uint8_t, 32 > f_coeffs_cs)
Definition cblock.cpp:219
static std::array< const functions::AD5452, 32 > make_f_coeffs(bus::addr_t block_address, std::array< const uint8_t, 32 > f_coeffs_cs)
Definition cblock.cpp:184
bool write_factor(uint8_t idx, float value) override
Definition cblock.cpp:223
CBlockHAL_V_1_0_X(bus::addr_t block_address)
Definition cblock.cpp:242
CBlockHAL_V_1_1_X(bus::addr_t block_address)
Definition cblock.cpp:231
The Lucidac Coefficient Block (C-Block) is represented by this class.
Definition cblock.h:83
utils::status write_to_hardware() override
returns true in case of success
Definition cblock.cpp:43
void config_self_to_json(JsonObject &cfg) override
Serialize the configuration of this entity to a JsonObject.
Definition cblock.cpp:153
void set_factors(const std::array< float, NUM_COEFF > &factors)
Definition cblock.cpp:41
const std::array< float, NUM_COEFF > & get_gain_corrections() const
Definition cblock.cpp:76
const std::array< float, NUM_COEFF > & get_factors() const
Definition cblock.cpp:27
bool set_gain_correction(uint8_t coeff_idx, const float correction)
Definition cblock.cpp:88
bool write_factors_to_hardware()
Definition cblock.cpp:51
static constexpr auto CLASS_
Definition cblock.h:87
void reset(entities::ResetAction action) override
Definition cblock.cpp:59
utils::status config_self_from_json(JsonObjectConst cfg) override
Deserialize a new configuration for this entity from a JsonObject.
Definition cblock.cpp:98
void set_gain_corrections(const std::array< float, NUM_COEFF > &corrections)
Definition cblock.cpp:84
float get_gain_correction(uint8_t idx) const
Definition cblock.cpp:70
void reset_gain_corrections()
Definition cblock.cpp:80
utils::status _config_elements_form_json(const JsonVariantConst &cfg)
Definition cblock.cpp:114
static CBlock * from_entity_classifier(entities::EntityClassifier classifier, bus::addr_t block_address)
Definition cblock.cpp:161
bool set_factor(uint8_t idx, float factor)
Definition cblock.cpp:31
float get_factor(uint8_t idx)
Set a particular digital potentiometer.
Definition cblock.cpp:15
metadata::eui_t get_entity_eui() const override
Definition cblock.cpp:21
A function block represents one module in a cluster, such as an M-Block, C-Block, I-Block or U-Block.
Definition base.h:29
EntityClassifier classifier
Definition base.h:217
virtual void reset(ResetAction action)
Definition base.h:155
The AD5452 is the 12-Bit Multiplying DAC, used in the C-Block (one AD5452 per lane).
Definition AD5452.h:16
A recoverable error, inspired from https://abseil.io/docs/cpp/guides/status and https://github....
Definition error.h:35
static status failure()
Syntactic sugar for failure.
Definition error.h:107
static status success()
Syntactic sugar for success.
Definition error.h:104
#define LOG(LOG_FLAG, message)
Definition logging.h:36
constexpr addr_t replace_function_idx(addr_t address, uint8_t func_idx)
Definition bus.h:88
uint16_t addr_t
Definition bus.h:27
std::array< uint8_t, 8 > eui_t
Definition base.h:20
static constexpr uint8_t CALIBRATION_RESET
Definition base.h:103
bool has(uint8_t other)
Definition base.h:111
static constexpr uint8_t CIRCUIT_RESET
Definition base.h:102