REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
carrier.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 "pb_decode.h"
6#include "redac/calibration.h"
7#include "run/run_manager.h"
8
9#include <entity/visitor.h>
10#include <lucidac/lucidac.h>
11#include <mode/mode.h>
12#include <span>
13#include <net/settings.h>
14#include <redac/redac.h>
15#include <utils/is_number.h>
16
17carrier::Carrier::Carrier(std::vector<platform::Cluster> clusters, carrier::Carrier_HAL *hardware)
18 : Entity("", hardware), hardware(hardware), clusters(std::move(clusters)) {
19 classifier.class_enum = CLASS_;
20}
21
22carrier::Carrier *carrier::Carrier::from_entity_classifier(entities::EntityClassifier classifier,
23 __attribute__((__unused__))
24 const bus::addr_t block_address) {
25 if (!classifier or classifier.class_enum != entities::EntityClass::CARRIER)
26 return nullptr;
27
28 auto type = classifier.type_as<TYPES>();
29 switch (type) {
30 case TYPES::UNKNOWN:
31 // This is already checked by !classifier above
32 return nullptr;
33 case TYPES::LUCIDAC:
34 return platform::LUCIDAC::from_entity_classifier(classifier, block_address);
35 case TYPES::mREDAC:
36 return platform::REDAC::from_entity_classifier(classifier, block_address);
37 }
38 // Any unknown value results in a nullptr here.
39 // Adding default case to switch suppresses warnings about missing cases.
40 return nullptr;
41}
42
43carrier::Carrier *carrier::Carrier::detect() {
44 return entities::detect<carrier::Carrier>(bus::address_from_tuple(bus::CARRIER_BADDR, 0));
45}
46
47UnitResult carrier::Carrier::better_init() {
48 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
49
50 entity_id = net::StartupConfig::get().mac;
51
52 if (entity_id.empty())
53 return UnitResult::err("Cannot determine Carrier MAC");
54
55 // Detect CTRL-block
56 ctrl_block = entities::detect<blocks::CTRLBlock>(bus::address_from_tuple(bus::CTRL_BLOCK_BADDR, 0));
57 if (!ctrl_block) {
58 return UnitResult::err("Missing CTRL Block");
59 }
60
61 for (auto &cluster : clusters) {
62 TRY(cluster.init());
63 }
64
65 reset(entities::ResetAction::EVERYTHING);
66
67 return UnitResult::ok();
68}
69
70uint8_t carrier::Carrier::get_active_adc_channel_range() const{
71 uint8_t num_adc_channels = 0;
72 for(size_t idx = 0; idx < m_adc_channels.size(); idx++){
73 if(m_adc_channels[idx].idx != ADCChannel::DISABLED)
74 num_adc_channels = idx + 1;
75 }
76 return num_adc_channels;
77}
78
79std::vector<entities::Entity *> carrier::Carrier::get_child_entities() {
80 std::vector<entities::Entity *> children;
81 for (auto &cluster : clusters) {
82 children.push_back(&cluster);
83 }
84 if (ctrl_block)
85 children.push_back(ctrl_block);
86 return children;
87}
88
89entities::Entity *carrier::Carrier::get_child_entity(std::string_view child_id) {
90 auto opt_int = utils::view_to_number(child_id);
91 if (opt_int.has_value()) {
92 auto cluster_idx = opt_int.value();
93 if (cluster_idx < 0 or clusters.size() < cluster_idx)
94 return nullptr;
95 return &clusters[cluster_idx];
96 }
97 if (child_id == "CTRL")
98 return ctrl_block;
99 if (child_id.size() == 17)
100 return this;
101 return nullptr;
102}
103
104ConfigResult carrier::Carrier::config(const pb_Item &item) {
105 if (!hardware)
106 return ConfigResult::err("Carrier cannot be configured without hardware");
107
108 if (item.which_kind == pb_Item_adc_config_tag) {
109 auto& carrier_config = item.kind.adc_config;
110
111 m_adc_channels.fill(ADCChannel());
112 size_t min_size = std::min(
113 static_cast<size_t>(carrier_config.channels_count),
114 m_adc_channels.size()
115 );
116
117 for (size_t idx = 0; idx < min_size; ++idx) {
118 auto& config_channel = carrier_config.channels[idx];
119 auto& channel = m_adc_channels[idx];
120 channel.idx = config_channel.idx;
121 channel.gain = config_channel.gain;
122 channel.offset = config_channel.offset;
123 channel.probe = config_channel.probe;
124 }
125
126 auto res = hardware->write_adc_bus_mux(m_adc_channels);
127 if (!res)
128 return ConfigResult::err("Could not configure ACLs from configuration");
129
130 return ConfigResult::ok(true);
131 }
132
133 return ConfigResult::ok(false);
134}
135
136void carrier::Carrier::extract(entities::ExtractVisitor &collector) {
137 Entity::extract(collector);
138
139 if (collector.include_specification()) {
140 auto& entity_spec = collector.create(pb_Item_entity_specification_tag).kind.entity_specification;
141 entity_spec.has_entity = true;
142 encode_classifier(entity_spec.entity);
143 }
144
145 if (collector.include_configuration()) {
146 auto& item = collector.create(pb_Item_adc_config_tag);
147 auto& carrier_config = item.kind.adc_config;
148 for (size_t idx = 0; idx < m_adc_channels.size(); ++idx) {
149 auto& channel = m_adc_channels[idx];
150 if (channel.idx == ADCChannel::DISABLED) continue;
151 if (channel.probe < 0) continue;
152 carrier_config.channels[carrier_config.channels_count++] = {
153 .idx = static_cast<uint32_t>(channel.idx),
154 .gain = channel.gain,
155 .offset = channel.offset,
156 .probe = static_cast<uint32_t>(channel.probe)
157 };
158 }
159 }
160}
161
162UnitResult carrier::Carrier::write_to_hardware() {
163 int cluster_index = 1;
164 for (auto &cluster : clusters) {
165 auto result = cluster.write_to_hardware();
166 if (!result) {
167 return UnitResult::err("Cluster " + std::to_string(cluster_index) + " write failed. (" + result.err_value() + ")");
168 }
169 cluster_index++;
170 }
171
172 return write_adcs_to_hardware();
173}
174
175UnitResult carrier::Carrier::calibrate_offsets() {
176 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
177
178 for (auto &cluster : clusters)
179 TRY(cluster.calibrate_offsets());
180
181 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
182 return UnitResult::ok();
183}
184
185UnitResult carrier::Carrier::calibrate_routes() {
186 entities::Setup setup;
187 entities::ExtractSettings settings{
188 .include_configuration = true
189 };
190 setup.extract(this, settings);
191 auto result = calibrate_routes_raw();
192 setup.apply(this, true);
193 return result;
194}
195
196// This calibration function is working for a generic array of clusters that don't have any shared connections.
197// LUCIDAC relies on this function, an mREDAC overwrites this function, as it can have cross cluster
198// connections.
199UnitResult carrier::Carrier::calibrate_routes_raw() {
200 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
201
202 bool gain_correction_exceeding = false;
203 for (auto &cluster : clusters) {
204 LOG_ANABRID_DEBUG_CALIBRATION(
205 ("Calibrating routes in cluster " + std::to_string(cluster.get_cluster_idx())).c_str());
206 // Save and change ADC bus selection
207 auto old_adcbus = ctrl_block->get_adc_bus();
208 auto old_adc_channels = get_adc_channels();
209
210 reset_adc_channels();
211
212 ctrl_block->set_adc_bus(blocks::CTRLBlock::ADCBus::ADC);
213 TRY(ctrl_block->write_to_hardware());
214
215 // Save current U-block transmission modes and set them to zero
216 LOG_ANABRID_DEBUG_CALIBRATION("Starting calibration");
217 auto old_transmission_modes = cluster.ublock->get_all_transmission_modes();
218 auto old_reference_magnitude = cluster.ublock->get_reference_magnitude();
219
220 // Enable reference signal for calibration
221 LOG_ANABRID_DEBUG_CALIBRATION("Enable u-block reference");
222 cluster.ublock->change_all_transmission_modes(blocks::UBlock::Transmission_Mode::POS_REF);
223 TRY(cluster.ublock->write_to_hardware());
224
225 // Save C-Block factors
226 LOG_ANABRID_DEBUG_CALIBRATION("Reset c-block");
227 auto old_c_block_factors = cluster.cblock->get_factors();
228 cluster.cblock->set_factors({});
229 TRY (cluster.cblock->write_to_hardware());
230
231 // Find an M block usable for its identity lanes
232 blocks::MBlock *id_block = nullptr;
233 if (cluster.m0block && cluster.m0block->has_id_lanes())
234 id_block = cluster.m0block;
235
236 if (!id_block && cluster.m1block && cluster.m1block->has_id_lanes())
237 id_block = cluster.m1block;
238
239 if (!id_block) {
240 return UnitResult::err("No M Block with ID Lanes found, calibration impossible!");
241 }
242
243 uint8_t id_in_lane = 0, id_out_lane = 4;
244 for (auto i = 0; i < id_block->ID_OUTPUT_CONNECTIONS().size(); i++) {
245 if (id_block->ID_OUTPUT_CONNECTIONS()[i] != -1) {
246 id_out_lane = id_block->slot_to_global_io_index(i);
247 id_in_lane = id_block->slot_to_global_io_index(id_block->ID_OUTPUT_CONNECTIONS()[i]);
248 break;
249 }
250 }
251
252 std::array<std::vector<uint8_t>, blocks::IBlock::NUM_OUTPUTS> old_i_block_connections;
253 for (auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE()) {
254 for (auto i_in_idx : blocks::IBlock::INPUT_IDX_RANGE()) {
255
256 // Only do something is this lane is used in the original I-block configuration
257 if (!cluster.iblock->is_connected(i_in_idx, i_out_idx))
258 continue;
259
260 // If we don't have a complete connection through the u block, we don't need / we can't calibrate this
261 // route from here
262 if (!cluster.ublock->is_output_connected(i_in_idx))
263 continue;
264
265 // Store this i block input to output connection
266 old_i_block_connections[i_out_idx].emplace_back(i_in_idx);
267 }
268 }
269
270 LOG_ANABRID_DEBUG_CALIBRATION("Reset i-block");
271 cluster.iblock->reset_outputs();
272 TRY(cluster.iblock->write_to_hardware());
273
274 // Now we restore each summation isolated from the rest and route each summation output / i block output to
275 // an M-Mul block
276 for (auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE()) {
277 for (auto i_in_idx : old_i_block_connections[i_out_idx])
278 TRY(cluster.iblock->connect(i_in_idx, id_in_lane));
279
280 TRY(cluster.iblock->write_to_hardware());
281
282 // Now switch through all relevant input signals and put one of them to 1.0
283 for (auto i_in_idx : old_i_block_connections[i_out_idx]) {
284 // Setup measure path
285 TRY(set_adc_channel(0, id_out_lane));
286 if (!hardware->write_adc_bus_mux(m_adc_channels))
287 return UnitResult::err("Writing adcs failed!");
288
289 // Depending on whether upscaling is enabled for this lane, we apply +1 or +0.1 reference
290 // This is done on all lanes (but no other I-block connection exists, so no other current flows)
291 bool upscaled_channel = cluster.iblock->get_upscaling(i_in_idx);
292 cluster.ublock->change_reference_magnitude(upscaled_channel
293 ? blocks::UBlock::Reference_Magnitude::ONE_TENTH
294 : blocks::UBlock::Reference_Magnitude::ONE);
295 TRY(cluster.ublock->write_to_hardware());
296
297 // First measure the offset of each measuring lane. The SH Block can not calibrate offsets that occur
298 // after himself so we need to take care of that.
299 TRY(cluster.cblock->set_factor(i_in_idx, 0.0f));
300 TRY(cluster.cblock->set_gain_correction(i_in_idx, 1.0f));
301 TRY(cluster.cblock->write_to_hardware());
302
303 // Calibrate offsets for this specific route
304 TRY(calibrate_offsets());
305
306 auto measured_offset = -daq::average(daq::sample, 4, 10)[0];
307
308 // Allow this connection to go up to full scale. Those values are allways legal so we can ignore the
309 // return value
310 (void)cluster.cblock->set_factor(i_in_idx, 1.0f);
311 TRY(cluster.cblock->write_to_hardware());
312
313 delay(10);
314
315 // Measure gain output
316 auto measured_gain = -daq::average(daq::sample, 4, 10)[0];
317 LOG_ANABRID_DEBUG_CALIBRATION(measured_gain);
318 // Calculate necessary gain correction
319 auto gain_correction = (upscaled_channel ? 0.8f : 1.0f) / (measured_gain - measured_offset);
320 LOG_ANABRID_DEBUG_CALIBRATION(gain_correction);
321 if (gain_correction > 1.1f) {
322 gain_correction_exceeding = true;
323 gain_correction = 1.1f;
324 }
325 // Set gain correction on C-block, which will automatically get applied when writing to hardware
326 TRY(cluster.cblock->set_gain_correction(i_in_idx, gain_correction));
327 // Deactivate this lane again
328 TRY(cluster.cblock->set_factor(i_in_idx, 0.0f));
329 LOG_ANABRID_DEBUG_CALIBRATION(" ");
330 }
331
332 cluster.iblock->reset_outputs();
333 reset_adc_channels();
334 }
335
336 // Restore original U-block transmission modes and reference
337 cluster.ublock->change_all_transmission_modes(old_transmission_modes);
338 cluster.ublock->change_reference_magnitude(old_reference_magnitude);
339 // Write them to hardware
340 LOG_ANABRID_DEBUG_CALIBRATION("Restoring u-block");
341 TRY(cluster.ublock->write_to_hardware());
342
343 // Restore C-block factors
344 cluster.cblock->set_factors(old_c_block_factors);
345 LOG_ANABRID_DEBUG_CALIBRATION("Restoring c-block");
346 TRY(cluster.cblock->write_to_hardware());
347
348 // Restore I-block connections
349 LOG_ANABRID_DEBUG_CALIBRATION("Restoring i-block");
350 for (auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE())
351 for (auto i_in_idx : old_i_block_connections[i_out_idx])
352 TRY(cluster.iblock->connect(i_in_idx, i_out_idx));
353
354 TRY(cluster.iblock->write_to_hardware());
355
356 // Restore ADC bus selection
357 ctrl_block->set_adc_bus(old_adcbus);
358 TRY(ctrl_block->write_to_hardware());
359
360 TRY(set_adc_channels(old_adc_channels));
361 if (!hardware->write_adc_bus_mux(m_adc_channels))
362 return UnitResult::err("Writing adcs failed");
363 }
364
365 if (gain_correction_exceeding)
366 return UnitResult::err("Gain correction is too high, this is probably a problem with the hardware");
367
368 // Calibrate offsets for complete system
369 auto result = Carrier::calibrate_offsets();
370 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
371 return result;
372}
373
374UnitResult carrier::Carrier::calibrate_mblock(platform::Cluster &cluster, blocks::MBlock &mblock) {
375 // CARE: This function does not preserve the currently configured routes
376 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
377
378 // The calibration for each M-Block is prepared by connecting all outputs
379 // to the ADCs. This limits the calibration to one M-Block (and one cluster) at a time,
380 // which is not a problem though.
381 // Each M-Block must connect required reference signals by itself.
382
383 LOG(ANABRID_DEBUG_CALIBRATION, "Connecting outputs to ADC...");
384 for (auto output_idx : blocks::MBlock::SLOT_OUTPUT_IDX_RANGE()) {
385 auto lane_idx = mblock.slot_to_global_io_index(output_idx);
386 TRY(set_adc_channel(output_idx, lane_idx, cluster.get_cluster_idx()));
387 }
388 // Write to hardware
389 TRY(write_to_hardware());
390
391 // Pass to calibration function
392 LOG(ANABRID_DEBUG_CALIBRATION, "Passing control to M-block...");
393 TRY(mblock.calibrate(&cluster, this));
394
395 LOG(ANABRID_DEBUG_CALIBRATION, "Cleaning up calibration signals...");
396 reset(entities::ResetAction::CIRCUIT_RESET);
397
398 // Write final clean-up to hardware
399 TRY(write_to_hardware());
400
401 LOG(ANABRID_DEBUG_CALIBRATION, "Calibration done.");
402 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
403
404 return UnitResult::ok();
405}
406
407UnitResult carrier::Carrier::calibrate_m_blocks() {
408 for (auto &cluster : clusters) {
409 for (auto mblock : {cluster.m0block, cluster.m1block}) {
410 if (!mblock) continue;
411 TRY(calibrate_mblock(cluster, *mblock));
412 }
413 }
414
415 return UnitResult::ok();
416}
417
418void carrier::Carrier::reset(entities::ResetAction action) {
419 for (auto &cluster : clusters) {
420 cluster.reset(action);
421 }
422 if (ctrl_block)
423 ctrl_block->reset(action);
424 reset_adc_channels();
425}
426
427const std::array<carrier::ADCChannel, 8> &carrier::Carrier::get_adc_channels() const { return m_adc_channels; }
428
429UnitResult carrier::Carrier::set_adc_channels(const std::array<carrier::ADCChannel, 8> &channels) {
430 // Check that all inputs are in a valid range
431 uint8_t channel_idx = 0;
432 for (auto channel : channels) {
433 TRY(set_adc_channel(channel_idx, channel));
434 ++channel_idx;
435 }
436 return UnitResult::ok();
437}
438
439UnitResult carrier::Carrier::set_adc_channels(const std::array<int8_t, 8> &channels) {
440 // Check that all inputs are in a valid range
441 uint8_t channel_idx = 0;
442 for (auto channel : channels) {
443 TRY(set_adc_channel(channel_idx, channel));
444 ++channel_idx;
445 }
446 return UnitResult::ok();
447}
448
449UnitResult carrier::Carrier::set_adc_channel(uint8_t adc_channel, ADCChannel src_channel) {
450 if (adc_channel >= m_adc_channels.size())
451 return UnitResult::err_fmt("Error carrier channel out of range: %d", adc_channel);
452
453 m_adc_channels[adc_channel] = src_channel;
454 return UnitResult::ok();
455}
456
457[[nodiscard]] UnitResult carrier::Carrier::set_adc_channel(uint8_t adc_channel, int8_t src_idx) {
458 return set_adc_channel(adc_channel, ADCChannel{
459 .idx = src_idx,
460 });
461}
462
463UnitResult carrier::Carrier::set_adc_channel(uint8_t adc_channel, int8_t src_idx, uint8_t cluster_idx) {
464 return set_adc_channel(adc_channel, static_cast<int8_t>(src_idx + cluster_idx * 16));
465}
466
467void carrier::Carrier::reset_adc_channels() {
468 m_adc_channels.fill(ADCChannel());
469}
470
471UnitResult carrier::Carrier::measure_all_signals(std::array<std::array<float, 8>, 6> &data) {
472 auto old_adc_channels = get_adc_channels();
473 reset_adc_channels();
474 size_t idx = static_cast<size_t>(-1);
475 for (const auto &cluster : clusters) {
476 for (const auto mblock : {cluster.m0block, cluster.m1block}) {
477 ++idx;
478 if (!mblock) continue;
479
480 for (auto slot : blocks::MBlock::SLOT_OUTPUT_IDX_RANGE())
481 TRY(set_adc_channel(slot, mblock->slot_to_global_io_index(slot), cluster.get_cluster_idx()));
482
483 TRY(write_to_hardware());
484 data[idx] = daq::average();
485 }
486 }
487 TRY(set_adc_channels(old_adc_channels));
488 return UnitResult::ok();
489}
490
491UnitResult carrier::Carrier::write_adcs_to_hardware() {
492 if (ctrl_block)
493 TRY(ctrl_block->write_to_hardware());
494
495 if (!hardware->write_adc_bus_mux(m_adc_channels))
496 return UnitResult::err("ADC Bus write failed.");
497
498 return UnitResult::ok();
499}
500
501UnitResult carrier::Carrier::calibrate(const pb_CalibrationConfig &item) {
502#ifdef ANABRID_DEBUG_COMMS
503 Serial.println(__PRETTY_FUNCTION__);
504#endif
505
506 //skip extraction if nothing will be calibrated
507 if(item.math == pb_CalibrationConfig_Kind_Disabled && item.offset == pb_CalibrationConfig_Kind_Disabled)
508 return UnitResult::ok();
509
510 //following calibrations are not configuration preserving
511 entities::Setup setup;
512 entities::ExtractSettings settings{
513 .include_configuration = true
514 };
515 setup.extract(this, settings);
516 reset(entities::ResetAction::CIRCUIT_RESET);
517 auto reset_write = write_to_hardware();
518
519 if (reset_write.is_ok()) {
520 if(item.math != pb_CalibrationConfig_Kind_Disabled)
521 TRY(calibrate_m_blocks());
522
523 if (item.offset != pb_CalibrationConfig_Kind_Disabled)
524 TRY(calibrate_offsets());
525 }
526
527 setup.apply(this, true);
528 return reset_write;
529}
530
531UnitResult carrier::Carrier::user_get_overload_status(pb_OverloadStatus &overload_status) {
532 entities::OverloadVisitor visitor;
533 visitor.visit(this, true);
534 visitor.to(overload_status);
535 return UnitResult::ok();
536}
537
538UnitResult carrier::Carrier::user_calibrate(const pb_CalibrationConfig &item) {
539 return calibrate(item);
540}
541
542static Result<uint32_t> parse_uint(std::string_view view)
543{
544 char* eptr = nullptr;
545 auto result = std::strtol(view.begin(), &eptr, 10);
546 if(eptr - view.begin() != view.length())
547 return Result<uint32_t>::err("Invalid path: " + std::string(view));
548
549 return Result<uint32_t>::ok(result);
550}
551
552
553PathResult Routing::node2path(uint32_t node) const {
554 if (idx2entity.size() <= node)
555 return PathResult::err_fmt("Unable to find path of entity idx: %d", node);
556 return PathResult::ok(idx2entity.at(node));
557}
558
559U32Result Routing::path2node(Path path) const {
560 auto it = entity2node.find(path);
561 if (it == entity2node.end())
562 return LaneResult::err_fmt("Unable to find entity idx of path %s", std::string(path).c_str());
563
564 return U32Result::ok(entity2node.at(path));
565}
566
567U32Result Routing::cluster2node(uint32_t cluster_idx) const {
568 auto it = m_cluster2node.find(cluster_idx);
569 if (it == m_cluster2node.end())
570 return U32Result::err_fmt("Unable to find entity idx of %d", cluster_idx);
571 return U32Result::ok(it->second);
572}
573
574LaneResult Routing::cluster2lane(uint32_t cluster_idx, uint32_t lane_idx) const {
575 return LaneResult::ok(Lane(TRY(cluster2node(cluster_idx)), lane_idx));
576}
577
578UnitResult Routing::config_entity_idx(const pb_EntityId* entity_ids, uint32_t ids_count) {
579 idx2entity.resize(ids_count);
580
581 for (auto node = 0; node < ids_count; ++node) {
582 auto& entity_id = entity_ids[node];
583 Path path = std::string(entity_id.path);
584 if (path.size() != 2)
585 return ConfigResult::err("Expected cluster path in trace config");
586 if (path.segment(0) == self) {
587 m_cluster2node.emplace(TRY(parse_uint(path.segment(1))), node);
588 }
589
590 entity2node.emplace(path, node);
591 idx2entity[node] = path;
592 }
593 return UnitResult::ok();
594}
595
596UnitResult Routing::config_trace_config(const pb_DependencyInfo& dep_info) {
597 clear();
598
599 TRY(config_entity_idx(dep_info.entity_ids, dep_info.entity_ids_count));
600
601 for (auto idx = 0; idx < dep_info.traces_count; ++idx) {
602 auto& trace = dep_info.traces[idx];
603 Lane src_lane(trace.source_node, trace.source_lane);
604 Lane sink_lane(trace.sink_node, trace.sink_lane);
605 m_src2uses[src_lane]++;
606 if (trace.sink_upscaled) {
607 m_is_upscaled.insert(src_lane);
608 m_is_upscaled.insert(sink_lane);
609 }
610 m_sink2src.emplace(sink_lane, src_lane);
611 m_sink_is_present.insert(sink_lane);
612 }
613
614 return UnitResult::ok();
615}
616
617
618ConfigResult Routing::config(const pb_Item &item){
619 if (item.which_kind == pb_Item_dependency_info_tag) {
620 TRY(config_trace_config(item.kind.dependency_info));
621 return ConfigResult::ok(true);
622 }
623
624 if (item.which_kind == pb_Item_ip_lookup_table_tag) {
625 auto& ip_lookup_table = item.kind.ip_lookup_table;
626 for (size_t idx = 0; idx < ip_lookup_table.entries_count; ++idx) {
627 auto& entity = ip_lookup_table.entries[idx];
628 if (!entity.has_address || !entity.has_entity_id) continue;
629 auto& data = entity.address.data.bytes;
630 IPAddress address(data[0], data[1], data[2], data[3]);
631 set_path_address(std::string_view(entity.entity_id.path), address);
632 }
633 }
634
635 return ConfigResult::ok(false);
636}
637
638bool Routing::is_upscaled(Lane lane) const {
639 auto it = m_is_upscaled.find(lane);
640 return it != m_is_upscaled.end();
641}
642
643uint32_t Routing::use_count(Lane lane) const {
644 auto it = m_src2uses.find(lane);
645 if (it == m_src2uses.end())
646 return 0;
647 return it->second;
648}
649
650LaneResult Routing::source(Lane lane) const {
651 auto it = m_sink2src.find(lane);
652 if (it == m_sink2src.end())
653 return LaneResult::err("Not found source");
654 return LaneResult::ok(it->second);
655}
656
657bool Routing::is_source_used(Lane lane) const {
658 return use_count(lane) > 0;
659}
660
661bool Routing::is_sink_present(Lane lane) const {
662 auto it = m_sink_is_present.find(lane);
663 return it != m_sink_is_present.end();
664}
665
666IPAddressResult Routing::ip_address(Path path) const {
667 auto it = m_path2ip.find(path);
668 if (it != m_path2ip.end())
669 return IPAddressResult::ok(it->second);
670 return UnitResult::err_fmt("Ip adress of %s not found", std::string(path).c_str());
671}
672
673
674LaneResult Routing::source(uint32_t cluster_idx, uint32_t lane) const {
675 return source(TRY(cluster2lane(cluster_idx, lane)));
676}
677
678BoolResult Routing::is_upscaled(uint32_t cluster_idx, uint32_t lane) const {
679 return BoolResult::ok(is_upscaled(TRY(cluster2lane(cluster_idx, lane))));
680}
681
682U32Result Routing::use_count(uint32_t cluster_idx, uint32_t lane) const {
683 return U32Result::ok(use_count(TRY(cluster2lane(cluster_idx, lane))));
684}
685
686PathResult Routing::source_path(uint32_t cluster_idx, uint32_t lane) const {
687 return node2path(TRY(source(TRY(cluster2lane(cluster_idx, lane)))).m_node);
688}
689
690BoolResult Routing::is_sink_present(uint32_t cluster_idx, uint32_t lane) const {
691 return BoolResult::ok(is_sink_present(TRY(cluster2lane(cluster_idx, lane))));
692}
693
694BoolResult Routing::is_source_used(uint32_t cluster_idx, uint32_t lane) const {
695 return BoolResult::ok(is_source_used(TRY(cluster2lane(cluster_idx, lane))));
696}
static Result< uint32_t > parse_uint(std::string_view view)
Definition carrier.cpp:542
uint32_t
Definition flasher.cpp:195
uint32_t uint32_t size
Definition flasher.cpp:63
__attribute__((section(".fastrun"), noinline, noclone, optimize("Os"))) int flash_sector_not_erased(uint32_t address)
Definition flasher.cpp:114
void setup()