17net::EthernetUDP CalibrationBase::net_group;
20Box<UdpMessageOutputStream> CalibrationBase::broadcast_output;
21Box<UdpMessageInputStream> CalibrationBase::broadcast_input;
24void CalibrationBase::begin() {
25 broadcast_output = std::make_unique<UdpMessageOutputStream>(&net_group, net_group_ip, net_group_port);
26 broadcast_input = std::make_unique<UdpMessageInputStream>(&net_group);
28 if (!net_group.beginMulticast(net_group_ip, net_group_port))
29 LOG_ALWAYS(
"unable to open net_group_port")
35void CalibrationBase::clear(uint32_t timeout_ms) {
36 pb_Envelope envelope = pb_Envelope_init_zero;
37 while (broadcast_input->has_message())
38 IGNORE(broadcast_input->read(envelope, timeout_ms));
44CalibrationBase::CalibrationBase(REDAC &redac)
50UnitResult CalibrationBase::send(
const pb_Envelope &envelope) {
51 return broadcast_output->write(envelope);
57UnitResult CalibrationBase::prepare_lane(uint8_t in_lane) {
58 for (
const auto &cluster : redac.clusters) {
59 bool signal_upscaled = TRY(redac.routing.is_source_upscaled(cluster.get_cluster_idx(), in_lane));
62 auto ref = signal_upscaled
63 ? blocks::UBlock::Reference_Magnitude::ONE_TENTH
64 : blocks::UBlock::Reference_Magnitude::ONE;
66 constexpr auto mode = blocks::UBlockHAL::Transmission_Mode::POS_REF;
67 TRY_TRUE(cluster.ublock->hardware->write_transmission_modes_and_ref({mode, mode}, ref));
68 TRY_TRUE(cluster.cblock->hardware->write_factor(in_lane, 1.0));
71 auto original_i_config = cluster.iblock->get_outputs();
72 uint8_t original_output_lane = 0xff;
74 for (uint8_t lane = 0; lane < original_i_config.size(); lane++) {
75 if (original_i_config[lane] & blocks::IBlockHAL::INPUT_BITMASK(in_lane)) {
76 original_output_lane = lane;
81 std::array<uint32_t, 16> new_outputs{};
82 if (original_output_lane < 16) {
83 uint8_t id_in_lane = cluster2id_lane[cluster.get_cluster_idx()];
84 new_outputs[id_in_lane] = original_i_config[original_output_lane];
87 TRY_TRUE(cluster.iblock->hardware->write_outputs(new_outputs));
90 return UnitResult::ok();
93UnitResult CalibrationBase::do_initial() {
100 constexpr auto pos = blocks::UBlock::Transmission_Mode::POS_REF;
101 constexpr auto one = blocks::UBlock::Reference_Magnitude::ONE;
102 for (
auto &cluster : redac.clusters) {
103 TRY_TRUE(cluster.ublock->hardware->write_transmission_modes_and_ref({pos, pos}, one));
105 for (
size_t lane = 0; lane < 32 ; ++lane) {
106 TRY_TRUE(cluster.cblock->hardware->write_factor(lane, 0.0));
112 timer.sync_at_us(100);
117 for (
auto &cluster : redac.clusters) {
118 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
120 timer.sync_at_us(10000);
121 for (
auto &cluster : redac.clusters) {
122 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
124 timer.sync_at_us(5000);
127 std::array<carrier::ADCChannel, 8> adc_channels;
128 for (
auto &cluster : redac.clusters) {
130 blocks::MBlock *id_lane_block =
nullptr;
131 if (cluster.m0block->has_id_lanes())
132 id_lane_block = cluster.m0block;
133 if (cluster.m1block->has_id_lanes())
134 id_lane_block = cluster.m1block;
136 if (id_lane_block ==
nullptr)
137 return UnitResult::err(
"No M-Block with ID lane found in this cluster!");
139 auto id_connections = id_lane_block->ID_OUTPUT_CONNECTIONS();
141 for (; lane < id_connections.size(); lane++) {
142 if (id_connections[lane] == -1)
continue;
143 uint8_t id_in_lane = id_lane_block->slot_to_global_io_index(id_connections[lane]);
144 uint8_t id_out_lane = id_lane_block->slot_to_global_io_index(lane);
146 cluster2id_lane.push_back(id_in_lane);
147 adc_channels[cluster.get_cluster_idx()].src = id_out_lane + cluster.get_cluster_idx() * 16;
151 if (lane == id_connections.size())
152 return UnitResult::err(
"No M-Block with ID lane found!");
155 TRY(redac.write_adcs_to_hardware(adc_channels));
156 return UnitResult::ok();
159UnitResult CalibrationBase::do_lane(uint8_t lane) {
164 TRY(prepare_lane(lane));
168 TRY_TRUE(timer.sync_at_us(5000));
171 auto gain_measure = daq::average(daq::sample, 4, 10);
174 TRY_TRUE(timer.sync_at_us(5000));
177 for (
auto &cluster : redac.clusters) {
178 TRY_TRUE(cluster.cblock->hardware->write_factor(lane, 0.0));
183 TRY_TRUE(timer.sync_at_us(5000));
185 auto offset_measure = daq::average(daq::sample, 4, 10);
188 bool gain_correction_exceeding =
false;
189 for (
size_t cluster_idx = 0; cluster_idx < redac.clusters.size(); cluster_idx++) {
190 if (!TRY(redac.routing.is_sink_present(cluster_idx, lane)))
193 bool signal_upscaled = TRY(redac.routing.is_source_upscaled(cluster_idx, lane));
195 float difference = offset_measure[cluster_idx] - gain_measure[cluster_idx];
196 float gain_correction = (signal_upscaled ? 0.8f : 1.0f) / difference;
198 if (gain_correction < 0.7f || 1.2f < gain_correction) {
199 bool carrier_idx = redac.routing.self_carrier();
200 return UnitResult::err_fmt(
"Gain correction far beyond normal %f at %d/%d/%d", gain_correction, carrier_idx, cluster_idx, lane);
203 if (gain_correction > 1.1f) {
204 bool carrier_idx = redac.routing.self_carrier();
205 LOGV(
"Gain correction exceeding 1.1 at %s(%d)/%d/%d which is %f at", redac.get_entity_id().c_str(), carrier_idx, cluster_idx, lane, gain_correction);
206 gain_correction = 1.1f;
207 gain_correction_exceeding =
true;
210 measured_gain_correction[cluster_idx][lane] = gain_correction;
213 if (gain_correction_exceeding) {
214 LOG_ERROR(
"Gain correction exceeding 1.1.");
217 return UnitResult::ok();
220UnitResult CalibrationBase::collect_gain_corrections(uint8_t cluster_idx, uint8_t lane,
float gain_correction) {
221 if (!TRY(redac.routing.is_sink_present(cluster_idx, lane))) {
222 return UnitResult::ok();
226 agg_gain_corrs[cluster_idx + 1][lane].add(gain_correction);
227 return UnitResult::ok();
230 auto dst_sector =
static_cast<blocks::TBlock::Sector
>(cluster_idx + 1);
231 auto src_sector = redac.carrier_t_block->src_of_signal(dst_sector, lane - 8);
232 auto& agg_gain_corr = agg_gain_corrs[src_sector][lane];
234 if (src_sector == 0) {
235 auto dst_lane = TRY(redac.routing.cluster2lane(cluster_idx, lane));
236 auto src_lane = TRY(redac.routing.source(dst_lane));
237 if (agg_gain_corr.get_n() == 0) {
238 bpl_srcs[lane] = src_lane;
239 }
else if (bpl_srcs[lane] != src_lane) {
240 return UnitResult::err_fmt(
"Expected source lane be unique %s:%d:%d from %d:%d:%d - %d:%d:%d", redac.get_entity_id().c_str(), cluster_idx, lane, src_lane.carrier(), src_lane.cluster(), src_lane.lane(), bpl_srcs[lane].carrier(), bpl_srcs[lane].cluster(), bpl_srcs[lane].lane());
244 agg_gain_corr.add(gain_correction);
263 return UnitResult::ok();
266BoolResult CalibrationBase::receive_gain_corrections(uint32_t timeout) {
267 pb_Envelope envelope;
268 if (!TRY(broadcast_input->read(envelope, timeout)))
269 return BoolResult::ok(
false);
271 if (envelope.which_kind != pb_Envelope_message_v1_tag)
272 return UnitResult::err(
"Expected message v1 tag");
274 auto& msg_in = envelope.kind.message_v1;
275 if (msg_in.which_kind != pb_MessageV1_calibrate_data_command_tag)
276 return UnitResult::err_fmt(
"Expected calibration data but message is of different kind: %d", msg_in.which_kind);
278 auto& cmd = msg_in.kind.calibrate_data_command;
279 for (
auto data_idx = 0; data_idx < cmd.data_count; ++data_idx) {
280 auto& data_in = cmd.data[data_idx];
283 if (data_in.carrier != redac.routing.self_carrier())
286 if (data_in.lane < 8)
287 return UnitResult::err(
"Not expected calibration data for first 8 lanes via network!");
289 auto source = redac.carrier_t_block->src_of_signal(blocks::TBlock::Sector::BPL, data_in.lane - 8);
290 if (source == blocks::TBlock::Sector::BPL)
291 return UnitResult::err_fmt(
"Not expected calibration data for not connected backplane! %d",
static_cast<int>(redac.carrier_t_block->get_connections()[0]));
293 agg_gain_corrs[source][data_in.lane].add(data_in.gain_correction, data_in.weight);
296 return BoolResult::ok(
true);
299UnitResult CalibrationBase::exchange_gain_corrections() {
303 for (uint8_t cluster_idx = 0; cluster_idx < 3; ++cluster_idx) {
304 for (uint8_t lane_idx = 0; lane_idx < 32; ++lane_idx) {
306 auto gain_correction = measured_gain_correction[cluster_idx][lane_idx];
307 TRY(collect_gain_corrections(cluster_idx, lane_idx, gain_correction));
311 CalibrationStaging staging;
312 for (uint8_t lane_idx = 0; lane_idx < 32; ++lane_idx) {
313 auto src = bpl_srcs[lane_idx];
314 if (!src.valid())
continue;
315 auto& correction = agg_gain_corrs[0][lane_idx];
316 TRY(staging.add(src, correction.get_average(), correction.get_n()));
319 TRY_TRUE(timer.sync_at_ms(10));
320 for (
auto idx = 0; idx < redac.routing.num_carrier(); ++idx) {
321 if (idx == redac.routing.self_carrier()) {
322 TRY(broadcast_output->write(staging.envelope));
324 TRY(receive_gain_corrections(9));
327 TRY_TRUE(timer.sync_at_ms(10));
330 bool gain_correction_exceeding =
false;
332 for (
auto cluster_idx = 0; cluster_idx < 3 ; ++cluster_idx) {
333 for (
auto lane_idx = 0; lane_idx < 32 ; ++lane_idx) {
334 auto& gain_correction = agg_gain_corrs[cluster_idx + 1][lane_idx];
335 auto expected_count = TRY(redac.routing.use_count(cluster_idx, lane_idx));
337 if(expected_count != gain_correction.get_n())
338 return UnitResult::err_fmt(
339 "Mismatch signal use and gain correction count of carrier %s/%d on lane %d. Received %d but expected %d.",
340 redac.get_entity_id().c_str(),
343 gain_correction.get_n(),
346 if (gain_correction.get_n() == 0)
349 auto gain_correction_avg = gain_correction.get_average();
350 if (gain_correction_avg > 1.1f) {
351 LOGV(
"Received gain correction exceeding 1.1 which is %f", gain_correction_avg);
352 gain_correction_avg = 1.1f;
353 gain_correction_exceeding =
true;
356 TRY (redac.clusters[cluster_idx].cblock->set_gain_correction(lane_idx, gain_correction_avg));
360 if (gain_correction_exceeding)
361 LOG_ERROR(
"Gain correction exceeding 1.1.");
363 TRY_TRUE(redac.write_to_hardware());
364 return UnitResult::ok();
367UnitResult CalibrationBase::do_final_offset_correction() {
370 constexpr auto ground = blocks::UBlock::Transmission_Mode::GROUND;
371 constexpr auto one = blocks::UBlock::Reference_Magnitude::ONE;
372 for (
auto &cluster : redac.clusters)
373 TRY_TRUE(cluster.ublock->hardware->write_transmission_modes_and_ref({ground, ground}, one));
377 TRY_TRUE(timer.sync_at_us(1000));
382 for (
auto &cluster : redac.clusters)
383 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
384 TRY_TRUE(timer.sync_at_us(10000));
385 for (
auto &cluster : redac.clusters)
386 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
388 TRY_TRUE(timer.sync_at_us(5000));
390 for (
auto &cluster : redac.clusters)
391 TRY_TRUE(cluster.ublock->write_to_hardware());
392 return UnitResult::ok();
395UnitResult CalibrationLeader::do_() {
397 LOG_ALWAYS(
"Init calibration routes for run as leader...")
398 TRY_TRUE(timer.sync_at_ms(500));
399 LOG_ALWAYS(
"Starting calibration routes for run as leader...")
401 LOG_ALWAYS(
"Started calibration routes for run as leader...")
402 for (uint8_t lane = 0u; lane < 32; lane++) {
403 TRY_TRUE(timer.sync_at_us(20000));
406 TRY_TRUE(timer.sync_at_us(1000));
407 TRY(exchange_gain_corrections());
408 TRY_TRUE(timer.sync_at_us(1000));
409 LOG_ALWAYS(
"Finishing calibration routes for run as leader...")
410 TRY_TRUE(redac.write_to_hardware());
411 TRY_TRUE(timer.sync_at_us(10000));
412 TRY(do_final_offset_correction());
413 return UnitResult::ok();
416UnitResult CalibrationLeader::do_initial() {
417 pb_Envelope envelope;
419 msg.kind.calibrate_init_command = pb_CalibrateInitCommand_init_default;
421 delayMicroseconds(19);
422 return CalibrationBase::do_initial();
425UnitResult CalibrationLeader::do_lane(uint8_t lane) {
426 pb_Envelope envelope;
428 auto& lane_cmd =
msg.kind.calibrate_lane_command = pb_CalibrateLaneCommand_init_default;
429 lane_cmd.lane = lane;
432 delayMicroseconds(19);
433 return CalibrationBase::do_lane(lane);
436UnitResult CalibrationLeader::exchange_gain_corrections() {
437 pb_Envelope envelope;
440 delayMicroseconds(19);
441 return CalibrationBase::exchange_gain_corrections();
444UnitResult CalibrationLeader::do_final_offset_correction() {
445 pb_Envelope envelope;
449 delayMicroseconds(19);
450 return CalibrationBase::do_final_offset_correction();
453CalibrationFollower::CalibrationFollower(REDAC &redac,
454 unsigned int timeout_ms)
455 : CalibrationBase(redac), timeout_ms(timeout_ms) {}
457UnitResult CalibrationFollower::receive_command(pb_Envelope &envelope)
const {
458 if (TRY(broadcast_input->read(envelope, timeout_ms)))
459 return UnitResult::ok();
461 return UnitResult::err(
"Timeout while waiting for incoming calibration command");
464UnitResult CalibrationFollower::do_() {
465 LOG_ALWAYS(
"Init calibrating routes for run as follower...")
467 LOG_ALWAYS(
"Started calibrating routes for run as follower...")
469 TRY(do_lane_as_told());
473 TRY(exchange_gain_corrections());
474 TRY_TRUE(redac.write_to_hardware());
475 TRY(do_final_offset_correction());
476 return UnitResult::ok();
479UnitResult CalibrationFollower::wait_for(pb_Envelope& envelope,
int v1_tag)
const {
482 if (timer.elapsed_ms() > timeout_ms)
483 return UnitResult::err(
"Error initializing calibration");
484 TRY(receive_command(envelope));
485 if (envelope.which_kind != pb_Envelope_message_v1_tag)
continue;
486 if (envelope.kind.message_v1.which_kind != v1_tag)
continue;
490 return UnitResult::ok();
493UnitResult CalibrationFollower::do_initial() {
494 pb_Envelope envelope;
495 TRY(wait_for(envelope, pb_MessageV1_calibrate_init_command_tag));
496 return CalibrationBase::do_initial();
499UnitResult CalibrationFollower::do_lane_as_told() {
500 pb_Envelope envelope = pb_Envelope_init_default;
501 TRY(wait_for(envelope, pb_MessageV1_calibrate_lane_command_tag));
503 auto&
msg = envelope.kind.message_v1;
504 auto& lane_cmd =
msg.kind.calibrate_lane_command;
505 uint8_t lane = lane_cmd.lane;
507 return UnitResult::err(
"Error: Told to calibrate a lane >= 32.");
509 return CalibrationBase::do_lane(lane);
512UnitResult CalibrationFollower::exchange_gain_corrections() {
513 pb_Envelope envelope;
514 TRY(wait_for(envelope, pb_MessageV1_calibrate_finalize_command_tag));
515 return CalibrationBase::exchange_gain_corrections();
518UnitResult CalibrationFollower::do_final_offset_correction() {
519 pb_Envelope envelope;
520 TRY(wait_for(envelope, pb_MessageV1_calibrate_offset_command_tag));
521 return CalibrationBase::do_final_offset_correction();