/src/ocudu/lib/nrppa/procedures/measurement_procedure.cpp
Line | Count | Source |
1 | | // SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited |
2 | | // SPDX-FileCopyrightText: Copyright (C) 2026 OCUDU contributors |
3 | | // SPDX-License-Identifier: BSD-3-Clause-Open-MPI |
4 | | // Portions of this file may implement 3GPP specifications, which may be subject to additional licensing requirements. |
5 | | |
6 | | #include "measurement_procedure.h" |
7 | | #include "../nrppa_asn1_converters.h" |
8 | | #include "../nrppa_helper.h" |
9 | | #include "ocudu/adt/format.h" |
10 | | #include "ocudu/asn1/nrppa/common.h" |
11 | | #include "ocudu/asn1/nrppa/nrppa_pdu_contents.h" |
12 | | #include "ocudu/ran/positioning/measurement_information.h" |
13 | | #include "ocudu/support/async/coroutine.h" |
14 | | #include "fmt/format.h" |
15 | | #include <variant> |
16 | | |
17 | | using namespace ocudu; |
18 | | using namespace ocucp; |
19 | | |
20 | | measurement_procedure::measurement_procedure(cu_cp_amf_index_t amf_index_, |
21 | | const measurement_request_t& request_, |
22 | | uint16_t transaction_id_, |
23 | | const nrppa_trp_registry& trp_registry_, |
24 | | nrppa_meas_context_list& meas_ctxt_list_, |
25 | | nrppa_du_context_list& du_ctxt_list_, |
26 | | nrppa_cu_cp_notifier& cu_cp_notifier_, |
27 | | ocudulog::basic_logger& logger_) : |
28 | 0 | amf_index(amf_index_), |
29 | 0 | meas_request(request_), |
30 | 0 | transaction_id(transaction_id_), |
31 | 0 | trp_registry(trp_registry_), |
32 | 0 | meas_ctxt_list(meas_ctxt_list_), |
33 | 0 | du_ctxt_list(du_ctxt_list_), |
34 | 0 | cu_cp_notifier(cu_cp_notifier_), |
35 | 0 | logger(logger_) |
36 | 0 | { |
37 | 0 | } |
38 | | |
39 | | void measurement_procedure::operator()(coro_context<async_task<void>>& ctx) |
40 | 0 | { |
41 | 0 | CORO_BEGIN(ctx); |
42 | |
|
43 | 0 | logger.info("\"{}\" started...", name()); |
44 | | |
45 | | // NOTE: create_measurement_context() must run first, as it allocates the RAN Meas ID that |
46 | | // prepare_du_measurement_information_requests() stamps onto every per-DU request. |
47 | 0 | if (!create_measurement_context() or !prepare_du_measurement_information_requests()) { |
48 | 0 | logger.warning("\"{}\" failed", name()); |
49 | | // Send failure to CU-CP. |
50 | 0 | send_ul_nrppa_pdu(logger, |
51 | 0 | cu_cp_notifier, |
52 | 0 | create_measurement_failure(nrppa_cause_protocol_t::msg_not_compatible_with_receiver_state), |
53 | 0 | "MeasResponse", |
54 | 0 | "MeasFailure", |
55 | 0 | amf_index); |
56 | 0 | CORO_EARLY_RETURN(); |
57 | 0 | } |
58 | | |
59 | | // TODO: use when_all. |
60 | 0 | for (du_request_it = du_meas_requests.begin(); du_request_it != du_meas_requests.end(); du_request_it++) { |
61 | 0 | sub_procedure_du_index = du_request_it->first; |
62 | 0 | sub_procedure_meas_request = du_request_it->second; |
63 | | // Send measurement request to DU. |
64 | 0 | CORO_AWAIT_VALUE( |
65 | 0 | du_meas_outcome, |
66 | 0 | du_ctxt_list[sub_procedure_du_index].f1ap->on_measurement_information_request(sub_procedure_meas_request)); |
67 | |
|
68 | 0 | handle_du_measurement_information_outcome(sub_procedure_du_index); |
69 | 0 | } |
70 | | |
71 | 0 | handle_procedure_outcome(); |
72 | |
|
73 | 0 | logger.info("\"{}\" finished successfully", name()); |
74 | |
|
75 | 0 | CORO_RETURN(); |
76 | 0 | } |
77 | | |
78 | | bool measurement_procedure::create_measurement_context() |
79 | 0 | { |
80 | | // Allocate RAN MEAS ID. |
81 | 0 | expected<ran_meas_id_t, std::string> ret = meas_ctxt_list.allocate_ran_meas_id(); |
82 | 0 | if (!ret.has_value()) { |
83 | 0 | logger.warning("lmf_meas_id={}: Couldn't allocate RAN meas ID. Cause: {}", |
84 | 0 | fmt::underlying(meas_request.lmf_meas_id), |
85 | 0 | ret.error()); |
86 | 0 | return false; |
87 | 0 | } |
88 | | |
89 | 0 | ran_meas_id = ret.value(); |
90 | |
|
91 | 0 | std::vector<trp_id_t> trp_list; |
92 | 0 | trp_list.reserve(meas_request.trp_meas_request_list.size()); |
93 | 0 | for (const auto& trp_meas_req_item : meas_request.trp_meas_request_list) { |
94 | 0 | trp_list.push_back(trp_meas_req_item.trp_id); |
95 | 0 | } |
96 | | |
97 | | // Create measurement context and store it. |
98 | 0 | meas_ctxt_list.add_measurement(amf_index, ran_meas_id, meas_request.lmf_meas_id, trp_list); |
99 | |
|
100 | 0 | return true; |
101 | 0 | } |
102 | | |
103 | | bool measurement_procedure::prepare_du_measurement_information_requests() |
104 | 0 | { |
105 | | // A TRP is addressed by its ID, which only the TRP Information Exchange procedure maps to a DU. |
106 | 0 | if (!trp_registry.has_trp_information()) { |
107 | 0 | logger.warning("lmf_meas_id={}: No TRP information available", fmt::underlying(meas_request.lmf_meas_id)); |
108 | 0 | return false; |
109 | 0 | } |
110 | | |
111 | 0 | for (const auto& trp_meas_req_item : meas_request.trp_meas_request_list) { |
112 | 0 | trp_id_t trp_id = trp_meas_req_item.trp_id; |
113 | 0 | if (std::optional<cu_cp_du_index_t> du_idx = trp_registry.find_du(trp_id); du_idx.has_value()) { |
114 | 0 | cu_cp_du_index_t du_index = du_idx.value(); |
115 | | // If the DU index is not found in the du_meas_requests map, create it. |
116 | 0 | if (du_meas_requests.find(du_index) == du_meas_requests.end()) { |
117 | 0 | measurement_request_t du_meas_request; |
118 | 0 | du_meas_request.lmf_meas_id = meas_request.lmf_meas_id; |
119 | 0 | du_meas_request.ran_meas_id = ran_meas_id; |
120 | 0 | du_meas_request.report_characteristics = meas_request.report_characteristics; |
121 | 0 | du_meas_request.meas_periodicity = meas_request.meas_periodicity; |
122 | 0 | du_meas_request.trp_meas_quantities = meas_request.trp_meas_quantities; |
123 | 0 | du_meas_request.sfn_initialization_time = meas_request.sfn_initialization_time; |
124 | 0 | du_meas_request.srs_config = meas_request.srs_config; |
125 | 0 | du_meas_request.meas_beam_info_request = meas_request.meas_beam_info_request; |
126 | 0 | du_meas_request.sys_frame_num = meas_request.sys_frame_num; |
127 | 0 | du_meas_request.slot_num = meas_request.slot_num; |
128 | 0 | du_meas_request.meas_periodicity_extended = meas_request.meas_periodicity_extended; |
129 | 0 | du_meas_request.resp_time = meas_request.resp_time; |
130 | 0 | du_meas_request.meas_characteristics_request_ind = meas_request.meas_characteristics_request_ind; |
131 | 0 | du_meas_request.meas_time_occasion = meas_request.meas_time_occasion; |
132 | 0 | du_meas_request.meas_amount = meas_request.meas_amount; |
133 | |
|
134 | 0 | du_meas_requests.emplace(du_index, du_meas_request); |
135 | 0 | } |
136 | |
|
137 | 0 | du_meas_requests.at(du_index).trp_meas_request_list.push_back(trp_meas_req_item); |
138 | 0 | } |
139 | 0 | } |
140 | |
|
141 | 0 | if (du_meas_requests.empty()) { |
142 | 0 | logger.warning("lmf_meas_id={}: No DU for TRP IDs found", fmt::underlying(meas_request.lmf_meas_id)); |
143 | 0 | return false; |
144 | 0 | } |
145 | | |
146 | 0 | return true; |
147 | 0 | } |
148 | | |
149 | | void measurement_procedure::handle_du_measurement_information_outcome(cu_cp_du_index_t du_index) |
150 | 0 | { |
151 | 0 | if (du_meas_outcome.has_value()) { |
152 | 0 | if (procedure_outcome.has_value()) { |
153 | | // Append result to the response message. |
154 | 0 | for (const auto& trp_meas_resp_item : du_meas_outcome.value().trp_meas_resp_list) { |
155 | 0 | procedure_outcome->trp_meas_resp_list.push_back(trp_meas_resp_item); |
156 | 0 | } |
157 | 0 | } else { |
158 | 0 | procedure_outcome = du_meas_outcome.value(); |
159 | 0 | } |
160 | 0 | } else { |
161 | 0 | logger.warning("Measurement Information Transfer Procedure failed for DU index={}", du_index); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | void measurement_procedure::handle_procedure_outcome() |
166 | 0 | { |
167 | 0 | if (!procedure_outcome.has_value()) { |
168 | 0 | meas_outcome = create_measurement_failure(nrppa_cause_radio_network_t::requested_item_not_supported); |
169 | 0 | logger.warning("\"{}\" failed", name()); |
170 | 0 | } else { |
171 | 0 | meas_outcome = create_measurement_response(); |
172 | 0 | logger.info("\"{}\" finished successfully", name()); |
173 | 0 | } |
174 | | |
175 | | // The measurement context only exists to correlate the DU response(s) with this one-shot query; release it now |
176 | | // that the procedure has completed, freeing up its RAN Meas ID for reuse. |
177 | 0 | meas_ctxt_list.remove_measurement_context(meas_request.lmf_meas_id); |
178 | | |
179 | | // Send response to CU-CP. |
180 | 0 | send_ul_nrppa_pdu(logger, cu_cp_notifier, meas_outcome, "MeasResponse", "MeasFailure", amf_index); |
181 | 0 | } |
182 | | |
183 | | asn1::nrppa::nr_ppa_pdu_c measurement_procedure::create_measurement_failure(nrppa_cause_t cause) const |
184 | 0 | { |
185 | 0 | asn1::nrppa::nr_ppa_pdu_c asn1_fail; |
186 | |
|
187 | 0 | asn1_fail.set_unsuccessful_outcome().load_info_obj(ASN1_NRPPA_ID_MEAS); |
188 | 0 | asn1_fail.unsuccessful_outcome().nrppatransaction_id = transaction_id; |
189 | 0 | asn1::nrppa::meas_fail_s& meas_init_fail = asn1_fail.unsuccessful_outcome().value.meas_fail(); |
190 | |
|
191 | 0 | meas_init_fail->lmf_meas_id = to_underlying(meas_request.lmf_meas_id); |
192 | 0 | meas_init_fail->cause = cause_to_asn1(cause); |
193 | |
|
194 | 0 | return asn1_fail; |
195 | 0 | } |
196 | | |
197 | | static inline asn1::nrppa::relative_path_delay_c |
198 | | relative_path_delay_to_asn1(const relative_path_delay_t& relative_path_delay) |
199 | 0 | { |
200 | 0 | asn1::nrppa::relative_path_delay_c asn1_relative_path_delay; |
201 | |
|
202 | 0 | if (relative_path_delay.type == relative_path_delay_t::type_t::k0) { |
203 | 0 | asn1_relative_path_delay.set_k0() = relative_path_delay.value; |
204 | 0 | } else if (relative_path_delay.type == relative_path_delay_t::type_t::k1) { |
205 | 0 | asn1_relative_path_delay.set_k1() = relative_path_delay.value; |
206 | 0 | } else if (relative_path_delay.type == relative_path_delay_t::type_t::k2) { |
207 | 0 | asn1_relative_path_delay.set_k2() = relative_path_delay.value; |
208 | 0 | } else if (relative_path_delay.type == relative_path_delay_t::type_t::k3) { |
209 | 0 | asn1_relative_path_delay.set_k3() = relative_path_delay.value; |
210 | 0 | } else if (relative_path_delay.type == relative_path_delay_t::type_t::k4) { |
211 | 0 | asn1_relative_path_delay.set_k4() = relative_path_delay.value; |
212 | 0 | } else { |
213 | 0 | asn1_relative_path_delay.set_k5() = relative_path_delay.value; |
214 | 0 | } |
215 | |
|
216 | 0 | return asn1_relative_path_delay; |
217 | 0 | } |
218 | | |
219 | | static inline asn1::nrppa::trp_meas_quality_c trp_meas_qualitiy_to_asn1(const trp_meas_quality_t& trp_meas_quality) |
220 | 0 | { |
221 | 0 | asn1::nrppa::trp_meas_quality_c asn1_trp_meas_quality; |
222 | |
|
223 | 0 | if (std::holds_alternative<trp_meas_timing_quality_t>(trp_meas_quality)) { |
224 | 0 | const trp_meas_timing_quality_t& trp_meas_timing_quality = std::get<trp_meas_timing_quality_t>(trp_meas_quality); |
225 | 0 | asn1::nrppa::trp_meas_timing_quality_s& asn1_trp_meas_timing_quality = |
226 | 0 | asn1_trp_meas_quality.set_timing_meas_quality(); |
227 | |
|
228 | 0 | asn1_trp_meas_timing_quality.meas_quality = trp_meas_timing_quality.meas_quality; |
229 | 0 | asn1_trp_meas_timing_quality.resolution = asn1::nrppa::trp_meas_timing_quality_s::resolution_opts::options( |
230 | 0 | (uint8_t)trp_meas_timing_quality.resolution.value); |
231 | 0 | } else { |
232 | 0 | const trp_meas_angle_quality_t& trp_meas_angle_quality = std::get<trp_meas_angle_quality_t>(trp_meas_quality); |
233 | 0 | asn1::nrppa::trp_meas_angle_quality_s& asn1_trp_meas_angle_quality = asn1_trp_meas_quality.set_angle_meas_quality(); |
234 | |
|
235 | 0 | asn1_trp_meas_angle_quality.azimuth_quality = trp_meas_angle_quality.azimuth_quality; |
236 | 0 | if (trp_meas_angle_quality.zenith_quality.has_value()) { |
237 | 0 | asn1_trp_meas_angle_quality.zenith_quality_present = true; |
238 | 0 | asn1_trp_meas_angle_quality.zenith_quality = trp_meas_angle_quality.zenith_quality.value(); |
239 | 0 | } |
240 | 0 | asn1_trp_meas_angle_quality.resolution = asn1::nrppa::trp_meas_angle_quality_s::resolution_opts::options( |
241 | 0 | (uint8_t)trp_meas_angle_quality.resolution.value); |
242 | 0 | } |
243 | |
|
244 | 0 | return asn1_trp_meas_quality; |
245 | 0 | } |
246 | | |
247 | | static asn1::nrppa::lcs_to_gcs_translation_s |
248 | | lcs_to_gcs_translation_to_asn1(const lcs_to_gcs_translation_t& lcs_to_gcs_translation) |
249 | 0 | { |
250 | 0 | asn1::nrppa::lcs_to_gcs_translation_s asn1_lcs_to_gcs_translation; |
251 | 0 | asn1_lcs_to_gcs_translation.alpha = lcs_to_gcs_translation.alpha; |
252 | 0 | asn1_lcs_to_gcs_translation.beta = lcs_to_gcs_translation.beta; |
253 | 0 | asn1_lcs_to_gcs_translation.gamma = lcs_to_gcs_translation.gamma; |
254 | 0 | return asn1_lcs_to_gcs_translation; |
255 | 0 | } |
256 | | |
257 | | static inline asn1::nrppa::multiple_ul_ao_a_item_c |
258 | | multiple_ul_aoa_item_to_asn1(const multiple_ul_aoa_item_t& multiple_ul_aoa_item) |
259 | 0 | { |
260 | 0 | asn1::nrppa::multiple_ul_ao_a_item_c asn1_multiple_ul_aoa_item; |
261 | 0 | if (std::holds_alternative<ul_angle_of_arrival_t>(multiple_ul_aoa_item)) { |
262 | 0 | const ul_angle_of_arrival_t& aoa = std::get<ul_angle_of_arrival_t>(multiple_ul_aoa_item); |
263 | 0 | asn1::nrppa::ul_ao_a_s& asn1_aoa = asn1_multiple_ul_aoa_item.set_ul_ao_a(); |
264 | 0 | asn1_aoa.azimuth_ao_a = aoa.azimuth_aoa; |
265 | 0 | if (aoa.zenith_aoa.has_value()) { |
266 | 0 | asn1_aoa.zenith_ao_a_present = true; |
267 | 0 | asn1_aoa.zenith_ao_a = aoa.zenith_aoa.value(); |
268 | 0 | } |
269 | 0 | if (aoa.lcs_to_gcs_translation.has_value()) { |
270 | 0 | asn1_aoa.lcs_to_gcs_translation_present = true; |
271 | 0 | asn1_aoa.lcs_to_gcs_translation.alpha = aoa.lcs_to_gcs_translation->alpha; |
272 | 0 | asn1_aoa.lcs_to_gcs_translation.beta = aoa.lcs_to_gcs_translation->beta; |
273 | 0 | asn1_aoa.lcs_to_gcs_translation.gamma = aoa.lcs_to_gcs_translation->gamma; |
274 | 0 | } |
275 | 0 | } else { |
276 | 0 | const zoa_t& zoa = std::get<zoa_t>(multiple_ul_aoa_item); |
277 | 0 | asn1::nrppa::zo_a_s& asn1_zoa = asn1_multiple_ul_aoa_item.set_ul_zo_a(); |
278 | 0 | asn1_zoa.zenith_ao_a = zoa.zenith_aoa; |
279 | 0 | if (zoa.lcs_to_gcs_translation.has_value()) { |
280 | 0 | asn1_zoa.lcs_to_gcs_translation_present = true; |
281 | 0 | asn1_zoa.lcs_to_gcs_translation.alpha = zoa.lcs_to_gcs_translation->alpha; |
282 | 0 | asn1_zoa.lcs_to_gcs_translation.beta = zoa.lcs_to_gcs_translation->beta; |
283 | 0 | asn1_zoa.lcs_to_gcs_translation.gamma = zoa.lcs_to_gcs_translation->gamma; |
284 | 0 | } |
285 | 0 | } |
286 | |
|
287 | 0 | return asn1_multiple_ul_aoa_item; |
288 | 0 | } |
289 | | |
290 | | static inline asn1::nrppa::add_path_list_item_s |
291 | | add_path_list_item_to_asn1(const add_path_list_item_t& add_path_list_item) |
292 | 0 | { |
293 | 0 | asn1::nrppa::add_path_list_item_s asn1_add_path_list_item; |
294 | | // Fill relative time of path. |
295 | 0 | asn1_add_path_list_item.relative_time_of_path = relative_path_delay_to_asn1(add_path_list_item.relative_time_of_path); |
296 | | |
297 | | // Fill path quality. |
298 | 0 | if (add_path_list_item.path_quality.has_value()) { |
299 | 0 | asn1_add_path_list_item.path_quality_present = true; |
300 | 0 | asn1_add_path_list_item.path_quality = trp_meas_qualitiy_to_asn1(add_path_list_item.path_quality.value()); |
301 | 0 | } |
302 | | |
303 | | // Fill IE exts. |
304 | 0 | if (!add_path_list_item.multiple_ul_aoa.empty()) { |
305 | 0 | asn1_add_path_list_item.ie_exts_present = true; |
306 | 0 | asn1_add_path_list_item.ie_exts.multiple_ul_ao_a_present = true; |
307 | 0 | for (const auto multiple_ul_aoa_item : add_path_list_item.multiple_ul_aoa) { |
308 | 0 | asn1_add_path_list_item.ie_exts.multiple_ul_ao_a.multiple_ul_ao_a.push_back( |
309 | 0 | multiple_ul_aoa_item_to_asn1(multiple_ul_aoa_item)); |
310 | 0 | } |
311 | 0 | } |
312 | |
|
313 | 0 | if (add_path_list_item.path_pwr.has_value()) { |
314 | 0 | asn1_add_path_list_item.ie_exts_present = true; |
315 | 0 | asn1_add_path_list_item.ie_exts.path_pwr_present = true; |
316 | 0 | asn1_add_path_list_item.ie_exts.path_pwr.first_path_rsrp_p = add_path_list_item.path_pwr->first_path_rsrp_pwr; |
317 | 0 | } |
318 | |
|
319 | 0 | return asn1_add_path_list_item; |
320 | 0 | } |
321 | | |
322 | | static inline asn1::nrppa::extended_add_path_list_item_s |
323 | | extended_add_path_list_item_to_asn1(const add_path_list_item_t& extended_add_path_list_item) |
324 | 0 | { |
325 | 0 | asn1::nrppa::extended_add_path_list_item_s asn1_extended_add_path_list_item; |
326 | | // Fill relative time of path. |
327 | 0 | asn1_extended_add_path_list_item.relative_time_of_path = |
328 | 0 | relative_path_delay_to_asn1(extended_add_path_list_item.relative_time_of_path); |
329 | | |
330 | | // Fill path quality. |
331 | 0 | if (extended_add_path_list_item.path_quality.has_value()) { |
332 | 0 | asn1_extended_add_path_list_item.path_quality_present = true; |
333 | 0 | asn1_extended_add_path_list_item.path_quality = |
334 | 0 | trp_meas_qualitiy_to_asn1(extended_add_path_list_item.path_quality.value()); |
335 | 0 | } |
336 | | |
337 | | // Fill Multiple UL AOA. |
338 | 0 | if (!extended_add_path_list_item.multiple_ul_aoa.empty()) { |
339 | 0 | asn1_extended_add_path_list_item.multiple_ul_ao_a_present = true; |
340 | 0 | for (const auto multiple_ul_aoa_item : extended_add_path_list_item.multiple_ul_aoa) { |
341 | 0 | asn1_extended_add_path_list_item.multiple_ul_ao_a.multiple_ul_ao_a.push_back( |
342 | 0 | multiple_ul_aoa_item_to_asn1(multiple_ul_aoa_item)); |
343 | 0 | } |
344 | 0 | } |
345 | |
|
346 | 0 | if (extended_add_path_list_item.path_pwr.has_value()) { |
347 | 0 | asn1_extended_add_path_list_item.path_pwr_present = true; |
348 | 0 | asn1_extended_add_path_list_item.path_pwr.first_path_rsrp_p = |
349 | 0 | extended_add_path_list_item.path_pwr->first_path_rsrp_pwr; |
350 | 0 | } |
351 | |
|
352 | 0 | return asn1_extended_add_path_list_item; |
353 | 0 | } |
354 | | |
355 | | asn1::nrppa::nr_ppa_pdu_c measurement_procedure::create_measurement_response() |
356 | 0 | { |
357 | 0 | asn1::nrppa::nr_ppa_pdu_c asn1_resp; |
358 | |
|
359 | 0 | asn1_resp.set_successful_outcome().load_info_obj(ASN1_NRPPA_ID_MEAS); |
360 | 0 | asn1_resp.successful_outcome().nrppatransaction_id = transaction_id; |
361 | |
|
362 | 0 | asn1::nrppa::meas_resp_s& asn1_meas_resp = asn1_resp.successful_outcome().value.meas_resp(); |
363 | |
|
364 | 0 | asn1_meas_resp->lmf_meas_id = to_underlying(procedure_outcome->lmf_meas_id); |
365 | 0 | asn1_meas_resp->ran_meas_id = to_underlying(ran_meas_id); |
366 | |
|
367 | 0 | if (!procedure_outcome->trp_meas_resp_list.empty()) { |
368 | 0 | asn1_meas_resp->trp_meas_resp_list_present = true; |
369 | |
|
370 | 0 | for (const auto& trp_measurement_response_item : procedure_outcome->trp_meas_resp_list) { |
371 | 0 | asn1::nrppa::trp_meas_resp_item_s asn1_trp_meas_resp_item; |
372 | 0 | asn1_trp_meas_resp_item.trp_id = to_underlying(trp_measurement_response_item.trp_id); |
373 | 0 | for (const auto& trp_meas_result_item : trp_measurement_response_item.meas_result) { |
374 | 0 | asn1::nrppa::trp_meas_result_item_s asn1_trp_meas_result_item; |
375 | | |
376 | | // Fill measured results value. |
377 | 0 | if (std::holds_alternative<ul_angle_of_arrival_t>(trp_meas_result_item.measured_results_value)) { |
378 | 0 | ul_angle_of_arrival_t ul_aoa = std::get<ul_angle_of_arrival_t>(trp_meas_result_item.measured_results_value); |
379 | 0 | asn1::nrppa::ul_ao_a_s& asn1_ul_aoa = |
380 | 0 | asn1_trp_meas_result_item.measured_results_value.set_ul_angle_of_arrival(); |
381 | 0 | asn1_ul_aoa.azimuth_ao_a = ul_aoa.azimuth_aoa; |
382 | 0 | if (ul_aoa.zenith_aoa.has_value()) { |
383 | 0 | asn1_ul_aoa.zenith_ao_a_present = true; |
384 | 0 | asn1_ul_aoa.zenith_ao_a = ul_aoa.zenith_aoa.value(); |
385 | 0 | } |
386 | 0 | if (ul_aoa.lcs_to_gcs_translation.has_value()) { |
387 | 0 | asn1_ul_aoa.lcs_to_gcs_translation_present = true; |
388 | 0 | asn1_ul_aoa.lcs_to_gcs_translation = lcs_to_gcs_translation_to_asn1(ul_aoa.lcs_to_gcs_translation.value()); |
389 | 0 | } |
390 | 0 | } else if (const auto* zoa = std::get_if<zoa_t>(&trp_meas_result_item.measured_results_value)) { |
391 | 0 | auto& asn1_ext = asn1_trp_meas_result_item.measured_results_value.set_choice_ext(); |
392 | 0 | asn1_ext->set(asn1::nrppa::trp_measured_results_value_ext_ies_o::value_c::types_opts::zo_a); |
393 | 0 | asn1::nrppa::zo_a_s& asn1_zoa = asn1_ext->zo_a(); |
394 | 0 | asn1_zoa.zenith_ao_a = zoa->zenith_aoa; |
395 | 0 | if (zoa->lcs_to_gcs_translation.has_value()) { |
396 | 0 | asn1_zoa.lcs_to_gcs_translation_present = true; |
397 | 0 | asn1_zoa.lcs_to_gcs_translation = lcs_to_gcs_translation_to_asn1(zoa->lcs_to_gcs_translation.value()); |
398 | 0 | } |
399 | 0 | } else if (std::holds_alternative<uint8_t>(trp_meas_result_item.measured_results_value)) { |
400 | 0 | asn1_trp_meas_result_item.measured_results_value.set_ul_srs_rsrp() = |
401 | 0 | std::get<uint8_t>(trp_meas_result_item.measured_results_value); |
402 | 0 | } else if (std::holds_alternative<ul_rtoa_t>(trp_meas_result_item.measured_results_value)) { |
403 | 0 | ul_rtoa_t ul_rtoa = std::get<ul_rtoa_t>(trp_meas_result_item.measured_results_value); |
404 | 0 | asn1::nrppa::ul_rtoa_measurement_s& asn1_ul_rtoa = |
405 | 0 | asn1_trp_meas_result_item.measured_results_value.set_ul_rtoa(); |
406 | | |
407 | | // Fill UL RTOA meas. |
408 | 0 | if (ul_rtoa.ul_rtoa_meas.type == ul_rtoa_meas_t::type_t::k0) { |
409 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k0() = ul_rtoa.ul_rtoa_meas.value; |
410 | 0 | } else if (ul_rtoa.ul_rtoa_meas.type == ul_rtoa_meas_t::type_t::k1) { |
411 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k1() = ul_rtoa.ul_rtoa_meas.value; |
412 | 0 | } else if (ul_rtoa.ul_rtoa_meas.type == ul_rtoa_meas_t::type_t::k2) { |
413 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k2() = ul_rtoa.ul_rtoa_meas.value; |
414 | 0 | } else if (ul_rtoa.ul_rtoa_meas.type == ul_rtoa_meas_t::type_t::k3) { |
415 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k3() = ul_rtoa.ul_rtoa_meas.value; |
416 | 0 | } else if (ul_rtoa.ul_rtoa_meas.type == ul_rtoa_meas_t::type_t::k4) { |
417 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k4() = ul_rtoa.ul_rtoa_meas.value; |
418 | 0 | } else { |
419 | 0 | asn1_ul_rtoa.ul_rto_ameas.set_k5() = (uint16_t)ul_rtoa.ul_rtoa_meas.value; |
420 | 0 | } |
421 | | // Fill add path list. |
422 | 0 | for (const auto& add_path_list_item : ul_rtoa.add_path_list) { |
423 | 0 | asn1_ul_rtoa.add_path_list.push_back(add_path_list_item_to_asn1(add_path_list_item)); |
424 | 0 | } |
425 | | // Fill extended add path list. |
426 | 0 | if (!ul_rtoa.extended_add_path_list.empty()) { |
427 | 0 | asn1_ul_rtoa.ie_exts_present = true; |
428 | 0 | asn1_ul_rtoa.ie_exts.extended_add_path_list_present = true; |
429 | 0 | for (const auto& extended_add_path_list_item : ul_rtoa.extended_add_path_list) { |
430 | 0 | asn1_ul_rtoa.ie_exts.extended_add_path_list.push_back( |
431 | 0 | extended_add_path_list_item_to_asn1(extended_add_path_list_item)); |
432 | 0 | } |
433 | 0 | } |
434 | | // Fill TRP RX reg info. |
435 | 0 | if (ul_rtoa.trp_rx_teg_info.has_value()) { |
436 | 0 | asn1_ul_rtoa.ie_exts_present = true; |
437 | 0 | asn1_ul_rtoa.ie_exts.trp_rx_teg_info_present = true; |
438 | 0 | asn1_ul_rtoa.ie_exts.trp_rx_teg_info.trp_rx_teg_id = ul_rtoa.trp_rx_teg_info->trp_rx_teg_id; |
439 | 0 | asn1::number_to_enum(asn1_ul_rtoa.ie_exts.trp_rx_teg_info.trp_rx_timing_error_margin, |
440 | 0 | ul_rtoa.trp_rx_teg_info->trp_rx_timing_error_margin); |
441 | 0 | } |
442 | 0 | } else { |
443 | 0 | gnb_rx_tx_time_diff_t rx_tx_time_diff = |
444 | 0 | std::get<gnb_rx_tx_time_diff_t>(trp_meas_result_item.measured_results_value); |
445 | 0 | asn1::nrppa::gnb_rx_tx_time_diff_s& asn1_rx_tx_time_diff = |
446 | 0 | asn1_trp_meas_result_item.measured_results_value.set_gnb_rx_tx_time_diff(); |
447 | | |
448 | | // Fill RX TX time diff. |
449 | 0 | if (rx_tx_time_diff.rx_tx_time_diff.type == gnb_rx_tx_time_diff_meas_t::type_t::k0) { |
450 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k0() = rx_tx_time_diff.rx_tx_time_diff.value; |
451 | 0 | } else if (rx_tx_time_diff.rx_tx_time_diff.type == gnb_rx_tx_time_diff_meas_t::type_t::k1) { |
452 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k1() = rx_tx_time_diff.rx_tx_time_diff.value; |
453 | 0 | } else if (rx_tx_time_diff.rx_tx_time_diff.type == gnb_rx_tx_time_diff_meas_t::type_t::k2) { |
454 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k2() = rx_tx_time_diff.rx_tx_time_diff.value; |
455 | 0 | } else if (rx_tx_time_diff.rx_tx_time_diff.type == gnb_rx_tx_time_diff_meas_t::type_t::k3) { |
456 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k3() = rx_tx_time_diff.rx_tx_time_diff.value; |
457 | 0 | } else if (rx_tx_time_diff.rx_tx_time_diff.type == gnb_rx_tx_time_diff_meas_t::type_t::k4) { |
458 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k4() = rx_tx_time_diff.rx_tx_time_diff.value; |
459 | 0 | } else { |
460 | 0 | asn1_rx_tx_time_diff.rx_tx_time_diff.set_k5() = (uint16_t)rx_tx_time_diff.rx_tx_time_diff.value; |
461 | 0 | } |
462 | | // Fill add path list. |
463 | 0 | for (const auto& add_path_list_item : rx_tx_time_diff.add_path_list) { |
464 | 0 | asn1_rx_tx_time_diff.add_path_list.push_back(add_path_list_item_to_asn1(add_path_list_item)); |
465 | 0 | } |
466 | | // Fill extended add path list. |
467 | 0 | if (!rx_tx_time_diff.extended_add_path_list.empty()) { |
468 | 0 | asn1_rx_tx_time_diff.ie_exts_present = true; |
469 | 0 | asn1_rx_tx_time_diff.ie_exts.extended_add_path_list_present = true; |
470 | 0 | for (const auto& extended_add_path_list_item : rx_tx_time_diff.extended_add_path_list) { |
471 | 0 | asn1_rx_tx_time_diff.ie_exts.extended_add_path_list.push_back( |
472 | 0 | extended_add_path_list_item_to_asn1(extended_add_path_list_item)); |
473 | 0 | } |
474 | 0 | } |
475 | | // Fill TRP TEG info. |
476 | 0 | if (rx_tx_time_diff.trp_teg_info.has_value()) { |
477 | 0 | asn1_rx_tx_time_diff.ie_exts_present = true; |
478 | 0 | asn1_rx_tx_time_diff.ie_exts.trpteg_info_present = true; |
479 | 0 | if (std::holds_alternative<rx_tx_teg_t>(rx_tx_time_diff.trp_teg_info.value())) { |
480 | 0 | const rx_tx_teg_t& rx_tx_teg = std::get<rx_tx_teg_t>(rx_tx_time_diff.trp_teg_info.value()); |
481 | 0 | asn1::nrppa::rx_tx_teg_s& asn1_rx_tx_teg = asn1_rx_tx_time_diff.ie_exts.trpteg_info.set_rx_tx_teg(); |
482 | 0 | asn1_rx_tx_teg.trp_rx_tx_teg_info.trp_rx_tx_teg_id = rx_tx_teg.trp_rx_tx_teg_info.trp_rx_tx_teg_id; |
483 | 0 | asn1_rx_tx_teg.trp_rx_tx_teg_info.trp_rx_tx_timing_error_margin = |
484 | 0 | asn1::nrppa::rx_tx_timing_error_margin_opts::options( |
485 | 0 | (uint8_t)rx_tx_teg.trp_rx_tx_teg_info.trp_rx_tx_timing_error_margin.value); |
486 | 0 | if (rx_tx_teg.trp_tx_teg_info.has_value()) { |
487 | 0 | asn1_rx_tx_teg.trp_tx_teg_info_present = true; |
488 | 0 | asn1_rx_tx_teg.trp_tx_teg_info.trp_tx_teg_id = rx_tx_teg.trp_tx_teg_info->trp_tx_teg_id; |
489 | 0 | asn1::number_to_enum(asn1_rx_tx_teg.trp_tx_teg_info.trp_tx_timing_error_margin, |
490 | 0 | rx_tx_teg.trp_tx_teg_info->trp_tx_timing_error_margin); |
491 | 0 | } |
492 | 0 | } else { |
493 | 0 | const rx_teg_t& rx_teg = std::get<rx_teg_t>(rx_tx_time_diff.trp_teg_info.value()); |
494 | 0 | asn1::nrppa::rx_teg_s& asn1_rx_teg = asn1_rx_tx_time_diff.ie_exts.trpteg_info.set_rx_teg(); |
495 | 0 | asn1_rx_teg.trp_rx_teg_info.trp_rx_teg_id = rx_teg.trp_rx_teg_info.trp_rx_teg_id; |
496 | 0 | asn1::number_to_enum(asn1_rx_teg.trp_rx_teg_info.trp_rx_timing_error_margin, |
497 | 0 | rx_teg.trp_rx_teg_info.trp_rx_timing_error_margin); |
498 | 0 | asn1_rx_teg.trp_tx_teg_info.trp_tx_teg_id = rx_teg.trp_tx_teg_info.trp_tx_teg_id; |
499 | 0 | asn1::number_to_enum(asn1_rx_teg.trp_tx_teg_info.trp_tx_timing_error_margin, |
500 | 0 | rx_teg.trp_tx_teg_info.trp_tx_timing_error_margin); |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | // Fill time stamp. |
506 | 0 | asn1_trp_meas_result_item.time_stamp.sys_frame_num = trp_meas_result_item.time_stamp.sys_frame_num; |
507 | 0 | if (trp_meas_result_item.time_stamp.slot_idx.type == time_stamp_slot_idx_t::idx_type::scs15) { |
508 | 0 | asn1_trp_meas_result_item.time_stamp.slot_idx.set_scs_15() = trp_meas_result_item.time_stamp.slot_idx.value; |
509 | 0 | } else if (trp_meas_result_item.time_stamp.slot_idx.type == time_stamp_slot_idx_t::idx_type::scs30) { |
510 | 0 | asn1_trp_meas_result_item.time_stamp.slot_idx.set_scs_30() = trp_meas_result_item.time_stamp.slot_idx.value; |
511 | 0 | } else if (trp_meas_result_item.time_stamp.slot_idx.type == time_stamp_slot_idx_t::idx_type::scs60) { |
512 | 0 | asn1_trp_meas_result_item.time_stamp.slot_idx.set_scs_60() = trp_meas_result_item.time_stamp.slot_idx.value; |
513 | 0 | } else { |
514 | 0 | asn1_trp_meas_result_item.time_stamp.slot_idx.set_scs_120() = trp_meas_result_item.time_stamp.slot_idx.value; |
515 | 0 | } |
516 | 0 | if (trp_meas_result_item.time_stamp.meas_time.has_value()) { |
517 | 0 | asn1_trp_meas_result_item.time_stamp.meas_time_present = true; |
518 | 0 | asn1_trp_meas_result_item.time_stamp.meas_time.from_number(trp_meas_result_item.time_stamp.meas_time.value()); |
519 | 0 | } |
520 | | |
521 | | // Fill meas quality. |
522 | 0 | if (trp_meas_result_item.meas_quality.has_value()) { |
523 | 0 | asn1_trp_meas_result_item.meas_quality_present = true; |
524 | 0 | asn1_trp_meas_result_item.meas_quality = trp_meas_qualitiy_to_asn1(trp_meas_result_item.meas_quality.value()); |
525 | 0 | } |
526 | | |
527 | | // Fill meas beam info. |
528 | 0 | if (trp_meas_result_item.meas_beam_info.has_value()) { |
529 | 0 | asn1_trp_meas_result_item.meas_beam_info_present = true; |
530 | 0 | if (trp_meas_result_item.meas_beam_info->prs_res_id.has_value()) { |
531 | 0 | asn1_trp_meas_result_item.meas_beam_info.prs_res_id_present = true; |
532 | 0 | asn1_trp_meas_result_item.meas_beam_info.prs_res_id = |
533 | 0 | trp_meas_result_item.meas_beam_info->prs_res_id.value(); |
534 | 0 | } |
535 | 0 | if (trp_meas_result_item.meas_beam_info->prs_res_set_id.has_value()) { |
536 | 0 | asn1_trp_meas_result_item.meas_beam_info.prs_res_set_id_present = true; |
537 | 0 | asn1_trp_meas_result_item.meas_beam_info.prs_res_set_id = |
538 | 0 | trp_meas_result_item.meas_beam_info->prs_res_set_id.value(); |
539 | 0 | } |
540 | 0 | if (trp_meas_result_item.meas_beam_info->ssb_idx.has_value()) { |
541 | 0 | asn1_trp_meas_result_item.meas_beam_info.ssb_idx_present = true; |
542 | 0 | asn1_trp_meas_result_item.meas_beam_info.ssb_idx = trp_meas_result_item.meas_beam_info->ssb_idx.value(); |
543 | 0 | } |
544 | 0 | } |
545 | |
|
546 | 0 | asn1_trp_meas_resp_item.meas_result.push_back(asn1_trp_meas_result_item); |
547 | 0 | } |
548 | |
|
549 | 0 | if (trp_measurement_response_item.cgi_nr.has_value()) { |
550 | 0 | asn1::protocol_ext_field_s<asn1::nrppa::trp_meas_resp_item_ext_ies_o> asn1_ie_exts_container; |
551 | 0 | asn1_ie_exts_container->cell_id().nr_cell_id.from_number(trp_measurement_response_item.cgi_nr->nci.value()); |
552 | 0 | asn1_ie_exts_container->cell_id().plmn_id = trp_measurement_response_item.cgi_nr->plmn_id.to_bytes(); |
553 | 0 | asn1_trp_meas_resp_item.ie_exts.push_back(asn1_ie_exts_container); |
554 | 0 | } |
555 | |
|
556 | 0 | asn1_meas_resp->trp_meas_resp_list.push_back(asn1_trp_meas_resp_item); |
557 | 0 | } |
558 | 0 | } |
559 | |
|
560 | 0 | return asn1_resp; |
561 | 0 | } |