15net::EthernetUDP CalibrationBase::net_group;
16net::EthernetUDP CalibrationBase::net_receive;
18Box<UdpMessageOutputStream> CalibrationBase::broadcast_output;
19Box<UdpMessageInputStream> CalibrationBase::broadcast_input;
20Box<UdpMessageInputStream> CalibrationBase::data_input;
22void CalibrationBase::begin() {
23 broadcast_output = std::make_unique<UdpMessageOutputStream>(&net_group, net_group_ip, net_group_port);
24 broadcast_input = std::make_unique<UdpMessageInputStream>(&net_group);
25 data_input = std::make_unique<UdpMessageInputStream>(&net_receive);
26 if (!net_group.beginMulticast(net_group_ip, net_group_port))
27 LOG_ALWAYS(
"unable to open net_group_port")
29 if (!net_receive.begin(net_receive_port))
30 LOG_ALWAYS(
"unable to open net_receive_port")
33CalibrationBase::CalibrationBase(REDAC &redac,
const run::Run &
run)
36 _orig_adc_channels = redac.get_adc_channels();
42status CalibrationBase::send(
const pb_Envelope &envelope) {
43 if (!broadcast_output->write(envelope))
44 return "Unable to send UDP data";
45 return status::success();
51status CalibrationBase::separate_lane(uint8_t i_in_lane) {
52 for (
const auto &cluster : redac.clusters) {
54 auto original_i_config = cluster.iblock->get_outputs();
55 uint8_t original_output_lane = 0xff;
57 for (uint8_t lane = 0; lane < original_i_config.size(); lane++) {
58 if (original_i_config[lane] & cluster.iblock->hardware->INPUT_BITMASK(i_in_lane)) {
59 original_output_lane = lane;
65 if (original_output_lane == 0xff) {
66 cluster.iblock->hardware->write_outputs({});
70 std::array<uint32_t, 16> new_outputs = {};
71 uint8_t id_in_lane = used_id_lanes[cluster.get_cluster_idx()].first;
72 new_outputs[id_in_lane] = original_i_config[original_output_lane];
74 cluster.iblock->hardware->write_outputs(new_outputs);
77 return status::success();
80status CalibrationBase::do_initial() {
85 for (
auto &cluster : redac.clusters) {
86 for (
auto lane : blocks::CBlock::OUTPUT_IDX_RANGE())
87 if (!cluster.cblock->hardware->write_factor(lane, 0.0))
88 return "Error setting factor on C-block";
90 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
91 {blocks::UBlock::Transmission_Mode::POS_REF, blocks::UBlock::Transmission_Mode::POS_REF},
92 blocks::UBlock::Reference_Magnitude::ONE))
93 return "Error setting constant on U-block";
98 delayMicroseconds(100);
103 for (
auto &cluster : redac.clusters) {
104 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
106 delayMicroseconds(10000);
107 for (
auto &cluster : redac.clusters) {
108 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
110 delayMicroseconds(5000);
113 redac.reset_adc_channels();
115 for (
auto &cluster : redac.clusters) {
119 blocks::MBlock *id_lane_block =
nullptr;
120 if (cluster.m0block->has_id_lanes())
121 id_lane_block = cluster.m0block;
122 if (cluster.m1block->has_id_lanes())
123 id_lane_block = cluster.m1block;
125 if (id_lane_block ==
nullptr)
126 return "No M-Block with ID lane found in this cluster!";
128 uint8_t id_in_lane = 0, id_out_lane = 0;
130 auto id_connections = id_lane_block->ID_OUTPUT_CONNECTIONS();
131 for (uint8_t lane = 0; lane < id_connections.size(); lane++) {
132 if (id_connections[lane] != -1) {
133 id_in_lane = id_lane_block->slot_to_global_io_index(id_connections[lane]);
134 id_out_lane = id_lane_block->slot_to_global_io_index(lane);
139 used_id_lanes.emplace_back(id_in_lane, id_out_lane);
141 if (!redac.set_adc_channel(cluster.get_cluster_idx(),
static_cast<int8_t
>(id_out_lane),
142 cluster.get_cluster_idx()))
143 return "Error setting ADC lanes";
145 if (!redac.write_adcs_to_hardware())
146 return "Error writing ADCs to hardware";
148 return status::success();
151status CalibrationBase::do_lane(uint8_t lane) {
156 for (
auto &cluster : redac.clusters) {
161 bool signal_upscaled =
false;
162 for (
auto dst : {blocks::TBlock::Sector::BPL, blocks::TBlock::Sector::CL0, blocks::TBlock::Sector::CL1,
163 blocks::TBlock::Sector::CL2})
164 if (dst == blocks::TBlock::Sector::BPL)
165 signal_upscaled |= redac.carrier_t_block->is_external_target_upscaled(lane - 8);
168 signal_upscaled |= redac.clusters[
static_cast<uint8_t
>(dst) - 1].iblock->get_upscaling(lane);
170 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
171 {blocks::UBlock::Transmission_Mode::POS_REF, blocks::UBlock::Transmission_Mode::POS_REF},
172 signal_upscaled ? blocks::UBlock::Reference_Magnitude::ONE_TENTH
173 : blocks::UBlock::Reference_Magnitude::ONE
176 return "Error setting constant on U-block";
177 if (!cluster.cblock->hardware->write_factor(lane, 1.0))
178 return "Error setting factor on C-block";
182 RETURN_IF_FAILED(separate_lane(lane));
186 delayMicroseconds(5000);
189 auto gain_measure = daq::average(daq::sample, 4, 10);
192 delayMicroseconds(1000);
195 for (
auto &cluster : redac.clusters) {
196 if (!cluster.cblock->hardware->write_factor(lane, 0.0))
197 return "Error setting factor on C-block";
202 delayMicroseconds(5000);
204 auto offset_measure = daq::average(daq::sample, 4, 10);
207 bool gain_correction_exceeding =
false;
208 for (uint8_t cluster_idx = 0; cluster_idx < 3; cluster_idx++) {
209 bool signal_upscaled = redac.clusters[cluster_idx].iblock->get_upscaling(lane);
212 if (fabs(gain_measure[cluster_idx]) > 0.1) {
213 float gain_correction =
214 (signal_upscaled ? -0.8f : -1.0f) / (gain_measure[cluster_idx] - offset_measure[cluster_idx]);
216 if (gain_correction > 1.1f) {
217 gain_correction = 1.1f;
218 gain_correction_exceeding =
true;
222 if (!redac.clusters[cluster_idx].cblock->set_gain_correction(lane, gain_correction))
223 return "Error setting local gain correction on C-block";
225 measured_gain_correction[(lane - 8) + cluster_idx * 24] = gain_correction;
230 if (gain_correction_exceeding) {
231 LOG_ERROR(
"Gain correction exceeding 1.1.");
234 return status::success();
237bool CalibrationBase::send_gain_corrections(uint8_t cluster_idx, uint8_t lane,
float gain_correction) {
239 pb_Envelope envelope;
241 auto& data_cmd = msg_out.kind.calibrate_data_command;
242 data_cmd.has_data =
true;
245 if (gain_correction <= 0.0f)
248 auto dst_sector =
static_cast<blocks::TBlock::Sector
>(cluster_idx + 1);
249 auto src_sector = redac.carrier_t_block->src_of_signal(dst_sector, lane - 8);
250 if (src_sector != blocks::TBlock::Sector::BPL) {
252 auto src_cluster_idx =
static_cast<uint8_t
>(src_sector) - 1;
253 received_gain_correction[(lane - 8) + src_cluster_idx * 24].add(gain_correction);
262 auto source_entity_id = redac.carrier_t_block->get_external_signal_source_entity_id(dst_sector, lane - 8);
264 if (!signal_source) {
265 LOG_ERROR(
"Source of signal is unknown.");
267 data_cmd.data = pb_CalibrationData{
269 .gain_correction = gain_correction
272 transport::DatagramMessageOutputStream<UDP*> data_output(&net_receive, signal_source, net_receive_port);
273 data_output.write(envelope);
278bool CalibrationBase::receive_gain_corrections(
uint32_t timeout) {
280 pb_Envelope envelope;
281 if (!data_input->read(envelope, timeout))
284 if (envelope.which_kind != pb_Envelope_message_v1_tag)
287 auto& msg_in = envelope.kind.message_v1;
288 if (msg_in.which_kind != pb_MessageV1_calibrate_data_command_tag) {
289 LOG_ERROR(
"Expected calibration data but message is of different kind.")
293 auto& data_in = msg_in.kind.calibrate_data_command.data;
295 auto source = redac.carrier_t_block->src_of_signal(blocks::TBlock::Sector::BPL, data_in.lane - 8);
296 auto cluster_idx_ =
static_cast<uint8_t
>(source) - 1;
297 received_gain_correction[(data_in.lane - 8) + cluster_idx_ * 24].add(data_in.gain_correction);
301status CalibrationBase::send_receive_apply_gain_corrections() {
305 for (uint8_t idx = 0; idx < measured_gain_correction.size();) {
307 if (receive_gain_corrections(0))
continue;
310 auto gain_correction = measured_gain_correction[idx];
311 uint8_t cluster_idx = idx / 24;
312 uint8_t lane_idx = idx % 24 + 8;
313 send_gain_corrections(cluster_idx, lane_idx, gain_correction);
317 while (receive_gain_corrections(10)) {}
320 bool gain_correction_exceeding =
false;
322 for (
auto idx = 0; idx < received_gain_correction.size() ; ++idx) {
323 auto& gain_correction = received_gain_correction[idx];
324 uint8_t cluster_idx = idx / 24;
325 uint8_t lane_idx = idx % 24 + 8;
326 if (!gain_correction.get_n())
continue;
328 auto gain_correction_avg = gain_correction.get_average();
329 if (gain_correction_avg > 1.1f) {
330 gain_correction_avg = 1.1f;
331 gain_correction_exceeding =
true;
334 if (!redac.clusters[cluster_idx].cblock->set_gain_correction(lane_idx, gain_correction_avg))
335 LOG_ERROR(
"Gain correction could not be set.");
338 if (gain_correction_exceeding)
339 LOG_ERROR(
"Gain correction exceeding 1.1.");
342 if (!redac.set_adc_channels(_orig_adc_channels))
343 LOG_ERROR(
"Error while restoring setting adc channels.");
345 if (!redac.write_to_hardware())
346 LOG_ERROR(
"Error while restoring original configuration.");
348 return status::success();
351status CalibrationBase::do_final_offset_correction() {
353 for (
auto &cluster : redac.clusters) {
354 if (!cluster.ublock->hardware->write_transmission_modes_and_ref(
355 {blocks::UBlock::Transmission_Mode::GROUND, blocks::UBlock::Transmission_Mode::GROUND},
356 blocks::UBlock::Reference_Magnitude::ONE))
357 return "Error setting ground on U-block";
362 delayMicroseconds(100);
367 for (
auto &cluster : redac.clusters) {
368 cluster.shblock->hardware->set_state(blocks::SHState::TRACK);
370 delayMicroseconds(10000);
371 for (
auto &cluster : redac.clusters) {
372 cluster.shblock->hardware->set_state(blocks::SHState::INJECT);
375 delayMicroseconds(5000);
378 for (
auto &cluster : redac.clusters) {
380 RETURN_IF_FAILED(cluster.ublock->write_to_hardware());
383 return status::success();
386status CalibrationLeader::do_() {
388 RETURN_IF_FAILED(do_initial())
390 elapsedMicros elapsed_micros;
391 uint64_t sync_time = elapsed_micros;
393 auto sync = [&](uint64_t offset) {
394 uint64_t current = elapsed_micros;
395 delayMicroseconds( current - sync_time + offset);
399 for (uint8_t lane = 0u; lane < 32; lane++) {
400 delayMicroseconds(1000);
401 RETURN_IF_FAILED(do_lane(lane))
403 delayMicroseconds(1000);
404 RETURN_IF_FAILED(send_receive_apply_gain_corrections());
408 delayMicroseconds(10000);
409 RETURN_IF_FAILED(do_final_offset_correction());
410 return status::success();
413status CalibrationLeader::do_initial() {
414 pb_Envelope envelope;
416 msg.kind.calibrate_init_command = pb_CalibrateInitCommand_init_default;
417 RETURN_IF_FAILED(send(envelope));
418 delayMicroseconds(19);
419 return CalibrationBase::do_initial();
422status CalibrationLeader::do_lane(uint8_t lane) {
423 pb_Envelope envelope;
425 auto& lane_cmd =
msg.kind.calibrate_lane_command = pb_CalibrateLaneCommand_init_default;
426 lane_cmd.lane = lane;
428 RETURN_IF_FAILED(send(envelope));
429 delayMicroseconds(19);
430 return CalibrationBase::do_lane(lane);
433status CalibrationLeader::send_receive_apply_gain_corrections() {
434 pb_Envelope envelope;
436 RETURN_IF_FAILED(send(envelope));
437 delayMicroseconds(19);
438 return CalibrationBase::send_receive_apply_gain_corrections();
441status CalibrationLeader::do_final_offset_correction() {
442 pb_Envelope envelope;
445 RETURN_IF_FAILED(send(envelope));
446 delayMicroseconds(19);
447 return CalibrationBase::do_final_offset_correction();
450CalibrationFollower::CalibrationFollower(REDAC &redac,
const run::Run &
run,
451 unsigned int timeout_ms)
452 : CalibrationBase(redac,
run), timeout_ms(timeout_ms) {}
454status CalibrationFollower::receive_command(pb_Envelope &envelope) {
455 if (!broadcast_input->read(envelope, timeout_ms))
456 return "Timout while waiting for incoming calibration command";
458 return status::success();
461status CalibrationFollower::do_() {
462 RETURN_IF_FAILED(do_initial())
464 RETURN_IF_FAILED(do_lane_as_told())
468 RETURN_IF_FAILED(send_receive_apply_gain_corrections());
469 RETURN_IF_FAILED(do_final_offset_correction());
470 return status::success();
473status CalibrationFollower::do_initial() {
474 pb_Envelope envelope;
475 RETURN_IF_FAILED(receive_command(envelope));
476 return CalibrationBase::do_initial();
479status CalibrationFollower::do_lane_as_told() {
480 pb_Envelope envelope = pb_Envelope_init_default;
481 RETURN_IF_FAILED(receive_command(envelope));
482 auto&
msg = envelope.kind.message_v1;
483 if (
msg.which_kind != pb_MessageV1_calibrate_lane_command_tag) {
484 std::string error_msg =
"Expected calibration lane command but message is of different kind.";
485 error_msg +=
" Received: " + std::to_string(
msg.which_kind);
486 return status(error_msg.c_str());
488 auto& lane_cmd =
msg.kind.calibrate_lane_command;
489 uint8_t lane = lane_cmd.lane;
491 return "Error: Told to calibrate a lane >= 32.";
494 return CalibrationBase::do_lane(lane);
497status CalibrationFollower::send_receive_apply_gain_corrections() {
498 pb_Envelope envelope;
499 RETURN_IF_FAILED(receive_command(envelope));
500 return CalibrationBase::send_receive_apply_gain_corrections();
503status CalibrationFollower::do_final_offset_correction() {
504 pb_Envelope envelope;
505 RETURN_IF_FAILED(receive_command(envelope));
506 return CalibrationBase::do_final_offset_correction();
513 return search->second;