1010
1111#include " pucch_collision_manager.h"
1212#include " ../support/pucch/pucch_default_resource.h"
13+ #include " srsran/adt/bounded_bitset.h"
14+ #include " srsran/adt/static_vector.h"
1315#include " srsran/ran/pucch/pucch_configuration.h"
1416#include " srsran/ran/pucch/pucch_constants.h"
1517#include " srsran/ran/pucch/pucch_mapping.h"
1921
2022using namespace srsran ;
2123
22- namespace {
23-
24- // / Represents the time-frequency allocation of a PUCCH resource.
25- struct time_freq_grants {
26- prb_interval prbs1;
27- ofdm_symbol_range symbols1;
28- prb_interval prbs2;
29- ofdm_symbol_range symbols2;
30-
31- // / Constructor from a dedicated PUCCH resource.
32- time_freq_grants (const pucch_resource& res)
33- {
34- unsigned nof_prbs = 1 ;
35- if (const auto * format_2_3 = std::get_if<pucch_format_2_3_cfg>(&res.format_params )) {
36- nof_prbs = format_2_3->nof_prbs ;
37- }
38-
39- if (res.second_hop_prb .has_value ()) {
40- prbs1 = {res.starting_prb , res.starting_prb + nof_prbs};
41- symbols1 = {res.starting_sym_idx , res.starting_sym_idx + res.nof_symbols / 2 };
42- prbs2 = {res.second_hop_prb .value (), res.second_hop_prb .value () + nof_prbs};
43- symbols2 = {res.starting_sym_idx + res.nof_symbols / 2 , res.starting_sym_idx + res.nof_symbols };
44- } else {
45- prbs1 = {res.starting_prb , res.starting_prb + nof_prbs};
46- symbols1 = {res.starting_sym_idx , res.starting_sym_idx + res.nof_symbols };
47- prbs2 = prb_interval ();
48- symbols2 = ofdm_symbol_range ();
49- }
50- }
51-
52- // / Constructor from a common PUCCH resource.
53- time_freq_grants (const pucch_default_resource& res, unsigned r_pucch, unsigned size_ul_bwp)
54- {
55- // Compute PRB_first_hop and PRB_second_hop as per Section 9.2.1, TS 38.213.
56- auto prbs = get_pucch_default_prb_index (r_pucch, res.rb_bwp_offset , res.cs_indexes .size (), size_ul_bwp);
57-
58- prbs1 = {prbs.first , prbs.first + pucch_constants::FORMAT0_1_4_MAX_NPRB};
59- symbols1 = {res.first_symbol_index , res.first_symbol_index + res.nof_symbols / 2 };
60- prbs2 = {prbs.second , prbs.second + pucch_constants::FORMAT0_1_4_MAX_NPRB};
61- symbols2 = {res.first_symbol_index + res.nof_symbols / 2 , res.first_symbol_index + res.nof_symbols };
62- }
63-
64- bool overlaps (const time_freq_grants& other) const
65- {
66- // Check overlap between this' first hop and other's first hop.
67- bool ret = symbols1.overlaps (other.symbols1 ) and prbs1.overlaps (other.prbs1 );
68- // Check overlap between this' first hop and other's second hop.
69- ret |= symbols1.overlaps (other.symbols2 ) and prbs1.overlaps (other.prbs2 );
70- // Check overlap between this' second hop and other's first hop.
71- ret |= symbols2.overlaps (other.symbols1 ) and prbs2.overlaps (other.prbs1 );
72- // Check overlap between this' second hop and other's second hop.
73- ret |= symbols2.overlaps (other.symbols2 ) and prbs2.overlaps (other.prbs2 );
74- return ret;
75- }
76-
77- bool operator ==(const time_freq_grants& other) const
78- {
79- return symbols1 == other.symbols1 and prbs1 == other.prbs1 and symbols2 == other.symbols2 and prbs2 == other.prbs2 ;
80- }
81-
82- bool operator !=(const time_freq_grants& other) const { return not (*this == other); }
83- };
84-
85- // / Represents the relevant information of a PUCCH resource for collision checking.
86- struct resource_info {
87- // / Time-frequency grants of the resource.
88- time_freq_grants grants;
89- // / PUCCH format of the resource.
90- pucch_format format;
91- // / Multiplexing index of the resource. Resources with different multiplexing indices are orthogonal and do not
92- // / collide. It is computed from different parameters depending on the format:
93- // / - Format 0: initial cyclic shift.
94- // / - Format 1: initial cyclic shift, time domain OCC index.
95- // / - Format 2/3: not multiplexed (always 0).
96- // / - Format 4: OCC index.
97- unsigned multiplexing_index;
98-
99- // / Constructor from a dedicated PUCCH resource.
100- resource_info (const pucch_resource& res) : grants(res), format(res.format)
101- {
102- switch (res.format ) {
103- case pucch_format::FORMAT_0: {
104- const auto & f0_params = std::get<pucch_format_0_cfg>(res.format_params );
105- multiplexing_index = f0_params.initial_cyclic_shift ;
106- } break ;
107- case pucch_format::FORMAT_1: {
108- // For PUCCH Format 1, two sequences are orthogonal unless both the initial cyclic shift and the time domain OCC
109- // index are the same.
110- const auto & f1_params = std::get<pucch_format_1_cfg>(res.format_params );
111- multiplexing_index = f1_params.initial_cyclic_shift +
112- f1_params.time_domain_occ * pucch_constants::format1_initial_cyclic_shift_range.length ();
113- } break ;
114- case pucch_format::FORMAT_4: {
115- // For PUCCH Format 4, the OCC index is mapped to a cyclic shift value, as per Table 6.4.1.3.3.1-1, TS 38.211.
116- // Thus, resources with different OCC indices will never collide, even if they have different OCC lengths.
117- // Therefore, we can use the OCC index directly as the multiplexing index.
118- const auto & f4_params = std::get<pucch_format_4_cfg>(res.format_params );
119- multiplexing_index = static_cast <unsigned >(f4_params.occ_index );
120- } break ;
121- default :
122- // Non multiplexed formats.
123- multiplexing_index = 0 ;
124- break ;
125- }
126- }
127-
128- // / Constructor from a common PUCCH resource.
129- resource_info (const pucch_default_resource& res, unsigned r_pucch, unsigned size_ul_bwp) :
130- grants (res, r_pucch, size_ul_bwp),
131- format (res.format),
132- multiplexing_index(res.cs_indexes[get_pucch_default_cyclic_shift(r_pucch, res.cs_indexes.size())])
133- {
134- }
135- };
136-
137- // / \brief Represents a multiplexing region of PUCCH resources.
138- // / Contains parameters that all resources in the region have in common.
139- struct mux_region {
140- // / Time-frequency grants of the region.
141- time_freq_grants grants;
142- // / PUCCH format of the region.
143- pucch_format format;
144-
145- // / Check if a a given resource belongs to this multiplexing region.
146- bool does_resource_belong (const resource_info& res) const { return res.format == format and res.grants == grants; }
147- };
148-
149- } // namespace
150-
151- // / Collects all PUCCH resources (common + dedicated) from the cell configuration.
152- static static_vector<resource_info, pucch_collision_manager::max_nof_cell_resources>
153- get_all_resources (const cell_configuration& cell_cfg)
24+ // / Constructs resource_info for a common PUCCH resource.
25+ static detail::resource_info
26+ make_common_resource_info (const pucch_default_resource& res, unsigned r_pucch, const bwp_configuration& bwp_cfg)
15427{
155- // Get the parameter N_bwp_size, which is the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1.
156- const unsigned size_ul_bwp = cell_cfg.ul_cfg_common .init_ul_bwp .generic_params .crbs .length ();
28+ // Compute PRB_first_hop and PRB_second_hop as per Section 9.2.1, TS 38.213.
29+ auto prbs = get_pucch_default_prb_index (r_pucch, res.rb_bwp_offset , res.cs_indexes .size (), bwp_cfg.crbs .length ());
30+
31+ return detail::resource_info{
32+ .format = res.format ,
33+ .multiplexing_index = res.cs_indexes [get_pucch_default_cyclic_shift (r_pucch, res.cs_indexes .size ())],
34+ .grants = {
35+ .first_hop = grant_info (
36+ bwp_cfg.scs ,
37+ {res.first_symbol_index , res.first_symbol_index + res.nof_symbols / 2 },
38+ prb_to_crb (bwp_cfg, prb_interval::start_and_len (prbs.first , pucch_constants::FORMAT0_1_4_MAX_NPRB))),
39+ .second_hop = grant_info (
40+ bwp_cfg.scs ,
41+ {res.first_symbol_index + res.nof_symbols / 2 , res.first_symbol_index + res.nof_symbols },
42+ prb_to_crb (bwp_cfg, prb_interval::start_and_len (prbs.second , pucch_constants::FORMAT0_1_4_MAX_NPRB))),
43+ }};
44+ }
15745
158- // Get PUCCH common resource config from Table 9.2.1-1, TS 38.213.
159- const pucch_default_resource common_default_res = get_pucch_default_resource (
160- cell_cfg.ul_cfg_common .init_ul_bwp .pucch_cfg_common ->pucch_resource_common , size_ul_bwp);
46+ // / Constructs resource_info for a dedicated PUCCH resource.
47+ static detail::resource_info make_ded_resource_info (const pucch_resource& res, const bwp_configuration& bwp_cfg)
48+ {
49+ detail::resource_info info{.format = res.format };
50+
51+ // Compute multiplexing index.
52+ switch (res.format ) {
53+ case pucch_format::FORMAT_0: {
54+ const auto & f0_params = std::get<pucch_format_0_cfg>(res.format_params );
55+ info.multiplexing_index = f0_params.initial_cyclic_shift ;
56+ } break ;
57+ case pucch_format::FORMAT_1: {
58+ // For PUCCH Format 1, two sequences are orthogonal unless both the initial cyclic shift and the time domain OCC
59+ // index are the same.
60+ const auto & f1_params = std::get<pucch_format_1_cfg>(res.format_params );
61+ info.multiplexing_index =
62+ f1_params.initial_cyclic_shift +
63+ f1_params.time_domain_occ * pucch_constants::format1_initial_cyclic_shift_range.length ();
64+ } break ;
65+ case pucch_format::FORMAT_4: {
66+ // For PUCCH Format 4, the OCC index is mapped to a cyclic shift value, as per Table 6.4.1.3.3.1-1, TS 38.211.
67+ // Thus, resources with different OCC indices will never collide, even if they have different OCC lengths.
68+ // Therefore, we can use the OCC index directly as the multiplexing index.
69+ const auto & f4_params = std::get<pucch_format_4_cfg>(res.format_params );
70+ info.multiplexing_index = static_cast <unsigned >(f4_params.occ_index );
71+ } break ;
72+ default :
73+ // Non multiplexed formats.
74+ info.multiplexing_index = 0 ;
75+ break ;
76+ }
16177
162- // Collect all resources (common + dedicated) .
163- static_vector<resource_info, pucch_collision_manager::max_nof_cell_resources> all_resources ;
164- for ( unsigned r_pucch = 0 ; r_pucch != pucch_collision_manager::nof_common_res; ++r_pucch ) {
165- all_resources. push_back ( resource_info (common_default_res, r_pucch, size_ul_bwp)) ;
78+ // Compute time-frequency grants .
79+ unsigned nof_prbs = 1 ;
80+ if ( const auto * format_2_3 = std::get_if<pucch_format_2_3_cfg>(&res. format_params ) ) {
81+ nof_prbs = format_2_3-> nof_prbs ;
16682 }
167- for (const auto & res : cell_cfg.ded_pucch_resources ) {
168- all_resources.push_back (resource_info (res));
83+ if (res.second_hop_prb .has_value ()) {
84+ // Intra-slot frequency hopping.
85+ info.grants = {
86+ .first_hop = grant_info{bwp_cfg.scs ,
87+ {res.starting_sym_idx , res.starting_sym_idx + res.nof_symbols / 2 },
88+ prb_to_crb (bwp_cfg, prb_interval::start_and_len (res.starting_prb , nof_prbs))},
89+ .second_hop =
90+ grant_info{bwp_cfg.scs ,
91+ {res.starting_sym_idx + res.nof_symbols / 2 , res.starting_sym_idx + res.nof_symbols },
92+ prb_to_crb (bwp_cfg, prb_interval::start_and_len (res.second_hop_prb .value (), nof_prbs))}};
93+ } else {
94+ // No intra-slot frequency hopping.
95+ info.grants = {
96+ .first_hop = grant_info{bwp_cfg.scs ,
97+ ofdm_symbol_range::start_and_len (res.starting_sym_idx , res.nof_symbols ),
98+ prb_to_crb (bwp_cfg, prb_interval::start_and_len (res.starting_prb , nof_prbs))},
99+ .second_hop = std::nullopt ,
100+ };
169101 }
170102
171- return all_resources ;
103+ return info ;
172104}
173105
174106// / Checks if two PUCCH resources collide.
175- static bool do_resources_collide (const resource_info& res1, const resource_info& res2)
107+ static bool do_resources_collide (const detail:: resource_info& res1, const detail:: resource_info& res2)
176108{
177109 if (not res1.grants .overlaps (res2.grants )) {
178110 // Resources that do not overlap in time and frequency do not collide.
@@ -194,11 +126,31 @@ static bool do_resources_collide(const resource_info& res1, const resource_info&
194126 return res1.multiplexing_index == res2.multiplexing_index ;
195127}
196128
129+ namespace {
130+
131+ // / \brief Represents a multiplexing region of PUCCH resources.
132+ // / Contains parameters that all resources in the region have in common.
133+ struct mux_region {
134+ // / Time-frequency grants of the region.
135+ detail::pucch_grants grants;
136+ // / PUCCH format of the region.
137+ pucch_format format;
138+
139+ // / Check if a a given resource belongs to this multiplexing region.
140+ bool does_resource_belong (const detail::resource_info& res) const
141+ {
142+ return res.format == format and res.grants == grants;
143+ }
144+ };
145+
146+ } // namespace
147+
197148pucch_collision_manager::pucch_collision_manager (const cell_configuration& cell_cfg_) :
198149 cell_cfg(cell_cfg_),
199- collision_matrix(compute_collisions(cell_cfg)),
200- mux_matrix(compute_mux_regions(cell_cfg)),
201- slots_ctx({bounded_bitset<max_nof_cell_resources>(nof_common_res + cell_cfg.ded_pucch_resources .size ())})
150+ resources(compute_resources(cell_cfg)),
151+ collision_matrix(compute_collisions(resources)),
152+ mux_matrix(compute_mux_regions(resources)),
153+ slots_ctx({bounded_bitset<max_nof_cell_resources>(resources.size ())})
202154{
203155}
204156
@@ -307,23 +259,41 @@ void pucch_collision_manager::free_ded(slot_point sl, unsigned cell_res_id)
307259 ctx.current_state .reset (nof_common_res + cell_res_id);
308260}
309261
310- pucch_collision_manager:: collision_matrix_t
311- pucch_collision_manager::compute_collisions (const cell_configuration& cell_cfg)
262+ // / Collects all PUCCH resources (common + dedicated) from the cell configuration.
263+ pucch_collision_manager::cell_resources_t pucch_collision_manager::compute_resources (const cell_configuration& cell_cfg)
312264{
313- const unsigned nof_res = nof_common_res + cell_cfg.ded_pucch_resources .size ();
314- collision_matrix_t matrix (nof_res, bounded_bitset<max_nof_cell_resources>(nof_res));
265+ const auto & init_ul_bwp_cfg = cell_cfg.ul_cfg_common .init_ul_bwp .generic_params ;
266+
267+ // Get PUCCH common resource config from Table 9.2.1-1, TS 38.213.
268+ // N_bwp_size is equal to the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1.
269+ const pucch_default_resource common_default_res = get_pucch_default_resource (
270+ cell_cfg.ul_cfg_common .init_ul_bwp .pucch_cfg_common ->pucch_resource_common , init_ul_bwp_cfg.crbs .length ());
315271
316272 // Collect all resources (common + dedicated).
317- static_vector<resource_info, max_nof_cell_resources> all_resources = get_all_resources (cell_cfg);
273+ cell_resources_t all_resources;
274+ for (unsigned r_pucch = 0 ; r_pucch != nof_common_res; ++r_pucch) {
275+ all_resources.push_back (make_common_resource_info (common_default_res, r_pucch, init_ul_bwp_cfg));
276+ }
277+ for (const auto & res : cell_cfg.ded_pucch_resources ) {
278+ all_resources.push_back (make_ded_resource_info (res, init_ul_bwp_cfg));
279+ }
280+
281+ return all_resources;
282+ }
283+
284+ pucch_collision_manager::collision_matrix_t
285+ pucch_collision_manager::compute_collisions (span<const detail::resource_info> resources)
286+ {
287+ collision_matrix_t matrix (resources.size (), bounded_bitset<max_nof_cell_resources>(resources.size ()));
318288
319289 // Precompute the collision matrix.
320- for (size_t i = 0 ; i != nof_res ; ++i) {
290+ for (size_t i = 0 ; i != resources. size () ; ++i) {
321291 // A resource always collides with itself.
322292 matrix[i].set (i);
323293
324294 // Note: The collision matrix is symmetric.
325- for (size_t j = i + 1 ; j != nof_res ; ++j) {
326- if (do_resources_collide (all_resources [i], all_resources [j])) {
295+ for (size_t j = i + 1 ; j != resources. size () ; ++j) {
296+ if (do_resources_collide (resources [i], resources [j])) {
327297 matrix[i].set (j);
328298 matrix[j].set (i);
329299 }
@@ -334,23 +304,17 @@ pucch_collision_manager::compute_collisions(const cell_configuration& cell_cfg)
334304}
335305
336306pucch_collision_manager::mux_regions_matrix_t
337- pucch_collision_manager::compute_mux_regions (const cell_configuration& cell_cfg )
307+ pucch_collision_manager::compute_mux_regions (span< const detail::resource_info> resources )
338308{
339- unsigned nof_res = nof_common_res + cell_cfg.ded_pucch_resources .size ();
340- mux_regions_matrix_t mux_regions;
341-
342- // Collect all resources (common + dedicated).
343- static_vector<resource_info, max_nof_cell_resources> all_resources = get_all_resources (cell_cfg);
344-
345309 // Helper structure to keep track of multiplexing regions and their members.
346310 struct region_record {
347311 mux_region region;
348312 bounded_bitset<max_nof_cell_resources> members;
349313 };
350314 static_vector<region_record, max_nof_cell_resources> tmp_regions;
351315
352- for (size_t i = 0 ; i != nof_res ; ++i) {
353- const auto & res = all_resources [i];
316+ for (size_t i = 0 ; i != resources. size () ; ++i) {
317+ const auto & res = resources [i];
354318
355319 // Find if the resource belongs to an existing multiplexing region.
356320 auto * region_it = std::find_if (tmp_regions.begin (), tmp_regions.end (), [&res](const region_record& record) {
@@ -363,21 +327,21 @@ pucch_collision_manager::compute_mux_regions(const cell_configuration& cell_cfg)
363327 .grants = res.grants ,
364328 .format = res.format ,
365329 },
366- bounded_bitset<max_nof_cell_resources>(nof_res )});
330+ bounded_bitset<max_nof_cell_resources>(resources. size () )});
367331 }
368332
369333 // Add the resource to the multiplexing region.
370334 region_it->members .set (i);
371335 }
372336
373- // Return only multiplexing regions with more than one resource.
337+ mux_regions_matrix_t mux_regions;
374338 for (const auto & record : tmp_regions) {
339+ // Return only multiplexing regions with more than one resource.
375340 if (record.members .count () < 2 ) {
376341 continue ;
377342 }
378343
379344 mux_regions.push_back (record.members );
380345 }
381-
382346 return mux_regions;
383347}
0 commit comments