6#include "redac/calibration.h"
7#include "utils/timer.h"
10#include <redac/redac.h>
11#include <utils/logging.h>
13blocks::TBlockBackplane *platform::REDAC::init_backpanel_tblock(uint8_t baddr,
const char *name) {
14 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
15 LOGV(
"Detecting Backpanel %s Block...", name);
16 blocks::TBlockBackplane *t_block = entities::detect<blocks::TBlockBackplane>(bus::address_from_tuple(baddr, 0));
18 LOG(ANABRID_DEBUG_INIT,
"Warning: The backplane T block is missing or unknown...");
22 LOG(ANABRID_DEBUG_INIT,
"Initializing the backplane T Block...");
23 t_block->rename_entity(name);
24 auto t_block_result = t_block->init();
25 if (!t_block_result) {
26 LOG(ANABRID_DEBUG_INIT,
"Backplane T-Block Failed");
27 LOG(ANABRID_DEBUG_INIT, t_block_result.err_value().c_str());
31 LOG(ANABRID_DEBUG_INIT,
"Backplane T-Block initialized.");
35bool platform::REDAC::init() {
36 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
39 routing.init(entity_id);
42 bp_identifier = BackPanelIdentifier(hardware->read_backplane_and_slot_id());
45 if (!carrier_t_block) {
46 LOG(ANABRID_DEBUG_INIT,
"Detecting Carrier T-Block...");
47 carrier_t_block = entities::detect<blocks::TBlock>(bus::address_from_tuple(bus::CARRIER_T_BLOCK_BADDR, 0));
48 if (!carrier_t_block) {
49 LOG(ANABRID_DEBUG_INIT,
"Warning: Carrier T-Block is missing or unknown.");
51 LOG(ANABRID_DEBUG_INIT,
"Initializing Carrier T-Block...");
52 if(!carrier_t_block->init())
54 LOG(ANABRID_DEBUG_INIT,
"Carrier T-Block initialized.");
58 LOG(ANABRID_DEBUG_INIT,
"Detecting back panel...");
59 back_panel = entities::detect<platform::REDACBackPanel>(bus::address_from_tuple(bus::BACKPLANE_BADDR, 0));
61 LOG(ANABRID_DEBUG_INIT,
"Warning: Back panel is missing or unknown.");
65 stack_t0_block = init_backpanel_tblock(bus::BPL_T0_BLOCK_BADDR, platform::REDAC::STACK_T0_NAME);
67 stack_t1_block = init_backpanel_tblock(bus::BPL_T1_BLOCK_BADDR, platform::REDAC::STACK_T1_NAME);
69 stack_t2_block = init_backpanel_tblock(bus::BPL_T2_BLOCK_BADDR, platform::REDAC::STACK_T2_NAME);
71 return UnitResult::ok();
74platform::REDAC::REDAC(REDAC_HAL *hardware) : Carrier({Cluster(0), Cluster(1), Cluster(2)}, hardware), hardware(hardware) {}
76platform::BackPanelIdentifier platform::REDAC::get_back_panel_identifier()
const {
return bp_identifier; }
78void platform::REDAC::reset(entities::ResetAction action) {
79 Carrier::reset(action);
81 for (
auto *t_block : get_all_tblocks())
83 t_block->reset(action);
85 hardware->reset_adc_bus_mux();
88void platform::REDAC::power_up() { hardware->set_standby(
false); }
90void platform::REDAC::power_down() { hardware->set_standby(
true); }
92bool platform::REDAC::write_to_hardware() {
93 if(!Carrier::write_to_hardware())
96 for (
auto t_block : get_all_tblocks()) {
97 if (!t_block)
continue;
98 if(!t_block->write_to_hardware())
105UnitResult platform::REDAC::route_cross_cluster(uint8_t start_cluster, uint8_t end_cluster, uint8_t u_in, uint8_t u_out,
float c_factor, uint8_t i_out) {
106 if (start_cluster > 2 || end_cluster > 2)
107 return UnitResult::err(
"Invalid cluster indices. Valid ranges are 0 to 2");
110 return UnitResult::err(
"Can not connect a lane lower then 8 across multiple clusters");
112 auto *ublock = clusters[start_cluster].ublock;
113 auto *cblock = clusters[start_cluster].cblock;
114 auto *iblock = clusters[end_cluster].iblock;
117 carrier_t_block->connect(
static_cast<blocks::TBlock::Sector
>(start_cluster + 1),
static_cast<blocks::TBlock::Sector
>(end_cluster + 1), u_out - 8);
119 if (fabs(c_factor) > 1.0f) {
120 c_factor = c_factor / 8.0f;
121 iblock->set_upscaling(u_out,
true);
123 iblock->set_upscaling(u_out,
false);
125 TRY(ublock->connect(u_in, u_out));
126 TRY(cblock->set_factor(u_out, c_factor));
127 TRY(iblock->connect(u_out, i_out));
128 return UnitResult::ok();
131UnitResult platform::REDAC::route_to_backplane(uint8_t start_cluster, uint8_t u_in, uint8_t u_out,
float c_factor) {
132 if (start_cluster > 2)
133 return UnitResult::err(
"Invalid cluster index. Valid ranges are 0 to 2");
136 return UnitResult::err(
"Can not connect a lane lower then 8 to backplane");
138 auto *ublock = clusters[start_cluster].ublock;
139 auto *cblock = clusters[start_cluster].cblock;
141 carrier_t_block->connect(
static_cast<blocks::TBlock::Sector
>(start_cluster + 1), blocks::TBlock::Sector::BPL, u_out - 8);
143 if (!ublock->connect(u_in, u_out))
144 return UnitResult::err(
"U block connection not possible");
145 if (!cblock->set_factor(u_out, c_factor))
146 return UnitResult::err(
"C block configuration not possible, remember there is no automatic upscaling");
147 return UnitResult::ok();
150UnitResult platform::REDAC::route_from_backplane(uint8_t end_cluster, uint8_t i_in, uint8_t i_out) {
152 return UnitResult::err(
"Invalid cluster index. Valid ranges are 0 to 2");
155 return UnitResult::err(
"Can not connect a lane lower then 8 to backplane");
157 auto *iblock = clusters[end_cluster].iblock;
159 carrier_t_block->connect(blocks::TBlock::Sector::BPL,
static_cast<blocks::TBlock::Sector
>(end_cluster + 1), i_in - 8);
161 TRY(iblock->connect(i_in, i_out));
162 return UnitResult::ok();
165UnitResult platform::REDAC::route_on_backplane(blocks::TBlockBackplane::Sector start_sector, blocks::TBlockBackplane::Sector end_sector,
168 return UnitResult::err(
"No backplane was accessible!");
169 if (back_panel->get_entity_version() < entities::Version(2, 0, 0))
170 return UnitResult::err(
"The detected backplane is using old topology, which is no longer supported");
172 blocks::TBlockBackplane *required_t_block =
nullptr;
173 if (lane_idx < 8 || lane_idx > 31)
174 return UnitResult::err(
"Invalid lane index for backplane signal");
175 else if (lane_idx < 16)
176 required_t_block = stack_t0_block;
177 else if (lane_idx < 24)
178 required_t_block = stack_t1_block;
179 else if (lane_idx < 32)
180 required_t_block = stack_t2_block;
182 if (!required_t_block)
183 return UnitResult::err(
"The required backplane t-block could not be found!");
185 return required_t_block->connect(start_sector, end_sector, lane_idx % 8);
188UnitResult platform::REDAC::calibrate_offsets() {
189 LOG_ANABRID_DEBUG_CALIBRATION(
"Halting external signal sources");
191 std::vector<std::array<uint32_t, blocks::IBlock::NUM_OUTPUTS>> old_iblock_connections;
192 for (
auto &cluster : clusters) {
193 old_iblock_connections.emplace_back(cluster.iblock->get_outputs());
195 for (
auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE()) {
196 for (
auto i_in_idx : blocks::IBlock::INPUT_IDX_RANGE()) {
201 if (!cluster.iblock->is_connected(i_in_idx, i_out_idx))
205 auto dest_sector =
static_cast<blocks::TBlock::Sector
>(cluster.get_cluster_idx() + 1);
206 auto src = carrier_t_block->src_of_signal(dest_sector, i_in_idx - 8);
209 if (src != blocks::TBlock::Sector::BPL)
213 cluster.iblock->disconnect(i_in_idx, i_out_idx);
216 TRY_TRUE(cluster.iblock->write_to_hardware());
219 LOG_ANABRID_DEBUG_CALIBRATION(
"Calibrating all offsets");
221 std::vector<std::pair<blocks::UBlock::Transmission_Mode, blocks::UBlock::Transmission_Mode>> old_transmission_modes;
222 std::vector<blocks::UBlock::Reference_Magnitude> old_reference_magnitudes;
223 for (
auto &cluster : clusters) {
224 old_transmission_modes.push_back(cluster.ublock->get_all_transmission_modes());
225 old_reference_magnitudes.push_back(cluster.ublock->get_reference_magnitude());
226 cluster.ublock->change_all_transmission_modes(blocks::UBlock::Transmission_Mode::GROUND);
228 TRY_TRUE(cluster.ublock->write_to_hardware());
233 for (
auto &cluster : clusters)
234 cluster.shblock->compensate_hardware_offsets();
236 for (
size_t i = 0; i < clusters.size(); i++) {
237 clusters[i].ublock->change_all_transmission_modes(old_transmission_modes[i]);
238 clusters[i].ublock->change_reference_magnitude(old_reference_magnitudes[i]);
240 TRY_TRUE(clusters[i].ublock->write_to_hardware());
243 LOG_ANABRID_DEBUG_CALIBRATION(
"Resuming external signal sources");
245 for (
size_t i = 0; i < clusters.size(); i++) {
246 clusters[i].iblock->set_outputs(old_iblock_connections[i]);
247 TRY_TRUE(clusters[i].iblock->write_to_hardware());
251 return UnitResult::ok();
254UnitResult platform::REDAC::calibrate_routes() {
256 auto old_adcbus = ctrl_block->get_adc_bus();
257 auto old_adc_channels = get_adc_channels();
259 reset_adc_channels();
261 ctrl_block->set_adc_bus(blocks::CTRLBlock::ADCBus::ADC);
262 TRY_TRUE(ctrl_block->write_to_hardware());
265 LOG_ANABRID_DEBUG_CALIBRATION(
"Enable u-block reference");
267 std::vector<std::pair<blocks::UBlock::Transmission_Mode, blocks::UBlock::Transmission_Mode>> old_transmission_modes;
268 std::vector<blocks::UBlock::Reference_Magnitude> old_reference_magnitudes;
269 for (
auto &cluster : clusters) {
270 old_transmission_modes.push_back(cluster.ublock->get_all_transmission_modes());
271 old_reference_magnitudes.push_back(cluster.ublock->get_reference_magnitude());
272 cluster.ublock->change_all_transmission_modes(blocks::UBlock::Transmission_Mode::POS_REF);
274 TRY_TRUE(cluster.ublock->write_to_hardware());
277 LOG_ANABRID_DEBUG_CALIBRATION(
"Reset c-blocks");
278 std::vector<std::array<float, blocks::CBlock::NUM_COEFF>> old_c_block_factors;
279 for (
auto &cluster : clusters) {
280 old_c_block_factors.push_back(cluster.cblock->get_factors());
281 cluster.cblock->set_factors({});
283 TRY_TRUE(cluster.cblock->write_to_hardware());
286 for (
auto &cluster : clusters) {
287 LOG_ANABRID_DEBUG_CALIBRATION((
"Calibrating routes ending in cluster " + std::to_string(cluster.get_cluster_idx())).c_str());
290 if (!cluster.iblock->is_anything_connected())
294 blocks::MBlock *id_block =
nullptr;
295 if (cluster.m0block && cluster.m0block->has_id_lanes())
296 id_block = cluster.m0block;
298 if (!id_block && cluster.m1block && cluster.m1block->has_id_lanes())
299 id_block = cluster.m1block;
302 return UnitResult::err(
"No M Block with ID Lanes found, calibration impossible!");
305 uint8_t id_in_lane = 0, id_out_lane = 4;
306 for (
auto i = 0; i < id_block->ID_OUTPUT_CONNECTIONS().
size(); i++) {
307 if (id_block->ID_OUTPUT_CONNECTIONS()[i] != -1) {
308 id_out_lane = id_block->slot_to_global_io_index(i);
309 id_in_lane = id_block->slot_to_global_io_index(id_block->ID_OUTPUT_CONNECTIONS()[i]);
314 std::array<std::vector<uint8_t>, blocks::IBlock::NUM_OUTPUTS> old_i_block_connections;
315 std::array<std::vector<uint8_t>, blocks::IBlock::NUM_OUTPUTS> old_i_block_connections_uncalibrated;
316 for (
auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE()) {
317 for (
auto i_in_idx : blocks::IBlock::INPUT_IDX_RANGE()) {
319 if (!cluster.iblock->is_connected(i_in_idx, i_out_idx))
322 uint8_t src_cluster = cluster.get_cluster_idx();
326 auto src = carrier_t_block->src_of_signal(
static_cast<blocks::TBlock::Sector
>(cluster.get_cluster_idx() + 1), i_in_idx - 8);
328 if (src == blocks::TBlock::Sector::BPL) {
329 LOG_ANABRID_DEBUG_CALIBRATION(
"Signal starts on backplane, we can't work with this");
330 old_i_block_connections_uncalibrated[i_out_idx].emplace_back(i_in_idx);
334 src_cluster = src - 1;
336 if (src_cluster >= clusters.size())
342 if (!clusters[src_cluster].ublock->is_output_connected(i_in_idx))
346 old_i_block_connections[i_out_idx].emplace_back(i_in_idx);
349 cluster.iblock->reset_outputs();
350 TRY_TRUE(cluster.iblock->write_to_hardware());
352 for (
auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE()) {
353 for (
auto i_in_idx : old_i_block_connections[i_out_idx])
354 TRY (cluster.iblock->connect(i_in_idx, id_in_lane));
356 TRY_TRUE(cluster.iblock->write_to_hardware());
359 for (
auto i_in_idx : old_i_block_connections[i_out_idx]) {
360 LOG_ANABRID_DEBUG_CALIBRATION(i_in_idx);
361 LOG_ANABRID_DEBUG_CALIBRATION(i_out_idx);
363 auto *ublock = cluster.ublock;
364 auto *cblock = cluster.cblock;
365 auto *iblock = cluster.iblock;
366 auto *shblock = cluster.shblock;
371 auto src = carrier_t_block->src_of_signal(
static_cast<blocks::TBlock::Sector
>(cluster.get_cluster_idx() + 1), i_in_idx - 8);
373 if (src == blocks::TBlock::Sector::BPL) {
374 LOG_ANABRID_DEBUG_CALIBRATION(
"Signal starts on backplane, we can't work with this");
378 uint8_t src_cluster = src - 1;
380 LOG_ANABRID_DEBUG_CALIBRATION((
"Signal starts in cluster " + std::to_string(src_cluster)).c_str());
382 if (src_cluster >= clusters.size())
386 ublock = clusters[src_cluster].ublock;
387 cblock = clusters[src_cluster].cblock;
391 TRY(set_adc_channel(0, id_out_lane, cluster.get_cluster_idx()));
392 if (!hardware->write_adc_bus_mux(m_adc_channels))
393 return UnitResult::err(
"Writing adcs failed!");
397 bool upscaled_channel = iblock->get_upscaling(i_in_idx);
398 ublock->change_reference_magnitude(upscaled_channel ? blocks::UBlock::Reference_Magnitude::ONE_TENTH
399 : blocks::UBlock::Reference_Magnitude::ONE);
400 TRY_TRUE(cluster.ublock->write_to_hardware());
404 TRY(cblock->set_factor(i_in_idx, 0.0f));
405 TRY(cblock->set_gain_correction(i_in_idx, 1.0f));
406 TRY_TRUE(cblock->write_to_hardware());
409 TRY(calibrate_offsets());
411 auto measured_offset = -daq::average(daq::sample, 4, 10)[0];
412 LOG_ANABRID_DEBUG_CALIBRATION(measured_offset);
416 TRY(cblock->set_factor(i_in_idx, 1.0f));
417 TRY_TRUE(cblock->write_to_hardware());
422 auto measured_gain = -daq::average(daq::sample, 4, 10)[0];
423 LOG_ANABRID_DEBUG_CALIBRATION(measured_gain);
425 auto gain_correction = (upscaled_channel ? 0.8f : 1.0f) / (measured_gain - measured_offset);
426 LOG_ANABRID_DEBUG_CALIBRATION(gain_correction);
427 if (gain_correction > 1.1f) {
428 LOG_ALWAYS(
"Gain correction is too high, this is probably a problem with the hardware");
429 gain_correction = 1.1f;
432 TRY(cblock->set_gain_correction(i_in_idx, gain_correction));
434 TRY(cblock->set_factor(i_in_idx, 0.0f));
435 TRY_TRUE(cblock->write_to_hardware());
436 LOG_ANABRID_DEBUG_CALIBRATION(
" ");
439 cluster.iblock->reset_outputs();
440 reset_adc_channels();
444 LOG_ANABRID_DEBUG_CALIBRATION(
"Restoring i-block");
445 for (
auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE())
446 for (
auto i_in_idx : old_i_block_connections[i_out_idx])
447 TRY(cluster.iblock->connect(i_in_idx, i_out_idx));
448 for (
auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE())
449 for (
auto i_in_idx : old_i_block_connections_uncalibrated[i_out_idx])
450 TRY (cluster.iblock->connect(i_in_idx, i_out_idx));
452 TRY_TRUE(cluster.iblock->write_to_hardware());
455 LOG_ANABRID_DEBUG_CALIBRATION(
"Restoring u-blocks");
456 for (
size_t i = 0; i < clusters.size(); i++) {
457 clusters[i].ublock->change_all_transmission_modes(old_transmission_modes[i]);
458 clusters[i].ublock->change_reference_magnitude(old_reference_magnitudes[i]);
460 TRY_TRUE(clusters[i].ublock->write_to_hardware());
463 LOG_ANABRID_DEBUG_CALIBRATION(
"Restoring c-blocks");
464 for (
size_t i = 0; i < clusters.size(); i++) {
465 clusters[i].cblock->set_factors(old_c_block_factors[i]);
466 TRY_TRUE(clusters[i].cblock->write_to_hardware());
470 ctrl_block->set_adc_bus(old_adcbus);
471 TRY_TRUE(ctrl_block->write_to_hardware());
473 TRY(set_adc_channels(old_adc_channels));
474 if (!hardware->write_adc_bus_mux(m_adc_channels))
475 return UnitResult::err(
"Writing adcs failed");
478 TRY(calibrate_offsets());
480 return UnitResult::ok();
483std::vector<entities::Entity *> platform::REDAC::get_child_entities() {
484 auto entities = this->carrier::Carrier::get_child_entities();
487 for (
auto *t_block : get_all_tblocks())
493entities::Entity *platform::REDAC::get_child_entity(std::string_view child_id) {
494 if (child_id ==
"BP")
497 return carrier_t_block;
498 if (child_id == platform::REDAC::STACK_T0_NAME)
499 return stack_t0_block;
500 if (child_id == platform::REDAC::STACK_T1_NAME)
501 return stack_t1_block;
502 if (child_id == platform::REDAC::STACK_T2_NAME)
503 return stack_t2_block;
504 return this->Carrier::get_child_entity(child_id);
507void platform::REDAC::extract(entities::ExtractVisitor &collector) {
508 Carrier::extract(collector);
510 if (!collector.include_configuration())
return;
511 auto &config = collector.create(pb_Item_backpanel_config_tag);
512 auto &backpanel_config = config.kind.backpanel_config;
514 auto identifier = get_back_panel_identifier();
516 backpanel_config.backpanel_id = identifier.backpanel_id;
517 backpanel_config.backpanel_slot = identifier.backpanel_slot;
518 backpanel_config.is_valid = identifier.valid;
519 backpanel_config.is_isolated = identifier.isolated;
522UnitResult platform::REDAC::calibrate(
const pb_CalibrationConfig &item)
525 if (item.gain != pb_CalibrationConfig_Kind_Disabled) {
526 std::string_view path_view(item.leader.path);
527 bool is_leader = item.has_leader && path_view == get_entity_id();
529 std::unique_ptr<CalibrationBase> base;
531 base = std::make_unique<CalibrationLeader>(*
this);
533 base = std::make_unique<CalibrationFollower>(*
this);
536 uint32_t ms_calibration_sync = item.math * 15000 + item.offset * 150 + 200;
537 timer.sync_at_ms(ms_calibration_sync);
538 auto do_result = base->do_();
540 LOG_ERROR(
"ERROR during calibration");
541 LOG_ERROR(do_result.err_value().c_str());
545 LOG_ALWAYS(
"Calibration done.")
546 }
else if (item.offset != pb_CalibrationConfig_Kind_Disabled) {
548 TRY(calibrate_offsets());
551 if(item.math != pb_CalibrationConfig_Kind_Disabled) {
553 entities::Setup
setup;
554 entities::ExtractSettings settings{
555 .include_configuration =
true
557 setup.extract(
this, settings);
558 reset(entities::ResetAction::CIRCUIT_RESET);
559 TRY_TRUE(write_to_hardware());
560 TRY(calibrate_m_blocks());
562 TRY(
setup.apply(
this,
true));
565 return UnitResult::ok();
568ConfigResult platform::REDAC::config(
const pb_Item &item) {
569 if (item.which_kind == pb_Item_dependency_info_tag || item.which_kind == pb_Item_ip_lookup_table_tag) {
570 return routing.config(item);
573 if (item.which_kind == pb_Item_backpanel_config_tag) {
574 return ConfigResult::ok(
true);
577 return Carrier::config(item);