17net::EthernetUDP CalibrationBase::net_group;
18net::EthernetUDP CalibrationBase::net_receive;
20Box<UdpMessageOutputStream> CalibrationBase::broadcast_output;
21Box<UdpMessageInputStream> CalibrationBase::broadcast_input;
22Box<UdpMessageInputStream> CalibrationBase::data_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);
27 data_input = std::make_unique<UdpMessageInputStream>(&net_receive);
28 if (!net_group.beginMulticast(net_group_ip, net_group_port))
29 LOG_ALWAYS(
"unable to open net_group_port")
31 if (!net_receive.begin(net_receive_port))
32 LOG_ALWAYS(
"unable to open net_receive_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));
40 while (data_input->has_message())
41 IGNORE(data_input->read(envelope, timeout_ms));
44CalibrationBase::CalibrationBase(REDAC &redac)
47 _orig_adc_channels = redac.get_adc_channels();
53UnitResult CalibrationBase::send(
const pb_Envelope &envelope) {
54 if (!broadcast_output->write(envelope))
55 return UnitResult::err(
"Unable to send UDP data");
56 return UnitResult::ok();
62UnitResult CalibrationBase::separate_lane(uint8_t i_in_lane) {
63 for (
const auto &cluster : redac.clusters) {
65 auto original_i_config = cluster.iblock->get_outputs();
66 uint8_t original_output_lane = 0xff;
68 for (uint8_t lane = 0; lane < original_i_config.size(); lane++) {
69 if (original_i_config[lane] & cluster.iblock->hardware->INPUT_BITMASK(i_in_lane)) {
70 original_output_lane = lane;
76 if (original_output_lane == 0xff) {
77 cluster.iblock->hardware->write_outputs({});
81 std::array<uint32_t, 16> new_outputs = {};
82 uint8_t id_in_lane = used_id_lanes[cluster.get_cluster_idx()].first;
83 new_outputs[id_in_lane] = original_i_config[original_output_lane];
85 cluster.iblock->hardware->write_outputs(new_outputs);
88 return UnitResult::ok();
91UnitResult CalibrationBase::do_initial() {
96 for (
auto &cluster : redac.clusters) {
97 for (
auto lane : blocks::CBlock::OUTPUT_IDX_RANGE())
98 if (!cluster.cblock->hardware->write_factor(lane, 0.0))
99 return UnitResult::err(
"Error setting factor on C-block");
101 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
102 {blocks::UBlock::Transmission_Mode::POS_REF, blocks::UBlock::Transmission_Mode::POS_REF},
103 blocks::UBlock::Reference_Magnitude::ONE))
104 return UnitResult::err(
"Error setting constant on U-block");
109 delayMicroseconds(100);
114 for (
auto &cluster : redac.clusters) {
115 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
117 delayMicroseconds(10000);
118 for (
auto &cluster : redac.clusters) {
119 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
121 delayMicroseconds(5000);
124 redac.reset_adc_channels();
126 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 uint8_t id_in_lane = 0, id_out_lane = 0;
141 auto id_connections = id_lane_block->ID_OUTPUT_CONNECTIONS();
142 for (uint8_t lane = 0; lane < id_connections.size(); lane++) {
143 if (id_connections[lane] != -1) {
144 id_in_lane = id_lane_block->slot_to_global_io_index(id_connections[lane]);
145 id_out_lane = id_lane_block->slot_to_global_io_index(lane);
150 used_id_lanes.emplace_back(id_in_lane, id_out_lane);
152 TRY(redac.set_adc_channel(cluster.get_cluster_idx(),
static_cast<int8_t
>(id_out_lane),
153 cluster.get_cluster_idx()));
155 if (!redac.write_adcs_to_hardware())
156 return UnitResult::err(
"Error writing ADCs to hardware");
158 return UnitResult::ok();
161UnitResult CalibrationBase::do_lane(uint8_t lane) {
166 for (
auto &cluster : redac.clusters) {
171 bool signal_upscaled = TRY(redac.routing.is_upscaled(cluster.get_cluster_idx(), lane));
173 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
174 {blocks::UBlock::Transmission_Mode::POS_REF, blocks::UBlock::Transmission_Mode::POS_REF},
175 signal_upscaled ? blocks::UBlock::Reference_Magnitude::ONE_TENTH
176 : blocks::UBlock::Reference_Magnitude::ONE
179 return UnitResult::err(
"Error setting constant on U-block");
180 if (!cluster.cblock->hardware->write_factor(lane, 1.0))
181 return UnitResult::err(
"Error setting factor on C-block");
185 TRY(separate_lane(lane));
189 timer.release_after_us(5000);
192 auto gain_measure = daq::average(daq::sample, 4, 10);
195 timer.release_after_us(1000);
198 for (
auto &cluster : redac.clusters) {
199 if (!cluster.cblock->hardware->write_factor(lane, 0.0))
200 return UnitResult::err(
"Error setting factor on C-block");
205 timer.release_after_us(5000);
207 auto offset_measure = daq::average(daq::sample, 4, 10);
210 bool gain_correction_exceeding =
false;
211 for (
size_t cluster_idx = 0; cluster_idx < redac.clusters.size(); cluster_idx++) {
212 if (!TRY(redac.routing.is_sink_present(cluster_idx, lane)))
continue;
214 bool signal_upscaled = TRY(redac.routing.is_upscaled(cluster_idx, lane));
215 float difference = offset_measure[cluster_idx] - gain_measure[cluster_idx];
216 float gain_correction = (signal_upscaled ? 0.1f : 1.0f) / difference;
218 if (gain_correction > 1.1f) {
219 gain_correction = 1.1f;
220 gain_correction_exceeding =
true;
223 measured_gain_correction[cluster_idx][lane] = gain_correction;
226 if (gain_correction_exceeding) {
227 LOG_ERROR(
"Gain correction exceeding 1.1.");
230 return UnitResult::ok();
233UnitResult CalibrationBase::distribute_gain_corrections(uint8_t cluster_idx, uint8_t lane,
float gain_correction) {
234 if (!TRY(redac.routing.is_sink_present(cluster_idx, lane))) {
235 return UnitResult::ok();
239 received_gain_correction[cluster_idx][lane].add(gain_correction);
240 return UnitResult::ok();
243 auto dst_sector =
static_cast<blocks::TBlock::Sector
>(cluster_idx + 1);
244 auto src_sector = redac.carrier_t_block->src_of_signal(dst_sector, lane - 8);
245 if (src_sector != blocks::TBlock::Sector::BPL) {
247 auto src_cluster_idx =
static_cast<uint8_t
>(src_sector) - 1;
248 received_gain_correction[src_cluster_idx][lane].add(gain_correction);
249 return UnitResult::ok();
258 pb_Envelope envelope;
260 auto& data_cmd = msg_out.kind.calibrate_data_command;
261 data_cmd.has_data =
true;
263 auto src_entity_path = TRY(redac.routing.source_path(cluster_idx, lane));
264 auto signal_source = TRY(redac.routing.ip_address(src_entity_path.segment(0)));
266 data_cmd.data = pb_CalibrationData{
268 .gain_correction = gain_correction
271 transport::DatagramMessageOutputStream<UDP*> data_output(&net_receive, signal_source, net_receive_port);
272 data_output.write(envelope);
273 return UnitResult::ok();
276UnitResult CalibrationBase::receive_gain_corrections(
uint32_t timeout) {
277 pb_Envelope envelope;
279 if (!TRY(data_input->read(envelope, timeout)))
280 return UnitResult::ok();
282 if (envelope.which_kind != pb_Envelope_message_v1_tag)
283 return UnitResult::err(
"Expected message v1 tag");
285 auto& msg_in = envelope.kind.message_v1;
286 if (msg_in.which_kind != pb_MessageV1_calibrate_data_command_tag) {
287 LOG_ERROR(
"Expected calibration data but message is of different kind.")
288 return UnitResult::err(
"Expected calibration data but message is of different kind");
291 auto& data_in = msg_in.kind.calibrate_data_command.data;
293 if (data_in.lane < 8)
294 return UnitResult::err(
"Not expected calibration data for first 8 lanes via network!");
296 auto source = redac.carrier_t_block->src_of_signal(blocks::TBlock::Sector::BPL, data_in.lane - 8);
297 if (source == blocks::TBlock::Sector::BPL)
298 return UnitResult::err(
"Not expected calibration data for not connected backplane!");
300 auto cluster_idx =
static_cast<uint8_t
>(source) - 1;
301 received_gain_correction[cluster_idx][data_in.lane].add(data_in.gain_correction);
305UnitResult CalibrationBase::send_receive_apply_gain_corrections() {
309 for (uint8_t cluster_idx = 0; cluster_idx < 3; ++cluster_idx) {
310 for (uint8_t lane_idx = 0; lane_idx < 32; ++lane_idx) {
312 auto gain_correction = measured_gain_correction[cluster_idx][lane_idx];
313 TRY(distribute_gain_corrections(cluster_idx, lane_idx, gain_correction));
315 TRY(receive_gain_corrections(5));
317 timer.release_after_us(10);
321 TRY(receive_gain_corrections(5000));
324 bool gain_correction_exceeding =
false;
326 for (
auto cluster_idx = 0; cluster_idx < 3 ; ++cluster_idx) {
327 for (
auto lane_idx = 0; lane_idx < 32 ; ++lane_idx) {
328 auto& gain_correction = received_gain_correction[cluster_idx][lane_idx];
329 auto count = TRY(redac.routing.use_count(cluster_idx, lane_idx));
331 if (count != gain_correction.get_n()) {
332 auto node = TRY(redac.routing.cluster2node(cluster_idx));
334 return UnitResult::err_fmt(
335 "Mismatch signal use and gain correction count of carrier %s/%d (%d) on lane %d. Received %d but expected %d.",
336 redac.get_entity_id().c_str(),
340 gain_correction.get_n(),
344 if (!gain_correction.get_n())
continue;
346 auto gain_correction_avg = gain_correction.get_average();
347 if (gain_correction_avg > 1.1f) {
348 gain_correction_avg = 1.1f;
349 gain_correction_exceeding =
true;
352 TRY (redac.clusters[cluster_idx].cblock->set_gain_correction(lane_idx, gain_correction_avg));
356 if (gain_correction_exceeding)
357 LOG_ERROR(
"Gain correction exceeding 1.1.");
360 TRY(redac.set_adc_channels(_orig_adc_channels));
361 TRY(redac.write_to_hardware());
363 return UnitResult::ok();
366UnitResult CalibrationBase::do_final_offset_correction() {
368 for (
auto &cluster : redac.clusters) {
369 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
370 {blocks::UBlock::Transmission_Mode::GROUND, blocks::UBlock::Transmission_Mode::GROUND},
371 blocks::UBlock::Reference_Magnitude::ONE))
372 return UnitResult::err(
"Error setting ground on U-block");
377 delayMicroseconds(100);
382 for (
auto &cluster : redac.clusters) {
383 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
385 delayMicroseconds(10000);
386 for (
auto &cluster : redac.clusters) {
387 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
390 delayMicroseconds(5000);
393 for (
auto &cluster : redac.clusters) {
395 TRY(cluster.ublock->write_to_hardware());
398 return UnitResult::ok();
401UnitResult CalibrationLeader::do_() {
403 LOG_ALWAYS(
"Init calibration routes for run as leader...")
404 timer.release_after_ms(500);
406 LOG_ALWAYS(
"Started calibration routes for run as leader...")
408 for (uint8_t lane = 0u; lane < 32; lane++) {
409 timer.release_after_us(1000);
412 timer.release_after_us(1000);
413 TRY(send_receive_apply_gain_corrections());
417 timer.release_after_us(10000);
418 TRY(do_final_offset_correction());
419 return UnitResult::ok();
422UnitResult CalibrationLeader::do_initial() {
423 pb_Envelope envelope;
425 msg.kind.calibrate_init_command = pb_CalibrateInitCommand_init_default;
427 delayMicroseconds(19);
428 return CalibrationBase::do_initial();
431UnitResult CalibrationLeader::do_lane(uint8_t lane) {
432 pb_Envelope envelope;
434 auto& lane_cmd =
msg.kind.calibrate_lane_command = pb_CalibrateLaneCommand_init_default;
435 lane_cmd.lane = lane;
438 delayMicroseconds(19);
439 return CalibrationBase::do_lane(lane);
442UnitResult CalibrationLeader::send_receive_apply_gain_corrections() {
443 pb_Envelope envelope;
446 delayMicroseconds(19);
447 return CalibrationBase::send_receive_apply_gain_corrections();
450UnitResult CalibrationLeader::do_final_offset_correction() {
451 pb_Envelope envelope;
455 delayMicroseconds(19);
456 return CalibrationBase::do_final_offset_correction();
459CalibrationFollower::CalibrationFollower(REDAC &redac,
460 unsigned int timeout_ms)
461 : CalibrationBase(redac), timeout_ms(timeout_ms) {}
463UnitResult CalibrationFollower::receive_command(pb_Envelope &envelope) {
464 if (TRY(broadcast_input->read(envelope, timeout_ms)))
465 return UnitResult::ok();
467 return UnitResult::err(
"Timout while waiting for incoming calibration command");
470UnitResult CalibrationFollower::do_() {
471 LOG_ALWAYS(
"Init calibrating routes for run as follower...")
473 LOG_ALWAYS(
"Starting calibrating routes for run as follower...")
475 TRY(do_lane_as_told());
479 TRY(send_receive_apply_gain_corrections());
480 TRY(do_final_offset_correction());
481 return UnitResult::ok();
484UnitResult CalibrationFollower::do_initial() {
485 pb_Envelope envelope;
486 TRY(receive_command(envelope));
487 return CalibrationBase::do_initial();
490UnitResult CalibrationFollower::do_lane_as_told() {
491 pb_Envelope envelope = pb_Envelope_init_default;
492 TRY(receive_command(envelope));
493 auto&
msg = envelope.kind.message_v1;
494 if (
msg.which_kind != pb_MessageV1_calibrate_lane_command_tag) {
495 return UnitResult::err_fmt(
496 "Expected calibration lane command but message is of different kind: %d",
500 auto& lane_cmd =
msg.kind.calibrate_lane_command;
501 uint8_t lane = lane_cmd.lane;
503 return UnitResult::err(
"Error: Told to calibrate a lane >= 32.");
505 return CalibrationBase::do_lane(lane);
508UnitResult CalibrationFollower::send_receive_apply_gain_corrections() {
509 pb_Envelope envelope;
510 TRY(receive_command(envelope));
511 return CalibrationBase::send_receive_apply_gain_corrections();
514UnitResult CalibrationFollower::do_final_offset_correction() {
515 pb_Envelope envelope;
516 TRY(receive_command(envelope));
517 return CalibrationBase::do_final_offset_correction();