Files
openairinterface5g/openair2/LAYER2/NR_MAC_UE/config_ue.c
T
Bartosz Podrygajlo 48d68f7d90 Fix a bug where if BWP size is not exactly maximum BWP size for a bandwidth power control code asserts.
This assert and assumption is incorrect, according to 38.101-1 UE channel is defined only by the BWP size
and BWP size can be any value supported by the RRC parameters defining the BWP.
To determine the UE channel the smallest bandwidth supporting the BWP is selected. This is an assumption based
on references in the same document to UE channel bandwidth being equal to one of the values in set
 {5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100}.
Also:
 - calculated P_CMIN during BWP setup since the parameter doesn't depend on DCI.
 - initiialize uniqCfg structure in test_nr_ue_power_procedures main function which enables LOG prints during tests
2024-07-26 11:15:49 +02:00

2366 lines
111 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* \file config_ue.c
* \brief UE configuration performed by RRC or as a consequence of RRC procedures
* \author R. Knopp, K.H. HSU
* \date 2018
* \version 0.1
* \company Eurecom / NTUST
* \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr
* \note
* \warning
*/
#define _GNU_SOURCE
//#include "mac_defs.h"
#include <NR_MAC_gNB/mac_proto.h>
#include "NR_MAC_UE/mac_proto.h"
#include "NR_MAC-CellGroupConfig.h"
#include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
#include "common/utils/nr/nr_common.h"
#include "executables/softmodem-common.h"
#include "SCHED_NR/phy_frame_config_nr.h"
#include "oai_asn1.h"
void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table,
int mu,
NR_TDD_UL_DL_Pattern_t *pattern)
{
const int nrofDownlinkSlots = pattern->nrofDownlinkSlots;
const int nrofDownlinkSymbols = pattern->nrofDownlinkSymbols;
const int nrofUplinkSlots = pattern->nrofUplinkSlots;
const int nrofUplinkSymbols = pattern->nrofUplinkSymbols;
const int nb_periods_per_frame = get_nb_periods_per_frame(pattern->dl_UL_TransmissionPeriodicity);
const int nb_slots_per_period = ((1 << mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME) / nb_periods_per_frame;
tdd_table->tdd_period_in_slots = nb_slots_per_period;
if ((nrofDownlinkSymbols + nrofUplinkSymbols) == 0)
AssertFatal(nb_slots_per_period == (nrofDownlinkSlots + nrofUplinkSlots),
"set_tdd_configuration_nr: given period is inconsistent with current tdd configuration, nrofDownlinkSlots %d, nrofUplinkSlots %d, nb_slots_per_period %d \n",
nrofDownlinkSlots,nrofUplinkSlots,nb_slots_per_period);
else {
AssertFatal(nrofDownlinkSymbols + nrofUplinkSymbols < 14,"illegal symbol configuration DL %d, UL %d\n",nrofDownlinkSymbols,nrofUplinkSymbols);
AssertFatal(nb_slots_per_period == (nrofDownlinkSlots + nrofUplinkSlots + 1),
"set_tdd_configuration_nr: given period is inconsistent with current tdd configuration, nrofDownlinkSlots %d, nrofUplinkSlots %d, nrofMixed slots 1, nb_slots_per_period %d \n",
nrofDownlinkSlots,nrofUplinkSlots,nb_slots_per_period);
}
tdd_table->max_tdd_periodicity_list = (fapi_nr_max_tdd_periodicity_t *) malloc(nb_slots_per_period * sizeof(fapi_nr_max_tdd_periodicity_t));
for(int memory_alloc = 0 ; memory_alloc < nb_slots_per_period; memory_alloc++)
tdd_table->max_tdd_periodicity_list[memory_alloc].max_num_of_symbol_per_slot_list =
(fapi_nr_max_num_of_symbol_per_slot_t *) malloc(NR_NUMBER_OF_SYMBOLS_PER_SLOT*sizeof(fapi_nr_max_num_of_symbol_per_slot_t));
int slot_number = 0;
while(slot_number != nb_slots_per_period) {
if(nrofDownlinkSlots != 0) {
for (int number_of_symbol = 0; number_of_symbol < nrofDownlinkSlots * NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol % NR_NUMBER_OF_SYMBOLS_PER_SLOT].slot_config = 0;
if((number_of_symbol + 1) % NR_NUMBER_OF_SYMBOLS_PER_SLOT == 0)
slot_number++;
}
}
if (nrofDownlinkSymbols != 0 || nrofUplinkSymbols != 0) {
for(int number_of_symbol = 0; number_of_symbol < nrofDownlinkSymbols; number_of_symbol++) {
tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config = 0;
}
for(int number_of_symbol = nrofDownlinkSymbols; number_of_symbol < NR_NUMBER_OF_SYMBOLS_PER_SLOT - nrofUplinkSymbols; number_of_symbol++) {
tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config = 2;
}
for(int number_of_symbol = NR_NUMBER_OF_SYMBOLS_PER_SLOT - nrofUplinkSymbols; number_of_symbol < NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config = 1;
}
slot_number++;
}
if(nrofUplinkSlots != 0) {
for (int number_of_symbol = 0; number_of_symbol < nrofUplinkSlots * NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
tdd_table->max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol%NR_NUMBER_OF_SYMBOLS_PER_SLOT].slot_config = 1;
if((number_of_symbol + 1) % NR_NUMBER_OF_SYMBOLS_PER_SLOT == 0)
slot_number++;
}
}
}
}
static void config_common_ue_sa(NR_UE_MAC_INST_t *mac,
NR_ServingCellConfigCommonSIB_t *scc,
int cc_idP)
{
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
mac->phy_config.Mod_id = mac->ue_id;
mac->phy_config.CC_id = cc_idP;
LOG_D(MAC, "Entering SA UE Config Common\n");
// carrier config
NR_FrequencyInfoDL_SIB_t *frequencyInfoDL = &scc->downlinkConfigCommon.frequencyInfoDL;
AssertFatal(frequencyInfoDL->frequencyBandList.list.array[0]->freqBandIndicatorNR, "Field mandatory present for DL in SIB1\n");
mac->nr_band = *frequencyInfoDL->frequencyBandList.list.array[0]->freqBandIndicatorNR;
int bw_index = get_supported_band_index(frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
mac->frequency_range,
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.dl_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
uint64_t dl_bw_khz = (12 * frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth) *
(15 << frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
cfg->carrier_config.dl_frequency = (downlink_frequency[cc_idP][0]/1000) - (dl_bw_khz>>1);
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.dl_grid_size[i] = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.dl_k0[i] = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
}
else {
cfg->carrier_config.dl_grid_size[i] = 0;
cfg->carrier_config.dl_k0[i] = 0;
}
}
NR_FrequencyInfoUL_SIB_t *frequencyInfoUL = &scc->uplinkConfigCommon->frequencyInfoUL;
mac->p_Max = frequencyInfoUL->p_Max ? *frequencyInfoUL->p_Max : INT_MIN;
bw_index = get_supported_band_index(frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
mac->frequency_range,
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.uplink_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
if (frequencyInfoUL->absoluteFrequencyPointA == NULL)
cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency;
else
// TODO check if corresponds to what reported in SIB1
cfg->carrier_config.uplink_frequency = (downlink_frequency[cc_idP][0]/1000) + uplink_frequency_offset[cc_idP][0];
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.ul_grid_size[i] = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.ul_k0[i] = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
}
else {
cfg->carrier_config.ul_grid_size[i] = 0;
cfg->carrier_config.ul_k0[i] = 0;
}
}
mac->frame_type = get_frame_type(mac->nr_band, get_softmodem_params()->numerology);
// cell config
cfg->cell_config.phy_cell_id = mac->physCellId;
cfg->cell_config.frame_duplex_type = mac->frame_type;
// SSB config
cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
cfg->ssb_config.scs_common = get_softmodem_params()->numerology;
// SSB Table config
cfg->ssb_table.ssb_offset_point_a = frequencyInfoDL->offsetToPointA;
cfg->ssb_table.ssb_period = scc->ssb_PeriodicityServingCell;
cfg->ssb_table.ssb_subcarrier_offset = mac->ssb_subcarrier_offset;
if (mac->frequency_range == FR1){
cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst.inOneGroup.buf[0]) << 24;
cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
}
else{
for (int i=0; i<8; i++){
if ((scc->ssb_PositionsInBurst.groupPresence->buf[0]>>(7-i))&0x01)
cfg->ssb_table.ssb_mask_list[i>>2].ssb_mask |= ((uint32_t)scc->ssb_PositionsInBurst.inOneGroup.buf[0])<<(24-8*(i%4));
}
}
// TDD Table Configuration
if (cfg->cell_config.frame_duplex_type == TDD){
set_tdd_config_nr_ue(&cfg->tdd_table_1, cfg->ssb_config.scs_common, &mac->tdd_UL_DL_ConfigurationCommon->pattern1);
if (mac->tdd_UL_DL_ConfigurationCommon->pattern2) {
cfg->tdd_table_2 = (fapi_nr_tdd_table_t *) malloc(sizeof(fapi_nr_tdd_table_t));
set_tdd_config_nr_ue(cfg->tdd_table_2, cfg->ssb_config.scs_common, mac->tdd_UL_DL_ConfigurationCommon->pattern2);
}
}
// PRACH configuration
uint8_t nb_preambles = 64;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup;
if(rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
nb_preambles = *rach_ConfigCommon->totalNumberOfRA_Preambles;
cfg->prach_config.prach_sequence_length = rach_ConfigCommon->prach_RootSequenceIndex.present-1;
if (rach_ConfigCommon->msg1_SubcarrierSpacing)
cfg->prach_config.prach_sub_c_spacing = *rach_ConfigCommon->msg1_SubcarrierSpacing;
else {
// If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839)
int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, mac->frame_type);
int format = prach_config_info_p[0];
cfg->prach_config.prach_sub_c_spacing = format == 3 ? 5 : 4;
}
cfg->prach_config.restricted_set_config = rach_ConfigCommon->restrictedSetConfig;
AssertFatal(rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM < 4,
"msg1 FDM identifier %ld undefined (0,1,2,3)\n", rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM);
cfg->prach_config.num_prach_fd_occasions = 1 << rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM;
cfg->prach_config.num_prach_fd_occasions_list = (fapi_nr_num_prach_fd_occasions_t *) malloc(cfg->prach_config.num_prach_fd_occasions*sizeof(fapi_nr_num_prach_fd_occasions_t));
for (int i=0; i<cfg->prach_config.num_prach_fd_occasions; i++) {
fapi_nr_num_prach_fd_occasions_t *prach_fd_occasion = &cfg->prach_config.num_prach_fd_occasions_list[i];
prach_fd_occasion->num_prach_fd_occasions = i;
if (cfg->prach_config.prach_sequence_length)
prach_fd_occasion->prach_root_sequence_index = rach_ConfigCommon->prach_RootSequenceIndex.choice.l139;
else
prach_fd_occasion->prach_root_sequence_index = rach_ConfigCommon->prach_RootSequenceIndex.choice.l839;
prach_fd_occasion->k1 = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP.genericParameters.locationAndBandwidth, MAX_BWP_SIZE) +
rach_ConfigCommon->rach_ConfigGeneric.msg1_FrequencyStart +
(get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing, frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing ) * i);
prach_fd_occasion->prach_zero_corr_conf = rach_ConfigCommon->rach_ConfigGeneric.zeroCorrelationZoneConfig;
prach_fd_occasion->num_root_sequences = compute_nr_root_seq(rach_ConfigCommon,
nb_preambles, mac->frame_type, mac->frequency_range);
//prach_fd_occasion->num_unused_root_sequences = ???
}
cfg->prach_config.ssb_per_rach = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present-1;
}
static void config_common_ue(NR_UE_MAC_INST_t *mac,
NR_ServingCellConfigCommon_t *scc,
int cc_idP)
{
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
mac->phy_config.Mod_id = mac->ue_id;
mac->phy_config.CC_id = cc_idP;
// carrier config
LOG_D(MAC, "[UE %d] Entering UE Config Common\n", mac->ue_id);
AssertFatal(scc->downlinkConfigCommon, "Not expecting downlinkConfigCommon to be NULL here\n");
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
if (frequencyInfoDL) { // NeedM for inter-freq handover
mac->nr_band = *frequencyInfoDL->frequencyBandList.list.array[0];
mac->frame_type = get_frame_type(mac->nr_band, get_softmodem_params()->numerology);
mac->frequency_range = mac->nr_band < 256 ? FR1 : FR2;
int bw_index = get_supported_band_index(frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
mac->frequency_range,
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.dl_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
cfg->carrier_config.dl_frequency = from_nrarfcn(mac->nr_band,
*scc->ssbSubcarrierSpacing,
frequencyInfoDL->absoluteFrequencyPointA)
/ 1000; // freq in kHz
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.dl_grid_size[i] = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.dl_k0[i] = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
} else {
cfg->carrier_config.dl_grid_size[i] = 0;
cfg->carrier_config.dl_k0[i] = 0;
}
}
}
if (scc->uplinkConfigCommon && scc->uplinkConfigCommon->frequencyInfoUL) {
NR_FrequencyInfoUL_t *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL;
mac->p_Max = frequencyInfoUL->p_Max ? *frequencyInfoUL->p_Max : INT_MIN;
int bw_index = get_supported_band_index(frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
mac->frequency_range,
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
cfg->carrier_config.uplink_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
long *UL_pointA = NULL;
if (frequencyInfoUL->absoluteFrequencyPointA)
UL_pointA = frequencyInfoUL->absoluteFrequencyPointA;
else if (frequencyInfoDL)
UL_pointA = &frequencyInfoDL->absoluteFrequencyPointA;
if (UL_pointA)
cfg->carrier_config.uplink_frequency = from_nrarfcn(*frequencyInfoUL->frequencyBandList->list.array[0],
*scc->ssbSubcarrierSpacing,
*UL_pointA)
/ 1000; // freq in kHz
for (int i = 0; i < 5; i++) {
if (i == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {
cfg->carrier_config.ul_grid_size[i] = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
cfg->carrier_config.ul_k0[i] = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier;
} else {
cfg->carrier_config.ul_grid_size[i] = 0;
cfg->carrier_config.ul_k0[i] = 0;
}
}
}
// cell config
cfg->cell_config.phy_cell_id = *scc->physCellId;
cfg->cell_config.frame_duplex_type = mac->frame_type;
// SSB config
cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
cfg->ssb_config.scs_common = *scc->ssbSubcarrierSpacing;
// SSB Table config
if (frequencyInfoDL && frequencyInfoDL->absoluteFrequencySSB) {
int scs_scaling = 1 << (cfg->ssb_config.scs_common);
if (frequencyInfoDL->absoluteFrequencyPointA < 600000)
scs_scaling = scs_scaling * 3;
if (frequencyInfoDL->absoluteFrequencyPointA > 2016666)
scs_scaling = scs_scaling >> 2;
uint32_t absolute_diff = (*frequencyInfoDL->absoluteFrequencySSB - frequencyInfoDL->absoluteFrequencyPointA);
cfg->ssb_table.ssb_offset_point_a = absolute_diff / (12 * scs_scaling) - 10;
cfg->ssb_table.ssb_period = *scc->ssb_periodicityServingCell;
// NSA -> take ssb offset from SCS
cfg->ssb_table.ssb_subcarrier_offset = absolute_diff % (12 * scs_scaling);
}
switch (scc->ssb_PositionsInBurst->present) {
case 1 :
cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] << 24;
cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
break;
case 2 :
cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]) << 24;
cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
break;
case 3 :
cfg->ssb_table.ssb_mask_list[0].ssb_mask = 0;
cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
for (int i = 0; i < 4; i++) {
cfg->ssb_table.ssb_mask_list[0].ssb_mask += (uint32_t) scc->ssb_PositionsInBurst->choice.longBitmap.buf[3 - i] << i * 8;
cfg->ssb_table.ssb_mask_list[1].ssb_mask += (uint32_t) scc->ssb_PositionsInBurst->choice.longBitmap.buf[7 - i] << i * 8;
}
break;
default:
AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", scc->ssb_PositionsInBurst->present);
}
// TDD Table Configuration
if (cfg->cell_config.frame_duplex_type == TDD){
set_tdd_config_nr_ue(&cfg->tdd_table_1, cfg->ssb_config.scs_common, &mac->tdd_UL_DL_ConfigurationCommon->pattern1);
if (mac->tdd_UL_DL_ConfigurationCommon->pattern2) {
cfg->tdd_table_2 = (fapi_nr_tdd_table_t *) malloc(sizeof(fapi_nr_tdd_table_t));
set_tdd_config_nr_ue(cfg->tdd_table_2, cfg->ssb_config.scs_common, mac->tdd_UL_DL_ConfigurationCommon->pattern2);
}
}
// PRACH configuration
uint8_t nb_preambles = 64;
if (scc->uplinkConfigCommon && scc->uplinkConfigCommon->initialUplinkBWP
&& scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon) { // all NeedM
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
if (rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
nb_preambles = *rach_ConfigCommon->totalNumberOfRA_Preambles;
cfg->prach_config.prach_sequence_length = rach_ConfigCommon->prach_RootSequenceIndex.present - 1;
if (rach_ConfigCommon->msg1_SubcarrierSpacing)
cfg->prach_config.prach_sub_c_spacing = *rach_ConfigCommon->msg1_SubcarrierSpacing;
else {
// If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839)
int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, mac->frame_type);
int format = prach_config_info_p[0];
cfg->prach_config.prach_sub_c_spacing = format == 3 ? 5 : 4;
}
cfg->prach_config.restricted_set_config = rach_ConfigCommon->restrictedSetConfig;
AssertFatal(rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM < 4,
"msg1 FDM identifier %ld undefined (0,1,2,3)\n", rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM);
cfg->prach_config.num_prach_fd_occasions = 1 << rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM;
cfg->prach_config.num_prach_fd_occasions_list = (fapi_nr_num_prach_fd_occasions_t *)malloc(
cfg->prach_config.num_prach_fd_occasions * sizeof(fapi_nr_num_prach_fd_occasions_t));
for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions; i++) {
fapi_nr_num_prach_fd_occasions_t *prach_fd_occasion = &cfg->prach_config.num_prach_fd_occasions_list[i];
prach_fd_occasion->num_prach_fd_occasions = i;
if (cfg->prach_config.prach_sequence_length)
prach_fd_occasion->prach_root_sequence_index = rach_ConfigCommon->prach_RootSequenceIndex.choice.l139;
else
prach_fd_occasion->prach_root_sequence_index = rach_ConfigCommon->prach_RootSequenceIndex.choice.l839;
prach_fd_occasion->k1 = rach_ConfigCommon->rach_ConfigGeneric.msg1_FrequencyStart;
prach_fd_occasion->prach_zero_corr_conf = rach_ConfigCommon->rach_ConfigGeneric.zeroCorrelationZoneConfig;
prach_fd_occasion->num_root_sequences =
compute_nr_root_seq(rach_ConfigCommon, nb_preambles, mac->frame_type, mac->frequency_range);
cfg->prach_config.ssb_per_rach = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present - 1;
// prach_fd_occasion->num_unused_root_sequences = ???
}
}
// NTN Config
if (scc->ext2) {
UPDATE_IE(mac->sc_info.ntn_Config_r17, scc->ext2->ntn_Config_r17, NR_NTN_Config_r17_t);
} else {
asn1cFreeStruc(asn_DEF_NR_NTN_Config_r17, mac->sc_info.ntn_Config_r17);
}
}
void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch)
{
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->otherSI_SS);
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->ra_SS);
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->paging_SS);
asn1cFreeStruc(asn_DEF_NR_ControlResourceSet, pdcch->commonControlResourceSet);
}
static void modlist_ss(NR_SearchSpace_t *source, NR_SearchSpace_t *target)
{
target->searchSpaceId = source->searchSpaceId;
if (source->controlResourceSetId)
UPDATE_IE(target->controlResourceSetId, source->controlResourceSetId, NR_ControlResourceSetId_t);
if (source->monitoringSlotPeriodicityAndOffset)
UPDATE_IE(target->monitoringSlotPeriodicityAndOffset,
source->monitoringSlotPeriodicityAndOffset,
struct NR_SearchSpace__monitoringSlotPeriodicityAndOffset);
UPDATE_IE(target->duration, source->duration, long);
if (source->monitoringSymbolsWithinSlot)
UPDATE_IE(target->monitoringSymbolsWithinSlot, source->monitoringSymbolsWithinSlot, BIT_STRING_t);
if (source->nrofCandidates)
UPDATE_IE(target->nrofCandidates, source->nrofCandidates, struct NR_SearchSpace__nrofCandidates);
if (source->searchSpaceType)
UPDATE_IE(target->searchSpaceType, source->searchSpaceType, struct NR_SearchSpace__searchSpaceType);
}
static NR_SearchSpace_t *get_common_search_space(const NR_UE_MAC_INST_t *mac,
const struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList,
const NR_BWP_PDCCH_t *pdcch,
const NR_SearchSpaceId_t ss_id)
{
if (ss_id == 0)
return mac->search_space_zero;
NR_SearchSpace_t *css = NULL;
for (int i = 0; i < commonSearchSpaceList->list.count; i++) {
if (commonSearchSpaceList->list.array[i]->searchSpaceId == ss_id) {
css = calloc(1, sizeof(*css));
modlist_ss(commonSearchSpaceList->list.array[i], css);
break;
}
}
AssertFatal(css, "Couldn't find CSS with Id %ld\n", ss_id);
return css;
}
static void configure_common_ss_coreset(const NR_UE_MAC_INST_t *mac,
NR_BWP_PDCCH_t *pdcch,
NR_PDCCH_ConfigCommon_t *pdcch_ConfigCommon)
{
if (pdcch_ConfigCommon) {
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->otherSI_SS);
if (pdcch_ConfigCommon->searchSpaceOtherSystemInformation)
pdcch->otherSI_SS = get_common_search_space(mac,
pdcch_ConfigCommon->commonSearchSpaceList,
pdcch,
*pdcch_ConfigCommon->searchSpaceOtherSystemInformation);
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->ra_SS);
if (pdcch_ConfigCommon->ra_SearchSpace) {
if (pdcch->otherSI_SS && *pdcch_ConfigCommon->ra_SearchSpace == pdcch->otherSI_SS->searchSpaceId)
pdcch->ra_SS = pdcch->otherSI_SS;
else
pdcch->ra_SS =
get_common_search_space(mac, pdcch_ConfigCommon->commonSearchSpaceList, pdcch, *pdcch_ConfigCommon->ra_SearchSpace);
}
asn1cFreeStruc(asn_DEF_NR_SearchSpace, pdcch->paging_SS);
if (pdcch_ConfigCommon->pagingSearchSpace) {
if (pdcch->otherSI_SS && *pdcch_ConfigCommon->pagingSearchSpace == pdcch->otherSI_SS->searchSpaceId)
pdcch->paging_SS = pdcch->otherSI_SS;
else if (pdcch->ra_SS && *pdcch_ConfigCommon->pagingSearchSpace == pdcch->ra_SS->searchSpaceId)
pdcch->paging_SS = pdcch->ra_SS;
if (!pdcch->paging_SS)
pdcch->paging_SS =
get_common_search_space(mac, pdcch_ConfigCommon->commonSearchSpaceList, pdcch, *pdcch_ConfigCommon->pagingSearchSpace);
}
UPDATE_IE(pdcch->commonControlResourceSet, pdcch_ConfigCommon->commonControlResourceSet, NR_ControlResourceSet_t);
}
}
static void modlist_coreset(NR_ControlResourceSet_t *source, NR_ControlResourceSet_t *target)
{
target->controlResourceSetId = source->controlResourceSetId;
target->frequencyDomainResources.size = source->frequencyDomainResources.size;
if (!target->frequencyDomainResources.buf)
target->frequencyDomainResources.buf =
calloc(target->frequencyDomainResources.size, sizeof(*target->frequencyDomainResources.buf));
for (int i = 0; i < source->frequencyDomainResources.size; i++)
target->frequencyDomainResources.buf[i] = source->frequencyDomainResources.buf[i];
target->duration = source->duration;
target->precoderGranularity = source->precoderGranularity;
long *shiftIndex = NULL;
if (target->cce_REG_MappingType.present == NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved)
shiftIndex = target->cce_REG_MappingType.choice.interleaved->shiftIndex;
if (source->cce_REG_MappingType.present == NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved) {
target->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved;
target->cce_REG_MappingType.choice.interleaved->reg_BundleSize = source->cce_REG_MappingType.choice.interleaved->reg_BundleSize;
target->cce_REG_MappingType.choice.interleaved->interleaverSize =
source->cce_REG_MappingType.choice.interleaved->interleaverSize;
UPDATE_IE(target->cce_REG_MappingType.choice.interleaved->shiftIndex,
source->cce_REG_MappingType.choice.interleaved->shiftIndex,
long);
} else {
free(shiftIndex);
target->cce_REG_MappingType = source->cce_REG_MappingType;
}
UPDATE_IE(target->tci_PresentInDCI, source->tci_PresentInDCI, long);
UPDATE_IE(target->pdcch_DMRS_ScramblingID, source->pdcch_DMRS_ScramblingID, long);
// TCI States
if (source->tci_StatesPDCCH_ToReleaseList) {
for (int i = 0; i < source->tci_StatesPDCCH_ToReleaseList->list.count; i++) {
long id = *source->tci_StatesPDCCH_ToReleaseList->list.array[i];
int j;
for (j = 0; j < target->tci_StatesPDCCH_ToAddList->list.count; j++) {
if (id == *target->tci_StatesPDCCH_ToAddList->list.array[j])
break;
}
if (j < target->tci_StatesPDCCH_ToAddList->list.count)
asn_sequence_del(&target->tci_StatesPDCCH_ToAddList->list, j, 1);
else
LOG_E(NR_MAC, "Element not present in the list, impossible to release\n");
}
}
if (source->tci_StatesPDCCH_ToAddList) {
if (target->tci_StatesPDCCH_ToAddList) {
for (int i = 0; i < source->tci_StatesPDCCH_ToAddList->list.count; i++) {
long id = *source->tci_StatesPDCCH_ToAddList->list.array[i];
int j;
for (j = 0; j < target->tci_StatesPDCCH_ToAddList->list.count; j++) {
if (id == *target->tci_StatesPDCCH_ToAddList->list.array[j])
break;
}
if (j == target->tci_StatesPDCCH_ToAddList->list.count)
ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, source->tci_StatesPDCCH_ToAddList->list.array[i]);
}
} else
UPDATE_IE(target->tci_StatesPDCCH_ToAddList,
source->tci_StatesPDCCH_ToAddList,
struct NR_ControlResourceSet__tci_StatesPDCCH_ToAddList);
}
// end TCI States
}
static void configure_ss_coreset(NR_BWP_PDCCH_t *pdcch, NR_PDCCH_Config_t *pdcch_Config)
{
if (!pdcch_Config)
return;
if (pdcch_Config->controlResourceSetToAddModList) {
for (int i = 0; i < pdcch_Config->controlResourceSetToAddModList->list.count; i++) {
NR_ControlResourceSet_t *source_coreset = pdcch_Config->controlResourceSetToAddModList->list.array[i];
NR_ControlResourceSet_t *target_coreset = NULL;
for (int j = 0; j < pdcch->list_Coreset.count; j++) {
if (pdcch->list_Coreset.array[j]->controlResourceSetId == source_coreset->controlResourceSetId) {
target_coreset = pdcch->list_Coreset.array[j];
break;
}
}
if (!target_coreset) {
target_coreset = calloc(1, sizeof(*target_coreset));
ASN_SEQUENCE_ADD(&pdcch->list_Coreset, target_coreset);
}
modlist_coreset(source_coreset, target_coreset);
}
}
if (pdcch_Config->controlResourceSetToReleaseList) {
for (int i = 0; i < pdcch_Config->controlResourceSetToReleaseList->list.count; i++) {
NR_ControlResourceSetId_t id = *pdcch_Config->controlResourceSetToReleaseList->list.array[i];
for (int j = 0; j < pdcch->list_Coreset.count; j++) {
if (id == pdcch->list_Coreset.array[j]->controlResourceSetId) {
asn_sequence_del(&pdcch->list_Coreset, j, 1);
break;
}
}
}
}
if (pdcch_Config->searchSpacesToAddModList) {
for (int i = 0; i < pdcch_Config->searchSpacesToAddModList->list.count; i++) {
NR_SearchSpace_t *source_ss = pdcch_Config->searchSpacesToAddModList->list.array[i];
NR_SearchSpace_t *target_ss = NULL;
for (int j = 0; j < pdcch->list_SS.count; j++) {
if (pdcch->list_SS.array[j]->searchSpaceId == source_ss->searchSpaceId) {
target_ss = pdcch->list_SS.array[j];
break;
}
}
if (!target_ss) {
target_ss = calloc(1, sizeof(*target_ss));
ASN_SEQUENCE_ADD(&pdcch->list_SS, target_ss);
}
modlist_ss(source_ss, target_ss);
}
}
if (pdcch_Config->searchSpacesToReleaseList) {
for (int i = 0; i < pdcch_Config->searchSpacesToReleaseList->list.count; i++) {
NR_ControlResourceSetId_t id = *pdcch_Config->searchSpacesToReleaseList->list.array[i];
for (int j = 0; j < pdcch->list_SS.count; j++) {
if (id == pdcch->list_SS.array[j]->searchSpaceId) {
asn_sequence_del(&pdcch->list_SS, j, 1);
break;
}
}
}
}
}
static int lcid_cmp(const void *a, const void *b)
{
long priority_a = (*((nr_lcordered_info_t**)a))->priority;
AssertFatal(priority_a > 0 && priority_a < 17, "Invalid priority value %ld\n", priority_a);
long priority_b = (*((nr_lcordered_info_t**)b))->priority;
AssertFatal(priority_b > 0 && priority_b < 17, "Invalid priority value %ld\n", priority_b);
return priority_a - priority_b;
}
static int nr_get_ms_bucketsizeduration(long bucketsizeduration)
{
switch (bucketsizeduration) {
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5:
return 5;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms10:
return 10;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms20:
return 20;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50:
return 50;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100:
return 100;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150:
return 150;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300:
return 300;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500:
return 500;
case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000:
return 1000;
default:
AssertFatal(false, "Invalid bucketSizeDuration %ld\n", bucketsizeduration);
}
}
static uint32_t nr_get_pbr(long prioritizedbitrate) // returns Bps
{
uint32_t pbr = 0;
switch (prioritizedbitrate) {
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps0:
pbr = 0;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8:
pbr = 8;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16:
pbr = 16;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32:
pbr = 32;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps64:
pbr = 64;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps128:
pbr = 128;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps256:
pbr = 256;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps512:
pbr = 512;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps1024:
pbr = 1024;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps2048:
pbr = 2048;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps4096:
pbr = 4096;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8192:
pbr = 8192;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps16384:
pbr = 16384;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps32768:
pbr = 32768;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps65536:
pbr = 65536;
break;
case NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity:
pbr = UINT_MAX;
break;
default:
AssertFatal(false, "The proritized bit rate value is not one of the enum values\n");
}
uint32_t pbr_bytes =
(prioritizedbitrate < NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity) ? pbr * 1000 : pbr;
return pbr_bytes;
}
static uint32_t get_lc_bucket_size(long prioritisedBitRate, long bucketSizeDuration)
{
uint32_t pbr = nr_get_pbr(prioritisedBitRate);
// if infinite pbr, the bucket is saturated by pbr
int bsd = 0;
if (prioritisedBitRate == NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity)
bsd = 1;
else
bsd = nr_get_ms_bucketsizeduration(bucketSizeDuration);
return pbr * bsd;
}
// default configuration as per 38.331 section 9.2.1
static void set_default_logicalchannelconfig(nr_lcordered_info_t *lc_info, NR_SRB_Identity_t srb_id)
{
lc_info->lcid = srb_id;
lc_info->priority = srb_id == 2 ? 3 : 1;
lc_info->pbr = UINT_MAX;
lc_info->bucket_size = UINT_MAX;
}
static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac,
nr_lcordered_info_t *lc_info,
NR_LogicalChannelConfig_t *mac_lc_config,
NR_SRB_Identity_t srb_id)
{
NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lc_info->lcid);
if (srb_id > 0 && !mac_lc_config->ul_SpecificParameters) {
// release configuration and reset to default
set_default_logicalchannelconfig(lc_info, srb_id);
// invalid LCGID to signal it is absent in the configuration
lc_sched_info->LCGID = NR_INVALID_LCGID;
return;
}
AssertFatal(mac_lc_config->ul_SpecificParameters, "UL parameters shouldn't be NULL for DRBs\n");
struct NR_LogicalChannelConfig__ul_SpecificParameters *ul_parm = mac_lc_config->ul_SpecificParameters;
lc_info->priority = ul_parm->priority;
lc_info->sr_id = ul_parm->schedulingRequestID ? *ul_parm->schedulingRequestID : -1;
lc_info->sr_DelayTimerApplied = ul_parm->logicalChannelSR_DelayTimerApplied;
lc_info->lc_SRMask = ul_parm->logicalChannelSR_Mask;
lc_info->pbr = nr_get_pbr(ul_parm->prioritisedBitRate);
// if logicalChannelGroup we release LCGID and set it to invalid
lc_sched_info->LCGID = ul_parm->logicalChannelGroup ? *ul_parm->logicalChannelGroup : NR_INVALID_LCGID;
lc_info->bucket_size = get_lc_bucket_size(ul_parm->prioritisedBitRate, ul_parm->bucketSizeDuration);
// setup and start Bj timer for this LC
NR_timer_t *bjt = &lc_sched_info->Bj_timer;
nr_timer_setup(bjt, UINT_MAX, 1); // this timer never expires in principle, counter incremented by number of slots
nr_timer_start(bjt);
}
static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac,
struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list,
struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list)
{
if (rlc_torelease_list) {
for (int i = 0; i < rlc_torelease_list->list.count; i++) {
long id = *rlc_torelease_list->list.array[i];
int j;
for (j = 0; j < mac->lc_ordered_list.count; j++) {
if (id == mac->lc_ordered_list.array[j]->lcid)
break;
}
if (j < mac->lc_ordered_list.count)
asn_sequence_del(&mac->lc_ordered_list, j, 1);
else
LOG_E(NR_MAC, "Element not present in the list, impossible to release\n");
}
}
if (rlc_toadd_list) {
for (int i = 0; i < rlc_toadd_list->list.count; i++) {
NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i];
int lc_identity = rlc_bearer->logicalChannelIdentity;
NR_LogicalChannelConfig_t *mac_lc_config = rlc_bearer->mac_LogicalChannelConfig;
int j;
for (j = 0; j < mac->lc_ordered_list.count; j++) {
if (lc_identity == mac->lc_ordered_list.array[j]->lcid)
break;
}
if (j < mac->lc_ordered_list.count) {
LOG_D(NR_MAC, "Logical channel %d is already established, Reconfiguring now\n", lc_identity);
if (mac_lc_config != NULL) {
NR_SRB_Identity_t srb_id = 0;
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity)
srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
nr_configure_lc_config(mac, mac->lc_ordered_list.array[j], mac_lc_config, srb_id);
}
}
else {
/* setup of new LCID*/
nr_lcordered_info_t *lc_info = calloc(1, sizeof(*lc_info));
lc_info->lcid = lc_identity;
LOG_D(NR_MAC, "Establishing the logical channel %d\n", lc_identity);
AssertFatal(rlc_bearer->servedRadioBearer, "servedRadioBearer should be present for LCID establishment\n");
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */
NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
if (mac_lc_config != NULL)
nr_configure_lc_config(mac, lc_info, mac_lc_config, srb_id);
else
set_default_logicalchannelconfig(lc_info, srb_id);
} else { /* DRB */
AssertFatal(mac_lc_config, "When establishing a DRB, LogicalChannelConfig should be mandatorily present\n");
nr_configure_lc_config(mac, lc_info, mac_lc_config, 0);
}
ASN_SEQUENCE_ADD(&mac->lc_ordered_list, lc_info);
}
}
// reorder the logical channels as per its priority
qsort(mac->lc_ordered_list.array, mac->lc_ordered_list.count, sizeof(nr_lcordered_info_t*), lcid_cmp);
}
}
void ue_init_config_request(NR_UE_MAC_INST_t *mac, int scs)
{
int slots_per_frame = nr_slots_per_frame[scs];
LOG_I(NR_MAC, "Initializing dl and ul config_request. num_slots = %d\n", slots_per_frame);
mac->dl_config_request = calloc(slots_per_frame, sizeof(*mac->dl_config_request));
mac->ul_config_request = calloc(slots_per_frame, sizeof(*mac->ul_config_request));
for (int i = 0; i < slots_per_frame; i++)
pthread_mutex_init(&(mac->ul_config_request[i].mutex_ul_config), NULL);
}
static void update_mib_conf(NR_MIB_t *target, NR_MIB_t *source)
{
target->systemFrameNumber.size = source->systemFrameNumber.size;
target->systemFrameNumber.bits_unused = source->systemFrameNumber.bits_unused;
if (!target->systemFrameNumber.buf)
target->systemFrameNumber.buf = calloc(target->systemFrameNumber.size, sizeof(*target->systemFrameNumber.buf));
for (int i = 0; i < target->systemFrameNumber.size; i++)
target->systemFrameNumber.buf[i] = source->systemFrameNumber.buf[i];
target->subCarrierSpacingCommon = source->subCarrierSpacingCommon;
target->ssb_SubcarrierOffset = source->ssb_SubcarrierOffset;
target->dmrs_TypeA_Position = source->dmrs_TypeA_Position;
target->pdcch_ConfigSIB1 = source->pdcch_ConfigSIB1;
target->cellBarred = source->cellBarred;
target->intraFreqReselection = source->intraFreqReselection;
}
void nr_rrc_mac_config_req_mib(module_id_t module_id,
int cc_idP,
NR_MIB_t *mib,
int sched_sib)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
AssertFatal(mib, "MIB should not be NULL\n");
if (!mac->mib)
mac->mib = calloc(1, sizeof(*mac->mib));
update_mib_conf(mac->mib, mib);
mac->phy_config.Mod_id = module_id;
mac->phy_config.CC_id = cc_idP;
if (sched_sib == 1)
mac->get_sib1 = true;
else if (sched_sib == 2)
mac->get_otherSI = true;
nr_ue_decode_mib(mac, cc_idP);
}
static void setup_puschpowercontrol(NR_UE_MAC_INST_t *mac, NR_PUSCH_PowerControl_t *source, NR_PUSCH_PowerControl_t *target)
{
UPDATE_IE(target->tpc_Accumulation, source->tpc_Accumulation, long);
UPDATE_IE(target->msg3_Alpha, source->msg3_Alpha, NR_Alpha_t);
if (source->p0_NominalWithoutGrant)
UPDATE_IE(target->p0_NominalWithoutGrant, source->p0_NominalWithoutGrant, long);
if (source->p0_AlphaSets) {
UPDATE_IE(target->p0_AlphaSets, source->p0_AlphaSets, struct NR_PUSCH_PowerControl__p0_AlphaSets);
if (target->p0_AlphaSets->list.array[0]->alpha) {
mac->f_b_f_c = 0;
}
if (target->p0_AlphaSets->list.array[0]->p0) {
mac->f_b_f_c = 0;
}
}
UPDATE_IE(target->twoPUSCH_PC_AdjustmentStates, source->twoPUSCH_PC_AdjustmentStates, long);
UPDATE_IE(target->deltaMCS, source->deltaMCS, long);
if (source->pathlossReferenceRSToReleaseList) {
RELEASE_IE_FROMLIST(source->pathlossReferenceRSToReleaseList,
target->pathlossReferenceRSToAddModList,
pusch_PathlossReferenceRS_Id);
}
if (source->pathlossReferenceRSToAddModList) {
if (!target->pathlossReferenceRSToAddModList)
target->pathlossReferenceRSToAddModList = calloc(1, sizeof(*target->pathlossReferenceRSToAddModList));
ADDMOD_IE_FROMLIST(source->pathlossReferenceRSToAddModList,
target->pathlossReferenceRSToAddModList,
pusch_PathlossReferenceRS_Id,
NR_PUSCH_PathlossReferenceRS_t);
}
if (source->sri_PUSCH_MappingToReleaseList) {
RELEASE_IE_FROMLIST(source->sri_PUSCH_MappingToReleaseList,
target->sri_PUSCH_MappingToAddModList,
sri_PUSCH_PowerControlId);
}
if (source->sri_PUSCH_MappingToAddModList) {
LOG_E(NR_MAC, "NR_SRI_PUSCH_PowerControl not implemented, power control will not work as intended\n");
if (!target->sri_PUSCH_MappingToAddModList)
target->sri_PUSCH_MappingToAddModList = calloc(1, sizeof(*target->sri_PUSCH_MappingToAddModList));
ADDMOD_IE_FROMLIST(source->sri_PUSCH_MappingToAddModList,
target->sri_PUSCH_MappingToAddModList,
sri_PUSCH_PowerControlId,
NR_SRI_PUSCH_PowerControl_t);
}
}
static void setup_puschconfig(NR_UE_MAC_INST_t *mac, NR_PUSCH_Config_t *source, NR_PUSCH_Config_t *target)
{
UPDATE_IE(target->dataScramblingIdentityPUSCH, source->dataScramblingIdentityPUSCH, long);
UPDATE_IE(target->txConfig, source->txConfig, long);
if (source->dmrs_UplinkForPUSCH_MappingTypeA)
HANDLE_SETUPRELEASE_IE(target->dmrs_UplinkForPUSCH_MappingTypeA,
source->dmrs_UplinkForPUSCH_MappingTypeA,
NR_DMRS_UplinkConfig_t,
asn_DEF_NR_SetupRelease_DMRS_UplinkConfig);
if (source->dmrs_UplinkForPUSCH_MappingTypeB)
HANDLE_SETUPRELEASE_IE(target->dmrs_UplinkForPUSCH_MappingTypeB,
source->dmrs_UplinkForPUSCH_MappingTypeB,
NR_DMRS_UplinkConfig_t,
asn_DEF_NR_SetupRelease_DMRS_UplinkConfig);
if (source->pusch_PowerControl) {
if (!target->pusch_PowerControl)
target->pusch_PowerControl = calloc(1, sizeof(*target->pusch_PowerControl));
setup_puschpowercontrol(mac, source->pusch_PowerControl, target->pusch_PowerControl);
}
UPDATE_IE(target->frequencyHopping, source->frequencyHopping, long);
if (source->frequencyHoppingOffsetLists)
UPDATE_IE(target->frequencyHoppingOffsetLists,
source->frequencyHoppingOffsetLists,
struct NR_PUSCH_Config__frequencyHoppingOffsetLists);
target->resourceAllocation = source->resourceAllocation;
if (source->pusch_TimeDomainAllocationList)
HANDLE_SETUPRELEASE_IE(target->pusch_TimeDomainAllocationList,
source->pusch_TimeDomainAllocationList,
NR_PUSCH_TimeDomainResourceAllocationList_t,
asn_DEF_NR_SetupRelease_PUSCH_TimeDomainResourceAllocationList);
UPDATE_IE(target->pusch_AggregationFactor, source->pusch_AggregationFactor, long);
UPDATE_IE(target->mcs_Table, source->mcs_Table, long);
UPDATE_IE(target->mcs_TableTransformPrecoder, source->mcs_TableTransformPrecoder, long);
UPDATE_IE(target->transformPrecoder, source->transformPrecoder, long);
UPDATE_IE(target->codebookSubset, source->codebookSubset, long);
UPDATE_IE(target->maxRank, source->maxRank, long);
UPDATE_IE(target->rbg_Size, source->rbg_Size, long);
UPDATE_IE(target->tp_pi2BPSK, source->tp_pi2BPSK, long);
if (source->uci_OnPUSCH) {
if (source->uci_OnPUSCH->present == NR_SetupRelease_UCI_OnPUSCH_PR_release)
asn1cFreeStruc(asn_DEF_NR_UCI_OnPUSCH, target->uci_OnPUSCH);
if (source->uci_OnPUSCH->present == NR_SetupRelease_UCI_OnPUSCH_PR_setup) {
if (!target->uci_OnPUSCH) {
target->uci_OnPUSCH = calloc(1, sizeof(*target->uci_OnPUSCH));
target->uci_OnPUSCH->choice.setup = calloc(1, sizeof(*target->uci_OnPUSCH->choice.setup));
}
target->uci_OnPUSCH->choice.setup->scaling = source->uci_OnPUSCH->choice.setup->scaling;
if (source->uci_OnPUSCH->choice.setup->betaOffsets)
UPDATE_IE(target->uci_OnPUSCH->choice.setup->betaOffsets,
source->uci_OnPUSCH->choice.setup->betaOffsets,
struct NR_UCI_OnPUSCH__betaOffsets);
}
}
}
static void configure_csi_resourcemapping(NR_CSI_RS_ResourceMapping_t *target, NR_CSI_RS_ResourceMapping_t *source)
{
if (target->frequencyDomainAllocation.present != source->frequencyDomainAllocation.present) {
UPDATE_NP_IE(target->frequencyDomainAllocation,
source->frequencyDomainAllocation,
struct NR_CSI_RS_ResourceMapping__frequencyDomainAllocation);
}
else {
switch (source->frequencyDomainAllocation.present) {
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
target->frequencyDomainAllocation.choice.row1.size = source->frequencyDomainAllocation.choice.row1.size;
target->frequencyDomainAllocation.choice.row1.bits_unused = source->frequencyDomainAllocation.choice.row1.bits_unused;
if (!target->frequencyDomainAllocation.choice.row1.buf)
target->frequencyDomainAllocation.choice.row1.buf =
calloc(target->frequencyDomainAllocation.choice.row1.size, sizeof(uint8_t));
for (int i = 0; i < target->frequencyDomainAllocation.choice.row1.size; i++)
target->frequencyDomainAllocation.choice.row1.buf[i] = source->frequencyDomainAllocation.choice.row1.buf[i];
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
target->frequencyDomainAllocation.choice.row2.size = source->frequencyDomainAllocation.choice.row2.size;
target->frequencyDomainAllocation.choice.row2.bits_unused = source->frequencyDomainAllocation.choice.row2.bits_unused;
if (!target->frequencyDomainAllocation.choice.row2.buf)
target->frequencyDomainAllocation.choice.row2.buf =
calloc(target->frequencyDomainAllocation.choice.row2.size, sizeof(uint8_t));
for (int i = 0; i < target->frequencyDomainAllocation.choice.row2.size; i++)
target->frequencyDomainAllocation.choice.row2.buf[i] = source->frequencyDomainAllocation.choice.row2.buf[i];
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
target->frequencyDomainAllocation.choice.row4.size = source->frequencyDomainAllocation.choice.row4.size;
target->frequencyDomainAllocation.choice.row4.bits_unused = source->frequencyDomainAllocation.choice.row4.bits_unused;
if (!target->frequencyDomainAllocation.choice.row4.buf)
target->frequencyDomainAllocation.choice.row4.buf =
calloc(target->frequencyDomainAllocation.choice.row4.size, sizeof(uint8_t));
for (int i = 0; i < target->frequencyDomainAllocation.choice.row4.size; i++)
target->frequencyDomainAllocation.choice.row4.buf[i] = source->frequencyDomainAllocation.choice.row4.buf[i];
break;
case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
target->frequencyDomainAllocation.choice.other.size = source->frequencyDomainAllocation.choice.other.size;
target->frequencyDomainAllocation.choice.other.bits_unused = source->frequencyDomainAllocation.choice.other.bits_unused;
if (!target->frequencyDomainAllocation.choice.other.buf)
target->frequencyDomainAllocation.choice.other.buf =
calloc(target->frequencyDomainAllocation.choice.other.size, sizeof(uint8_t));
for (int i = 0; i < target->frequencyDomainAllocation.choice.other.size; i++)
target->frequencyDomainAllocation.choice.other.buf[i] = source->frequencyDomainAllocation.choice.other.buf[i];
break;
default:
AssertFatal(false, "Invalid entry\n");
}
}
target->nrofPorts = source->nrofPorts;
target->firstOFDMSymbolInTimeDomain = source->firstOFDMSymbolInTimeDomain;
UPDATE_IE(target->firstOFDMSymbolInTimeDomain2, source->firstOFDMSymbolInTimeDomain2, long);
target->cdm_Type = source->cdm_Type;
target->density = source->density;
target->freqBand = source->freqBand;
}
static void config_zp_CSI_RS_Resource(NR_ZP_CSI_RS_Resource_t *target, NR_ZP_CSI_RS_Resource_t *source)
{
target->zp_CSI_RS_ResourceId = source->zp_CSI_RS_ResourceId;
configure_csi_resourcemapping(&target->resourceMapping, &source->resourceMapping);
if (source->periodicityAndOffset)
UPDATE_IE(target->periodicityAndOffset,
source->periodicityAndOffset,
NR_CSI_ResourcePeriodicityAndOffset_t);
}
static void setup_pdschconfig(NR_PDSCH_Config_t *source, NR_PDSCH_Config_t *target)
{
UPDATE_IE(target->dataScramblingIdentityPDSCH, source->dataScramblingIdentityPDSCH, long);
if (source->dmrs_DownlinkForPDSCH_MappingTypeA)
HANDLE_SETUPRELEASE_IE(target->dmrs_DownlinkForPDSCH_MappingTypeA,
source->dmrs_DownlinkForPDSCH_MappingTypeA,
NR_DMRS_DownlinkConfig_t,
asn_DEF_NR_SetupRelease_DMRS_DownlinkConfig);
if (source->dmrs_DownlinkForPDSCH_MappingTypeB)
HANDLE_SETUPRELEASE_IE(target->dmrs_DownlinkForPDSCH_MappingTypeB,
source->dmrs_DownlinkForPDSCH_MappingTypeB,
NR_DMRS_DownlinkConfig_t,
asn_DEF_NR_SetupRelease_DMRS_DownlinkConfig);
// TCI States
if (source->tci_StatesToReleaseList) {
RELEASE_IE_FROMLIST(source->tci_StatesToReleaseList,
target->tci_StatesToAddModList,
tci_StateId);
}
if (source->tci_StatesToAddModList) {
if (!target->tci_StatesToAddModList)
target->tci_StatesToAddModList = calloc(1, sizeof(*target->tci_StatesToAddModList));
ADDMOD_IE_FROMLIST(source->tci_StatesToAddModList,
target->tci_StatesToAddModList,
tci_StateId,
NR_TCI_State_t);
}
// end TCI States
UPDATE_IE(target->vrb_ToPRB_Interleaver, source->vrb_ToPRB_Interleaver, long);
target->resourceAllocation = source->resourceAllocation;
if (source->pdsch_TimeDomainAllocationList)
HANDLE_SETUPRELEASE_IE(target->pdsch_TimeDomainAllocationList,
source->pdsch_TimeDomainAllocationList,
NR_PDSCH_TimeDomainResourceAllocationList_t,
asn_DEF_NR_SetupRelease_PDSCH_TimeDomainResourceAllocationList);
UPDATE_IE(target->pdsch_AggregationFactor, source->pdsch_AggregationFactor, long);
// rateMatchPattern
if (source->rateMatchPatternToReleaseList) {
RELEASE_IE_FROMLIST(source->rateMatchPatternToReleaseList,
target->rateMatchPatternToAddModList,
rateMatchPatternId);
}
if (source->rateMatchPatternToAddModList) {
if (!target->rateMatchPatternToAddModList)
target->rateMatchPatternToAddModList = calloc(1, sizeof(*target->rateMatchPatternToAddModList));
ADDMOD_IE_FROMLIST(source->rateMatchPatternToAddModList,
target->rateMatchPatternToAddModList,
rateMatchPatternId,
NR_RateMatchPattern_t);
}
// end rateMatchPattern
UPDATE_IE(target->rateMatchPatternGroup1, source->rateMatchPatternGroup1, NR_RateMatchPatternGroup_t);
UPDATE_IE(target->rateMatchPatternGroup2, source->rateMatchPatternGroup2, NR_RateMatchPatternGroup_t);
target->rbg_Size = source->rbg_Size;
UPDATE_IE(target->mcs_Table, source->mcs_Table, long);
UPDATE_IE(target->maxNrofCodeWordsScheduledByDCI, source->maxNrofCodeWordsScheduledByDCI, long);
UPDATE_NP_IE(target->prb_BundlingType, source->prb_BundlingType, struct NR_PDSCH_Config__prb_BundlingType);
if (source->zp_CSI_RS_ResourceToAddModList) {
if (!target->zp_CSI_RS_ResourceToAddModList)
target->zp_CSI_RS_ResourceToAddModList = calloc(1, sizeof(*target->zp_CSI_RS_ResourceToAddModList));
ADDMOD_IE_FROMLIST_WFUNCTION(source->zp_CSI_RS_ResourceToAddModList,
target->zp_CSI_RS_ResourceToAddModList,
zp_CSI_RS_ResourceId,
NR_ZP_CSI_RS_Resource_t,
config_zp_CSI_RS_Resource);
}
if (source->zp_CSI_RS_ResourceToReleaseList) {
RELEASE_IE_FROMLIST(source->zp_CSI_RS_ResourceToReleaseList,
target->zp_CSI_RS_ResourceToAddModList,
zp_CSI_RS_ResourceId);
}
if (source->p_ZP_CSI_RS_ResourceSet)
HANDLE_SETUPRELEASE_IE(target->p_ZP_CSI_RS_ResourceSet,
source->p_ZP_CSI_RS_ResourceSet,
NR_ZP_CSI_RS_ResourceSet_t,
asn_DEF_NR_ZP_CSI_RS_ResourceSet);
AssertFatal(source->aperiodic_ZP_CSI_RS_ResourceSetsToAddModList == NULL, "Not handled\n");
AssertFatal(source->sp_ZP_CSI_RS_ResourceSetsToAddModList == NULL, "Not handled\n");
}
static void setup_sr_resource(NR_SchedulingRequestResourceConfig_t *target, NR_SchedulingRequestResourceConfig_t *source)
{
target->schedulingRequestResourceId = source->schedulingRequestResourceId;
target->schedulingRequestID = source->schedulingRequestID;
if (source->periodicityAndOffset)
UPDATE_IE(target->periodicityAndOffset,
source->periodicityAndOffset,
struct NR_SchedulingRequestResourceConfig__periodicityAndOffset);
if (source->resource)
UPDATE_IE(target->resource, source->resource, NR_PUCCH_ResourceId_t);
}
static void setup_pucchconfig(NR_PUCCH_Config_t *source, NR_PUCCH_Config_t *target)
{
// PUCCH-ResourceSet
if (source->resourceSetToAddModList) {
if (!target->resourceSetToAddModList)
target->resourceSetToAddModList = calloc(1, sizeof(*target->resourceSetToAddModList));
ADDMOD_IE_FROMLIST(source->resourceSetToAddModList,
target->resourceSetToAddModList,
pucch_ResourceSetId,
NR_PUCCH_ResourceSet_t);
}
if (source->resourceSetToReleaseList) {
RELEASE_IE_FROMLIST(source->resourceSetToReleaseList,
target->resourceSetToAddModList,
pucch_ResourceSetId);
}
// PUCCH-Resource
if (source->resourceToAddModList) {
if (!target->resourceToAddModList)
target->resourceToAddModList = calloc(1, sizeof(*target->resourceToAddModList));
ADDMOD_IE_FROMLIST(source->resourceToAddModList,
target->resourceToAddModList,
pucch_ResourceId,
NR_PUCCH_Resource_t);
}
if (source->resourceToReleaseList) {
RELEASE_IE_FROMLIST(source->resourceToReleaseList,
target->resourceToAddModList,
pucch_ResourceId);
}
// PUCCH-FormatConfig
if (source->format1)
HANDLE_SETUPRELEASE_IE(target->format1,
source->format1,
NR_PUCCH_FormatConfig_t,
asn_DEF_NR_SetupRelease_PUCCH_FormatConfig);
if (source->format2)
HANDLE_SETUPRELEASE_IE(target->format2,
source->format2,
NR_PUCCH_FormatConfig_t,
asn_DEF_NR_SetupRelease_PUCCH_FormatConfig);
if (source->format3)
HANDLE_SETUPRELEASE_IE(target->format3,
source->format3,
NR_PUCCH_FormatConfig_t,
asn_DEF_NR_SetupRelease_PUCCH_FormatConfig);
if (source->format4)
HANDLE_SETUPRELEASE_IE(target->format4,
source->format4,
NR_PUCCH_FormatConfig_t,
asn_DEF_NR_SetupRelease_PUCCH_FormatConfig);
// SchedulingRequestResourceConfig
if (source->schedulingRequestResourceToAddModList) {
if (!target->schedulingRequestResourceToAddModList)
target->schedulingRequestResourceToAddModList = calloc(1, sizeof(*target->schedulingRequestResourceToAddModList));
ADDMOD_IE_FROMLIST_WFUNCTION(source->schedulingRequestResourceToAddModList,
target->schedulingRequestResourceToAddModList,
schedulingRequestResourceId,
NR_SchedulingRequestResourceConfig_t,
setup_sr_resource);
}
if (source->schedulingRequestResourceToReleaseList) {
RELEASE_IE_FROMLIST(source->schedulingRequestResourceToReleaseList,
target->schedulingRequestResourceToAddModList,
schedulingRequestResourceId);
}
if (source->multi_CSI_PUCCH_ResourceList)
UPDATE_IE(target->multi_CSI_PUCCH_ResourceList,
source->multi_CSI_PUCCH_ResourceList,
struct NR_PUCCH_Config__multi_CSI_PUCCH_ResourceList);
if (source->dl_DataToUL_ACK)
UPDATE_IE(target->dl_DataToUL_ACK, source->dl_DataToUL_ACK, struct NR_PUCCH_Config__dl_DataToUL_ACK);
// PUCCH-SpatialRelationInfo
if (source->spatialRelationInfoToAddModList) {
if (!target->spatialRelationInfoToAddModList)
target->spatialRelationInfoToAddModList = calloc(1, sizeof(*target->spatialRelationInfoToAddModList));
ADDMOD_IE_FROMLIST(source->spatialRelationInfoToAddModList,
target->spatialRelationInfoToAddModList,
pucch_SpatialRelationInfoId,
NR_PUCCH_SpatialRelationInfo_t);
}
if (source->spatialRelationInfoToReleaseList) {
RELEASE_IE_FROMLIST(source->spatialRelationInfoToReleaseList,
target->spatialRelationInfoToAddModList,
pucch_SpatialRelationInfoId);
}
if (source->pucch_PowerControl) {
if (!target->pucch_PowerControl)
target->pucch_PowerControl = calloc(1, sizeof(*target->pucch_PowerControl));
UPDATE_IE(target->pucch_PowerControl->deltaF_PUCCH_f0, source->pucch_PowerControl->deltaF_PUCCH_f0, long);
UPDATE_IE(target->pucch_PowerControl->deltaF_PUCCH_f1, source->pucch_PowerControl->deltaF_PUCCH_f1, long);
UPDATE_IE(target->pucch_PowerControl->deltaF_PUCCH_f2, source->pucch_PowerControl->deltaF_PUCCH_f2, long);
UPDATE_IE(target->pucch_PowerControl->deltaF_PUCCH_f3, source->pucch_PowerControl->deltaF_PUCCH_f3, long);
UPDATE_IE(target->pucch_PowerControl->deltaF_PUCCH_f4, source->pucch_PowerControl->deltaF_PUCCH_f4, long);
if (source->pucch_PowerControl->p0_Set)
UPDATE_IE(target->pucch_PowerControl->p0_Set, source->pucch_PowerControl->p0_Set, struct NR_PUCCH_PowerControl__p0_Set);
if (source->pucch_PowerControl->pathlossReferenceRSs)
UPDATE_IE(target->pucch_PowerControl->pathlossReferenceRSs,
source->pucch_PowerControl->pathlossReferenceRSs,
struct NR_PUCCH_PowerControl__pathlossReferenceRSs);
UPDATE_IE(target->pucch_PowerControl->twoPUCCH_PC_AdjustmentStates,
source->pucch_PowerControl->twoPUCCH_PC_AdjustmentStates,
long);
}
}
static void handle_aperiodic_srs_type(struct NR_SRS_ResourceSet__resourceType__aperiodic *source,
struct NR_SRS_ResourceSet__resourceType__aperiodic *target)
{
target->aperiodicSRS_ResourceTrigger = source->aperiodicSRS_ResourceTrigger;
if (source->csi_RS)
UPDATE_IE(target->csi_RS, source->csi_RS, NR_NZP_CSI_RS_ResourceId_t);
UPDATE_IE(target->slotOffset, source->slotOffset, long);
if (source->ext1 && source->ext1->aperiodicSRS_ResourceTriggerList)
UPDATE_IE(target->ext1->aperiodicSRS_ResourceTriggerList,
source->ext1->aperiodicSRS_ResourceTriggerList,
struct NR_SRS_ResourceSet__resourceType__aperiodic__ext1__aperiodicSRS_ResourceTriggerList);
}
static void setup_srsresourceset(NR_SRS_ResourceSet_t *target, NR_SRS_ResourceSet_t *source)
{
target->srs_ResourceSetId = source->srs_ResourceSetId;
if (source->srs_ResourceIdList)
UPDATE_IE(target->srs_ResourceIdList, source->srs_ResourceIdList, struct NR_SRS_ResourceSet__srs_ResourceIdList);
if (target->resourceType.present != source->resourceType.present) {
UPDATE_NP_IE(target->resourceType, source->resourceType, struct NR_SRS_ResourceSet__resourceType);
}
else {
switch (source->resourceType.present) {
case NR_SRS_ResourceSet__resourceType_PR_aperiodic:
handle_aperiodic_srs_type(source->resourceType.choice.aperiodic, target->resourceType.choice.aperiodic);
break;
case NR_SRS_ResourceSet__resourceType_PR_periodic:
if (source->resourceType.choice.periodic->associatedCSI_RS)
UPDATE_IE(target->resourceType.choice.periodic->associatedCSI_RS,
source->resourceType.choice.periodic->associatedCSI_RS,
NR_NZP_CSI_RS_ResourceId_t);
break;
case NR_SRS_ResourceSet__resourceType_PR_semi_persistent:
if (source->resourceType.choice.semi_persistent->associatedCSI_RS)
UPDATE_IE(target->resourceType.choice.semi_persistent->associatedCSI_RS,
source->resourceType.choice.semi_persistent->associatedCSI_RS,
NR_NZP_CSI_RS_ResourceId_t);
break;
default:
break;
}
}
target->usage = source->usage;
UPDATE_IE(target->alpha, source->alpha, NR_Alpha_t);
if (source->p0)
UPDATE_IE(target->p0, source->p0, long);
if (source->pathlossReferenceRS)
UPDATE_IE(target->pathlossReferenceRS, source->pathlossReferenceRS, struct NR_PathlossReferenceRS_Config);
UPDATE_IE(target->srs_PowerControlAdjustmentStates, source->srs_PowerControlAdjustmentStates, long);
}
static void setup_srsconfig(NR_SRS_Config_t *source, NR_SRS_Config_t *target)
{
UPDATE_IE(target->tpc_Accumulation, source->tpc_Accumulation, long);
// SRS-Resource
if (source->srs_ResourceToAddModList) {
if (!target->srs_ResourceToAddModList)
target->srs_ResourceToAddModList = calloc(1, sizeof(*target->srs_ResourceToAddModList));
ADDMOD_IE_FROMLIST(source->srs_ResourceToAddModList,
target->srs_ResourceToAddModList,
srs_ResourceId,
NR_SRS_Resource_t);
}
if (source->srs_ResourceToReleaseList) {
RELEASE_IE_FROMLIST(source->srs_ResourceToReleaseList,
target->srs_ResourceToAddModList,
srs_ResourceId);
}
// SRS-ResourceSet
if (source->srs_ResourceSetToAddModList) {
if (!target->srs_ResourceSetToAddModList)
target->srs_ResourceSetToAddModList = calloc(1, sizeof(*target->srs_ResourceSetToAddModList));
ADDMOD_IE_FROMLIST_WFUNCTION(source->srs_ResourceSetToAddModList,
target->srs_ResourceSetToAddModList,
srs_ResourceSetId,
NR_SRS_ResourceSet_t,
setup_srsresourceset);
}
if (source->srs_ResourceSetToReleaseList) {
RELEASE_IE_FROMLIST(source->srs_ResourceSetToReleaseList,
target->srs_ResourceSetToAddModList,
srs_ResourceSetId);
}
}
static NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
{
NR_UE_DL_BWP_t *bwp = NULL;
for (int i = 0; i < mac->dl_BWPs.count; i++) {
if (bwp_id == mac->dl_BWPs.array[i]->bwp_id) {
bwp = mac->dl_BWPs.array[i];
break;
}
}
if (!bwp && setup) {
bwp = calloc(1, sizeof(*bwp));
ASN_SEQUENCE_ADD(&mac->dl_BWPs, bwp);
}
if (!setup) {
mac->sc_info.n_dl_bwp = mac->dl_BWPs.count - 1;
mac->sc_info.dl_bw_tbslbrm = 0;
for (int i = 0; i < mac->dl_BWPs.count; i++) {
if (mac->dl_BWPs.array[i]->BWPSize > mac->sc_info.dl_bw_tbslbrm)
mac->sc_info.dl_bw_tbslbrm = mac->dl_BWPs.array[i]->BWPSize;
}
}
return bwp;
}
static NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
{
NR_UE_UL_BWP_t *bwp = NULL;
for (int i = 0; i < mac->ul_BWPs.count; i++) {
if (bwp_id == mac->ul_BWPs.array[i]->bwp_id) {
bwp = mac->ul_BWPs.array[i];
break;
}
}
if (!bwp && setup) {
bwp = calloc(1, sizeof(*bwp));
ASN_SEQUENCE_ADD(&mac->ul_BWPs, bwp);
}
if (!setup) {
mac->sc_info.n_ul_bwp = mac->ul_BWPs.count - 1;
mac->sc_info.ul_bw_tbslbrm = 0;
for (int i = 0; i < mac->ul_BWPs.count; i++) {
if (mac->ul_BWPs.array[i]->BWPSize > mac->sc_info.ul_bw_tbslbrm)
mac->sc_info.ul_bw_tbslbrm = mac->ul_BWPs.array[i]->BWPSize;
}
}
return bwp;
}
static void configure_dedicated_BWP_dl(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_DownlinkDedicated_t *dl_dedicated)
{
if (dl_dedicated) {
NR_UE_DL_BWP_t *bwp = get_dl_bwp_structure(mac, bwp_id, true);
bwp->bwp_id = bwp_id;
NR_BWP_PDCCH_t *pdcch = &mac->config_BWP_PDCCH[bwp_id];
if(dl_dedicated->pdsch_Config) {
if (dl_dedicated->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_release)
asn1cFreeStruc(asn_DEF_NR_PDSCH_Config, bwp->pdsch_Config);
if (dl_dedicated->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_setup) {
if (!bwp->pdsch_Config)
bwp->pdsch_Config = calloc(1, sizeof(*bwp->pdsch_Config));
setup_pdschconfig(dl_dedicated->pdsch_Config->choice.setup, bwp->pdsch_Config);
}
}
if (dl_dedicated->pdcch_Config) {
if (dl_dedicated->pdcch_Config->present == NR_SetupRelease_PDCCH_Config_PR_release) {
for (int i = pdcch->list_Coreset.count; i > 0 ; i--)
asn_sequence_del(&pdcch->list_Coreset, i - 1, 1);
for (int i = pdcch->list_SS.count; i > 0 ; i--)
asn_sequence_del(&pdcch->list_SS, i - 1, 1);
}
if (dl_dedicated->pdcch_Config->present == NR_SetupRelease_PDCCH_Config_PR_setup)
configure_ss_coreset(pdcch, dl_dedicated->pdcch_Config->choice.setup);
}
AssertFatal(!dl_dedicated->sps_Config, "SPS handling not implemented\n");
}
}
static void configure_dedicated_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_UplinkDedicated_t *ul_dedicated)
{
if (ul_dedicated) {
NR_UE_UL_BWP_t *bwp = get_ul_bwp_structure(mac, bwp_id, true);
bwp->bwp_id = bwp_id;
if(ul_dedicated->pucch_Config) {
if (ul_dedicated->pucch_Config->present == NR_SetupRelease_PUCCH_Config_PR_release)
asn1cFreeStruc(asn_DEF_NR_PUCCH_Config, bwp->pucch_Config);
if (ul_dedicated->pucch_Config->present == NR_SetupRelease_PUCCH_Config_PR_setup) {
if (!bwp->pucch_Config)
bwp->pucch_Config = calloc(1, sizeof(*bwp->pucch_Config));
setup_pucchconfig(ul_dedicated->pucch_Config->choice.setup, bwp->pucch_Config);
}
}
if(ul_dedicated->pusch_Config) {
if (ul_dedicated->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_release)
asn1cFreeStruc(asn_DEF_NR_PUSCH_Config, bwp->pusch_Config);
if (ul_dedicated->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_setup) {
if (!bwp->pusch_Config)
bwp->pusch_Config = calloc(1, sizeof(*bwp->pusch_Config));
setup_puschconfig(mac, ul_dedicated->pusch_Config->choice.setup, bwp->pusch_Config);
}
}
if(ul_dedicated->srs_Config) {
if (ul_dedicated->srs_Config->present == NR_SetupRelease_SRS_Config_PR_release)
asn1cFreeStruc(asn_DEF_NR_SRS_Config, bwp->srs_Config);
if (ul_dedicated->srs_Config->present == NR_SetupRelease_SRS_Config_PR_setup) {
if (!bwp->srs_Config)
bwp->srs_Config = calloc(1, sizeof(*bwp->srs_Config));
setup_srsconfig(ul_dedicated->srs_Config->choice.setup, bwp->srs_Config);
}
}
AssertFatal(!ul_dedicated->configuredGrantConfig, "configuredGrantConfig not supported\n");
}
}
static void configure_common_BWP_dl(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_DownlinkCommon_t *dl_common)
{
if (dl_common) {
NR_UE_DL_BWP_t *bwp = get_dl_bwp_structure(mac, bwp_id, true);
bwp->bwp_id = bwp_id;
NR_BWP_t *dl_genericParameters = &dl_common->genericParameters;
bwp->scs = dl_genericParameters->subcarrierSpacing;
bwp->cyclicprefix = dl_genericParameters->cyclicPrefix;
bwp->BWPSize = NRRIV2BW(dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
bwp->BWPStart = NRRIV2PRBOFFSET(dl_genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
if (bwp_id == 0) {
mac->sc_info.initial_dl_BWPSize = bwp->BWPSize;
mac->sc_info.initial_dl_BWPStart = bwp->BWPStart;
}
if (dl_common->pdsch_ConfigCommon) {
if (dl_common->pdsch_ConfigCommon->present == NR_SetupRelease_PDSCH_ConfigCommon_PR_setup)
UPDATE_IE(bwp->tdaList_Common,
dl_common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList,
NR_PDSCH_TimeDomainResourceAllocationList_t);
if (dl_common->pdsch_ConfigCommon->present == NR_SetupRelease_PDSCH_ConfigCommon_PR_release)
asn1cFreeStruc(asn_DEF_NR_PDSCH_TimeDomainResourceAllocationList, bwp->tdaList_Common);
}
NR_BWP_PDCCH_t *pdcch = &mac->config_BWP_PDCCH[bwp_id];
if (dl_common->pdcch_ConfigCommon) {
if (dl_common->pdcch_ConfigCommon->present == NR_SetupRelease_PDCCH_ConfigCommon_PR_setup)
configure_common_ss_coreset(mac, pdcch, dl_common->pdcch_ConfigCommon->choice.setup);
if (dl_common->pdcch_ConfigCommon->present == NR_SetupRelease_PDCCH_ConfigCommon_PR_release)
release_common_ss_cset(pdcch);
}
}
}
static void configure_common_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_UplinkCommon_t *ul_common)
{
if (ul_common) {
NR_UE_UL_BWP_t *bwp = get_ul_bwp_structure(mac, bwp_id, true);
bwp->bwp_id = bwp_id;
NR_BWP_t *ul_genericParameters = &ul_common->genericParameters;
bwp->scs = ul_genericParameters->subcarrierSpacing;
bwp->cyclicprefix = ul_genericParameters->cyclicPrefix;
bwp->BWPSize = NRRIV2BW(ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
bwp->BWPStart = NRRIV2PRBOFFSET(ul_genericParameters->locationAndBandwidth, MAX_BWP_SIZE);
// For power calculations assume the UE channel is the smallest channel that can support the BWP
int bw_index = get_smallest_supported_bandwidth_index(bwp->scs, mac->frequency_range, bwp->BWPSize);
bwp->channel_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
// Minumum transmission power depends on bandwidth, precalculate it here
bwp->P_CMIN = nr_get_Pcmin(bw_index);
if (bwp_id == 0) {
mac->sc_info.initial_ul_BWPSize = bwp->BWPSize;
mac->sc_info.initial_ul_BWPStart = bwp->BWPStart;
}
if (ul_common->rach_ConfigCommon) {
HANDLE_SETUPRELEASE_DIRECT(bwp->rach_ConfigCommon,
ul_common->rach_ConfigCommon,
NR_RACH_ConfigCommon_t,
asn_DEF_NR_RACH_ConfigCommon);
}
if (ul_common->pucch_ConfigCommon)
HANDLE_SETUPRELEASE_DIRECT(bwp->pucch_ConfigCommon,
ul_common->pucch_ConfigCommon,
NR_PUCCH_ConfigCommon_t,
asn_DEF_NR_PUCCH_ConfigCommon);
if (ul_common->pusch_ConfigCommon) {
if (ul_common->pusch_ConfigCommon->present == NR_SetupRelease_PUSCH_ConfigCommon_PR_setup) {
UPDATE_IE(bwp->tdaList_Common,
ul_common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList,
NR_PUSCH_TimeDomainResourceAllocationList_t);
UPDATE_IE(bwp->msg3_DeltaPreamble, ul_common->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble, long);
UPDATE_IE(bwp->p0_NominalWithGrant, ul_common->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant, long);
}
if (ul_common->pusch_ConfigCommon->present == NR_SetupRelease_PUSCH_ConfigCommon_PR_release) {
asn1cFreeStruc(asn_DEF_NR_PUSCH_TimeDomainResourceAllocationList, bwp->tdaList_Common);
free(bwp->msg3_DeltaPreamble);
bwp->msg3_DeltaPreamble = NULL;
free(bwp->p0_NominalWithGrant);
bwp->p0_NominalWithGrant = NULL;
}
}
}
}
void nr_rrc_mac_config_req_reset(module_id_t module_id,
NR_UE_MAC_reset_cause_t cause)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
fapi_nr_synch_request_t sync_req = {.target_Nid_cell = -1, .ssb_bw_scan = true};
switch (cause) {
case GO_TO_IDLE:
reset_ra(mac, true);
release_mac_configuration(mac, cause);
nr_ue_init_mac(mac);
nr_ue_mac_default_configs(mac);
// new sync but no target cell id -> -1
nr_ue_send_synch_request(mac, module_id, 0, &sync_req);
break;
case DETACH:
LOG_A(NR_MAC, "Received detach indication\n");
reset_ra(mac, true);
reset_mac_inst(mac);
nr_ue_reset_sync_state(mac);
release_mac_configuration(mac, cause);
mac->state = UE_DETACHING;
break;
case T300_EXPIRY:
reset_ra(mac, false);
reset_mac_inst(mac);
mac->state = UE_SYNC; // still in sync but need to restart RA
break;
case RE_ESTABLISHMENT:
reset_mac_inst(mac);
nr_ue_mac_default_configs(mac);
nr_ue_reset_sync_state(mac);
release_mac_configuration(mac, cause);
// new sync with old cell ID (re-establishment on the same cell)
sync_req.target_Nid_cell = mac->physCellId;
sync_req.ssb_bw_scan = false;
nr_ue_send_synch_request(mac, module_id, 0, &sync_req);
break;
default:
AssertFatal(false, "Invalid MAC reset cause %d\n", cause);
}
}
void nr_rrc_mac_config_req_sib1(module_id_t module_id,
int cc_idP,
NR_SI_SchedulingInfo_t *si_SchedulingInfo,
NR_ServingCellConfigCommonSIB_t *scc)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
AssertFatal(scc, "SIB1 SCC should not be NULL\n");
UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
UPDATE_IE(mac->si_SchedulingInfo, si_SchedulingInfo, NR_SI_SchedulingInfo_t);
config_common_ue_sa(mac, scc, cc_idP);
configure_common_BWP_dl(mac,
0, // bwp-id
&scc->downlinkConfigCommon.initialDownlinkBWP);
if (scc->uplinkConfigCommon)
configure_common_BWP_ul(mac,
0, // bwp-id
&scc->uplinkConfigCommon->initialUplinkBWP);
// set current BWP only if coming from non-connected state
// otherwise it is just a periodically update of the SIB1 content
if (mac->state < UE_CONNECTED) {
mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false);
AssertFatal(mac->current_DL_BWP, "Couldn't find DL-BWP0\n");
mac->current_UL_BWP = get_ul_bwp_structure(mac, 0, false);
AssertFatal(mac->current_UL_BWP, "Couldn't find DL-BWP0\n");
}
// Setup the SSB to Rach Occasions mapping according to the config
build_ssb_to_ro_map(mac);
if (!get_softmodem_params()->emulate_l1)
mac->if_module->phy_config_request(&mac->phy_config);
mac->phy_config_request_sent = true;
}
void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id,
NR_SIB19_r17_t *sib19_r17)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
// ntn-Config-r17
UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17, NR_NTN_Config_r17_t);
// TODO handle other SIB19 elements
}
static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
int cc_idP,
const NR_ReconfigurationWithSync_t *reconfigurationWithSync)
{
mac->crnti = reconfigurationWithSync->newUE_Identity;
LOG_I(NR_MAC, "Configuring CRNTI %x\n", mac->crnti);
RA_config_t *ra = &mac->ra;
if (reconfigurationWithSync->rach_ConfigDedicated) {
AssertFatal(
reconfigurationWithSync->rach_ConfigDedicated->present == NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink,
"RACH on supplementaryUplink not supported\n");
UPDATE_IE(ra->rach_ConfigDedicated, reconfigurationWithSync->rach_ConfigDedicated->choice.uplink, NR_RACH_ConfigDedicated_t);
}
if (reconfigurationWithSync->spCellConfigCommon) {
NR_ServingCellConfigCommon_t *scc = reconfigurationWithSync->spCellConfigCommon;
if (scc->physCellId)
mac->physCellId = *scc->physCellId;
mac->dmrs_TypeA_Position = scc->dmrs_TypeA_Position;
UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
config_common_ue(mac, scc, cc_idP);
if (scc->downlinkConfigCommon)
configure_common_BWP_dl(mac,
0, // bwp-id
scc->downlinkConfigCommon->initialDownlinkBWP);
if (scc->uplinkConfigCommon)
configure_common_BWP_ul(mac,
0, // bwp-id
scc->uplinkConfigCommon->initialUplinkBWP);
}
mac->state = UE_NOT_SYNC;
ra->ra_state = nrRA_UE_IDLE;
nr_ue_mac_default_configs(mac);
if (!get_softmodem_params()->emulate_l1) {
mac->synch_request.Mod_id = mac->ue_id;
mac->synch_request.CC_id = cc_idP;
mac->synch_request.synch_req.target_Nid_cell = mac->physCellId;
mac->if_module->synch_request(&mac->synch_request);
mac->if_module->phy_config_request(&mac->phy_config);
mac->phy_config_request_sent = true;
}
}
static void configure_physicalcellgroup(NR_UE_MAC_INST_t *mac,
const NR_PhysicalCellGroupConfig_t *phyConfig)
{
mac->pdsch_HARQ_ACK_Codebook = phyConfig->pdsch_HARQ_ACK_Codebook;
mac->harq_ACK_SpatialBundlingPUCCH = phyConfig->harq_ACK_SpatialBundlingPUCCH ? true : false;
mac->harq_ACK_SpatialBundlingPUSCH = phyConfig->harq_ACK_SpatialBundlingPUSCH ? true : false;
AssertFatal(!phyConfig->ext1 || !phyConfig->ext1->mcs_C_RNTI, "Handling of mcs-C-RNTI not implemented\n");
NR_P_Max_t *p_NR_FR1 = phyConfig->p_NR_FR1;
NR_P_Max_t *p_UE_FR1 = phyConfig->ext1 ? phyConfig->ext1->p_UE_FR1 : NULL;
if (p_NR_FR1 == NULL)
mac->p_Max_alt = p_UE_FR1 == NULL ? INT_MIN : *p_UE_FR1;
else
mac->p_Max_alt = p_UE_FR1 == NULL ? *p_NR_FR1 : (*p_UE_FR1 < *p_NR_FR1 ? *p_UE_FR1 : *p_NR_FR1);
}
static uint32_t get_sr_DelayTimer(long logicalChannelSR_DelayTimer)
{
uint32_t timer = 0;
switch (logicalChannelSR_DelayTimer) {
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf20 :
timer = 20;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf40 :
timer = 40;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf64 :
timer = 64;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf128 :
timer = 128;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf512 :
timer = 512;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf1024 :
timer = 1024;
break;
case NR_BSR_Config__logicalChannelSR_DelayTimer_sf2560 :
timer = 2560;
break;
default :
AssertFatal(false, "Invalid SR_DelayTimer %ld\n", logicalChannelSR_DelayTimer);
}
return timer;
}
static uint32_t nr_get_sf_retxBSRTimer(long retxBSR_Timer)
{
uint32_t timer = 0;
switch (retxBSR_Timer) {
case NR_BSR_Config__retxBSR_Timer_sf10:
timer = 10;
break;
case NR_BSR_Config__retxBSR_Timer_sf20:
timer = 20;
break;
case NR_BSR_Config__retxBSR_Timer_sf40:
timer = 40;
break;
case NR_BSR_Config__retxBSR_Timer_sf80:
timer = 80;
break;
case NR_BSR_Config__retxBSR_Timer_sf160:
timer = 160;
break;
case NR_BSR_Config__retxBSR_Timer_sf320:
timer = 320;
break;
case NR_BSR_Config__retxBSR_Timer_sf640:
timer = 640;
break;
case NR_BSR_Config__retxBSR_Timer_sf1280:
timer = 1280;
break;
case NR_BSR_Config__retxBSR_Timer_sf2560:
timer = 2560;
break;
case NR_BSR_Config__retxBSR_Timer_sf5120:
timer = 5120;
break;
case NR_BSR_Config__retxBSR_Timer_sf10240:
timer = 10240;
break;
default:
AssertFatal(false, "Invalid retxBSR_Timer %ld\n", retxBSR_Timer);
}
return timer;
}
static uint32_t nr_get_sf_periodicBSRTimer(long periodicBSR)
{
uint32_t timer = 0;
switch (periodicBSR) {
case NR_BSR_Config__periodicBSR_Timer_sf1:
timer = 1;
break;
case NR_BSR_Config__periodicBSR_Timer_sf5:
timer = 5;
break;
case NR_BSR_Config__periodicBSR_Timer_sf10:
timer = 10;
break;
case NR_BSR_Config__periodicBSR_Timer_sf16:
timer = 16;
break;
case NR_BSR_Config__periodicBSR_Timer_sf20:
timer = 20;
break;
case NR_BSR_Config__periodicBSR_Timer_sf32:
timer = 32;
break;
case NR_BSR_Config__periodicBSR_Timer_sf40:
timer = 40;
break;
case NR_BSR_Config__periodicBSR_Timer_sf64:
timer = 64;
break;
case NR_BSR_Config__periodicBSR_Timer_sf80:
timer = 80;
break;
case NR_BSR_Config__periodicBSR_Timer_sf128:
timer = 128;
break;
case NR_BSR_Config__periodicBSR_Timer_sf160:
timer = 160;
break;
case NR_BSR_Config__periodicBSR_Timer_sf320:
timer = 320;
break;
case NR_BSR_Config__periodicBSR_Timer_sf640:
timer = 640;
break;
case NR_BSR_Config__periodicBSR_Timer_sf1280:
timer = 1280;
break;
case NR_BSR_Config__periodicBSR_Timer_sf2560:
timer = 2560;
break;
case NR_BSR_Config__periodicBSR_Timer_infinity:
timer = UINT_MAX;
default:
AssertFatal(false, "Invalid periodicBSR_Timer %ld\n", periodicBSR);
}
return timer;
}
static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroupConfig_t *mcg)
{
NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info;
int scs = mac->current_UL_BWP->scs;
if (mcg->drx_Config)
LOG_E(NR_MAC, "DRX not implemented! Configuration not handled!\n");
if (mcg->schedulingRequestConfig) {
const NR_SchedulingRequestConfig_t *src = mcg->schedulingRequestConfig;
if (src->schedulingRequestToReleaseList) {
for (int i = 0; i < src->schedulingRequestToReleaseList->list.count; i++) {
NR_SchedulingRequestId_t id = *src->schedulingRequestToReleaseList->list.array[i];
memset(&si->sr_info[id], 0, sizeof(si->sr_info[id]));
}
}
if (src->schedulingRequestToAddModList) {
for (int i = 0; i < src->schedulingRequestToAddModList->list.count; i++) {
NR_SchedulingRequestToAddMod_t *sr = src->schedulingRequestToAddModList->list.array[i];
nr_sr_info_t *sr_info = &si->sr_info[sr->schedulingRequestId];
sr_info->active_SR_ID = true;
// NR_SchedulingRequestToAddMod__sr_TransMax_n4 = 0 and so on
// to obtain the value to configure we need to right shift 4 by the RRC parameter
sr_info->maxTransmissions = 4 << sr->sr_TransMax;
int target_ms = 0;
if (sr->sr_ProhibitTimer)
target_ms = 1 << *sr->sr_ProhibitTimer;
if (mcg->ext4 && mcg->ext4->schedulingRequestConfig_v1700) {
const NR_SchedulingRequestConfig_v1700_t *src_v1700 = mcg->ext4->schedulingRequestConfig_v1700;
if (src_v1700->schedulingRequestToAddModListExt_v1700) {
if (i < src_v1700->schedulingRequestToAddModListExt_v1700->list.count) {
const NR_SchedulingRequestToAddModExt_v1700_t *sr_v1700 = src_v1700->schedulingRequestToAddModListExt_v1700->list.array[i];
if (sr_v1700->sr_ProhibitTimer_v1700) {
target_ms = 192 + 64 * *sr_v1700->sr_ProhibitTimer_v1700;
}
}
}
}
// length of slot is (1/2^scs)ms
nr_timer_setup(&sr_info->prohibitTimer, target_ms << scs, 1); // 1 slot update rate
}
}
}
if (mcg->bsr_Config) {
int subframes_per_slot = nr_slots_per_frame[scs] / 10;
uint32_t periodic_sf = nr_get_sf_periodicBSRTimer(mcg->bsr_Config->periodicBSR_Timer);
uint32_t target = periodic_sf < UINT_MAX ? periodic_sf * subframes_per_slot : periodic_sf;
nr_timer_setup(&si->periodicBSR_Timer, target, 1); // 1 slot update rate
nr_timer_start(&si->periodicBSR_Timer);
uint32_t retx_sf = nr_get_sf_retxBSRTimer(mcg->bsr_Config->retxBSR_Timer);
nr_timer_setup(&si->retxBSR_Timer, retx_sf * subframes_per_slot, 1); // 1 slot update rate
if (mcg->bsr_Config->logicalChannelSR_DelayTimer) {
uint32_t dt_sf = get_sr_DelayTimer(*mcg->bsr_Config->logicalChannelSR_DelayTimer);
nr_timer_setup(&si->sr_DelayTimer, dt_sf * subframes_per_slot, 1); // 1 slot update rate
}
}
if (mcg->tag_Config) {
// TODO TAG not handled
if(mcg->tag_Config->tag_ToAddModList) {
for (int i = 0; i < mcg->tag_Config->tag_ToAddModList->list.count; i++) {
if (mcg->tag_Config->tag_ToAddModList->list.array[i]->timeAlignmentTimer !=
NR_TimeAlignmentTimer_infinity)
LOG_E(NR_MAC, "TimeAlignmentTimer not handled\n");
}
}
}
if (mcg->phr_Config) {
// TODO configuration when PHR is implemented
}
}
static void configure_csirs_resource(NR_NZP_CSI_RS_Resource_t *target, NR_NZP_CSI_RS_Resource_t *source)
{
configure_csi_resourcemapping(&target->resourceMapping, &source->resourceMapping);
target->powerControlOffset = source->powerControlOffset;
UPDATE_IE(target->powerControlOffsetSS, source->powerControlOffsetSS, long);
target->scramblingID = source->scramblingID;
if (source->periodicityAndOffset)
UPDATE_IE(target->periodicityAndOffset, source->periodicityAndOffset, NR_CSI_ResourcePeriodicityAndOffset_t);
if (source->qcl_InfoPeriodicCSI_RS)
UPDATE_IE(target->qcl_InfoPeriodicCSI_RS, source->qcl_InfoPeriodicCSI_RS, NR_TCI_StateId_t);
}
static void configure_csiim_resource(NR_CSI_IM_Resource_t *target, NR_CSI_IM_Resource_t *source)
{
if (source->csi_IM_ResourceElementPattern)
UPDATE_IE(target->csi_IM_ResourceElementPattern,
source->csi_IM_ResourceElementPattern,
struct NR_CSI_IM_Resource__csi_IM_ResourceElementPattern);
if (source->freqBand)
UPDATE_IE(target->freqBand, source->freqBand, NR_CSI_FrequencyOccupation_t);
if (source->periodicityAndOffset)
UPDATE_IE(target->periodicityAndOffset, source->periodicityAndOffset, NR_CSI_ResourcePeriodicityAndOffset_t);
}
static void modify_csi_measconfig(NR_CSI_MeasConfig_t *source, NR_CSI_MeasConfig_t *target)
{
if (source->reportTriggerSize)
UPDATE_IE(target->reportTriggerSize, source->reportTriggerSize, long);
if (source->semiPersistentOnPUSCH_TriggerStateList)
HANDLE_SETUPRELEASE_IE(target->semiPersistentOnPUSCH_TriggerStateList,
source->semiPersistentOnPUSCH_TriggerStateList,
NR_CSI_SemiPersistentOnPUSCH_TriggerStateList_t,
asn_DEF_NR_SetupRelease_CSI_SemiPersistentOnPUSCH_TriggerStateList);
// NZP-CSI-RS-Resources
if (source->nzp_CSI_RS_ResourceToReleaseList) {
RELEASE_IE_FROMLIST(source->nzp_CSI_RS_ResourceToReleaseList,
target->nzp_CSI_RS_ResourceToAddModList,
nzp_CSI_RS_ResourceId);
}
if (source->nzp_CSI_RS_ResourceToAddModList) {
if (!target->nzp_CSI_RS_ResourceToAddModList)
target->nzp_CSI_RS_ResourceToAddModList = calloc(1, sizeof(*target->nzp_CSI_RS_ResourceToAddModList));
ADDMOD_IE_FROMLIST_WFUNCTION(source->nzp_CSI_RS_ResourceToAddModList,
target->nzp_CSI_RS_ResourceToAddModList,
nzp_CSI_RS_ResourceId,
NR_NZP_CSI_RS_Resource_t,
configure_csirs_resource);
}
// NZP-CSI-RS-ResourceSets
if (source->nzp_CSI_RS_ResourceSetToReleaseList) {
RELEASE_IE_FROMLIST(source->nzp_CSI_RS_ResourceSetToReleaseList,
target->nzp_CSI_RS_ResourceSetToAddModList,
nzp_CSI_ResourceSetId);
}
if (source->nzp_CSI_RS_ResourceSetToAddModList) {
if (!target->nzp_CSI_RS_ResourceSetToAddModList)
target->nzp_CSI_RS_ResourceSetToAddModList = calloc(1, sizeof(*target->nzp_CSI_RS_ResourceSetToAddModList));
ADDMOD_IE_FROMLIST(source->nzp_CSI_RS_ResourceSetToAddModList,
target->nzp_CSI_RS_ResourceSetToAddModList,
nzp_CSI_ResourceSetId,
NR_NZP_CSI_RS_ResourceSet_t);
}
// CSI-IM-Resource
if (source->csi_IM_ResourceToReleaseList) {
RELEASE_IE_FROMLIST(source->csi_IM_ResourceToReleaseList,
target->csi_IM_ResourceToAddModList,
csi_IM_ResourceId);
}
if (source->csi_IM_ResourceToAddModList) {
if (!target->csi_IM_ResourceToAddModList)
target->csi_IM_ResourceToAddModList = calloc(1, sizeof(*target->csi_IM_ResourceToAddModList));
ADDMOD_IE_FROMLIST_WFUNCTION(source->csi_IM_ResourceToAddModList,
target->csi_IM_ResourceToAddModList,
csi_IM_ResourceId,
NR_CSI_IM_Resource_t,
configure_csiim_resource);
}
// CSI-IM-ResourceSets
if (source->csi_IM_ResourceSetToReleaseList) {
RELEASE_IE_FROMLIST(source->csi_IM_ResourceSetToReleaseList,
target->csi_IM_ResourceSetToAddModList,
csi_IM_ResourceSetId);
}
if (source->csi_IM_ResourceSetToAddModList) {
if (!target->csi_IM_ResourceSetToAddModList)
target->csi_IM_ResourceSetToAddModList = calloc(1, sizeof(*target->csi_IM_ResourceSetToAddModList));
ADDMOD_IE_FROMLIST(source->csi_IM_ResourceSetToAddModList,
target->csi_IM_ResourceSetToAddModList,
csi_IM_ResourceSetId,
NR_CSI_IM_ResourceSet_t);
}
// CSI-SSB-ResourceSets
if (source->csi_SSB_ResourceSetToReleaseList) {
RELEASE_IE_FROMLIST(source->csi_SSB_ResourceSetToReleaseList,
target->csi_SSB_ResourceSetToAddModList,
csi_SSB_ResourceSetId);
}
if (source->csi_SSB_ResourceSetToAddModList) {
if (!target->csi_SSB_ResourceSetToAddModList)
target->csi_SSB_ResourceSetToAddModList = calloc(1, sizeof(*target->csi_SSB_ResourceSetToAddModList));
ADDMOD_IE_FROMLIST(source->csi_SSB_ResourceSetToAddModList,
target->csi_SSB_ResourceSetToAddModList,
csi_SSB_ResourceSetId,
NR_CSI_SSB_ResourceSet_t);
}
// CSI-ResourceConfigs
if (source->csi_ResourceConfigToReleaseList) {
RELEASE_IE_FROMLIST(source->csi_ResourceConfigToReleaseList,
target->csi_ResourceConfigToAddModList,
csi_ResourceConfigId);
}
if (source->csi_ResourceConfigToAddModList) {
if (!target->csi_ResourceConfigToAddModList)
target->csi_ResourceConfigToAddModList = calloc(1, sizeof(*target->csi_ResourceConfigToAddModList));
ADDMOD_IE_FROMLIST(source->csi_ResourceConfigToAddModList,
target->csi_ResourceConfigToAddModList,
csi_ResourceConfigId,
NR_CSI_ResourceConfig_t);
}
// CSI-ReportConfigs
if (source->csi_ReportConfigToReleaseList) {
RELEASE_IE_FROMLIST(source->csi_ReportConfigToReleaseList,
target->csi_ReportConfigToAddModList,
reportConfigId);
}
if (source->csi_ReportConfigToAddModList) {
if (!target->csi_ReportConfigToAddModList)
target->csi_ReportConfigToAddModList = calloc(1, sizeof(*target->csi_ReportConfigToAddModList));
ADDMOD_IE_FROMLIST(source->csi_ReportConfigToAddModList,
target->csi_ReportConfigToAddModList,
reportConfigId,
NR_CSI_ReportConfig_t);
}
}
static void configure_csiconfig(NR_UE_ServingCell_Info_t *sc_info, struct NR_SetupRelease_CSI_MeasConfig *csi_MeasConfig_sr)
{
switch (csi_MeasConfig_sr->present) {
case NR_SetupRelease_CSI_MeasConfig_PR_NOTHING:
break;
case NR_SetupRelease_CSI_MeasConfig_PR_release:
asn1cFreeStruc(asn_DEF_NR_CSI_MeasConfig, sc_info->csi_MeasConfig);
asn1cFreeStruc(asn_DEF_NR_CSI_AperiodicTriggerStateList, sc_info->aperiodicTriggerStateList);
break;
case NR_SetupRelease_CSI_MeasConfig_PR_setup: {
// separately handling aperiodicTriggerStateList
// because it is set directly into sc_info structure
if (csi_MeasConfig_sr->choice.setup->aperiodicTriggerStateList)
HANDLE_SETUPRELEASE_DIRECT(sc_info->aperiodicTriggerStateList,
csi_MeasConfig_sr->choice.setup->aperiodicTriggerStateList,
NR_CSI_AperiodicTriggerStateList_t,
asn_DEF_NR_CSI_AperiodicTriggerStateList);
if (!sc_info->csi_MeasConfig) { // setup
UPDATE_IE(sc_info->csi_MeasConfig, csi_MeasConfig_sr->choice.setup, NR_CSI_MeasConfig_t);
} else { // modification
modify_csi_measconfig(csi_MeasConfig_sr->choice.setup, sc_info->csi_MeasConfig);
}
break;
}
default:
AssertFatal(false, "Invalid case\n");
}
}
static void configure_servingcell_info(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd)
{
NR_UE_ServingCell_Info_t *sc_info = &mac->sc_info;
if (scd->csi_MeasConfig) {
configure_csiconfig(sc_info, scd->csi_MeasConfig);
compute_csi_bitlen(sc_info->csi_MeasConfig, mac->csi_report_template);
}
if (scd->supplementaryUplink)
UPDATE_IE(sc_info->supplementaryUplink, scd->supplementaryUplink, NR_UplinkConfig_t);
if (scd->crossCarrierSchedulingConfig)
UPDATE_IE(sc_info->crossCarrierSchedulingConfig, scd->crossCarrierSchedulingConfig, NR_CrossCarrierSchedulingConfig_t);
if (scd->pdsch_ServingCellConfig) {
switch (scd->pdsch_ServingCellConfig->present) {
case NR_SetupRelease_PDSCH_ServingCellConfig_PR_NOTHING:
break;
case NR_SetupRelease_PDSCH_ServingCellConfig_PR_release:
// release all configurations
if (sc_info->pdsch_CGB_Transmission)
asn1cFreeStruc(asn_DEF_NR_PDSCH_CodeBlockGroupTransmission, sc_info->pdsch_CGB_Transmission);
if (sc_info->xOverhead_PDSCH) {
free(sc_info->xOverhead_PDSCH);
sc_info->xOverhead_PDSCH = NULL;
}
if (sc_info->maxMIMO_Layers_PDSCH) {
free(sc_info->maxMIMO_Layers_PDSCH);
sc_info->maxMIMO_Layers_PDSCH = NULL;
}
if (sc_info->downlinkHARQ_FeedbackDisabled_r17)
asn1cFreeStruc(asn_DEF_NR_DownlinkHARQ_FeedbackDisabled_r17, sc_info->downlinkHARQ_FeedbackDisabled_r17);
break;
case NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup: {
NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = scd->pdsch_ServingCellConfig->choice.setup;
if (pdsch_servingcellconfig->codeBlockGroupTransmission)
HANDLE_SETUPRELEASE_DIRECT(sc_info->pdsch_CGB_Transmission,
pdsch_servingcellconfig->codeBlockGroupTransmission,
NR_PDSCH_CodeBlockGroupTransmission_t,
asn_DEF_NR_PDSCH_CodeBlockGroupTransmission);
UPDATE_IE(sc_info->xOverhead_PDSCH, pdsch_servingcellconfig->xOverhead, long);
if (pdsch_servingcellconfig->ext1 && pdsch_servingcellconfig->ext1->maxMIMO_Layers)
UPDATE_IE(sc_info->maxMIMO_Layers_PDSCH, pdsch_servingcellconfig->ext1->maxMIMO_Layers, long);
if (pdsch_servingcellconfig->ext3 && pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17) {
switch (pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->present) {
case NR_SetupRelease_DownlinkHARQ_FeedbackDisabled_r17_PR_NOTHING:
break;
case NR_SetupRelease_DownlinkHARQ_FeedbackDisabled_r17_PR_release:
if (sc_info->downlinkHARQ_FeedbackDisabled_r17)
asn1cFreeStruc(asn_DEF_NR_DownlinkHARQ_FeedbackDisabled_r17, sc_info->downlinkHARQ_FeedbackDisabled_r17);
break;
case NR_SetupRelease_DownlinkHARQ_FeedbackDisabled_r17_PR_setup:
if (sc_info->downlinkHARQ_FeedbackDisabled_r17 == NULL) {
sc_info->downlinkHARQ_FeedbackDisabled_r17 = calloc(1, sizeof(*sc_info->downlinkHARQ_FeedbackDisabled_r17));
sc_info->downlinkHARQ_FeedbackDisabled_r17->buf = calloc(4, sizeof(*sc_info->downlinkHARQ_FeedbackDisabled_r17->buf));
}
sc_info->downlinkHARQ_FeedbackDisabled_r17->size = pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->choice.setup.size;
sc_info->downlinkHARQ_FeedbackDisabled_r17->bits_unused = pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->choice.setup.bits_unused;
for (int i = 0; i < sc_info->downlinkHARQ_FeedbackDisabled_r17->size; i++)
sc_info->downlinkHARQ_FeedbackDisabled_r17->buf[i] = pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->choice.setup.buf[i];
break;
default:
AssertFatal(false, "Invalid case\n");
}
}
break;
}
default:
AssertFatal(false, "Invalid case\n");
}
}
if (scd->uplinkConfig && scd->uplinkConfig->pusch_ServingCellConfig) {
switch (scd->uplinkConfig->pusch_ServingCellConfig->present) {
case NR_SetupRelease_PUSCH_ServingCellConfig_PR_NOTHING:
break;
case NR_SetupRelease_PUSCH_ServingCellConfig_PR_release:
// release all configurations
if (sc_info->pusch_CGB_Transmission)
asn1cFreeStruc(asn_DEF_NR_PUSCH_CodeBlockGroupTransmission, sc_info->pusch_CGB_Transmission);
if (sc_info->rateMatching_PUSCH) {
free(sc_info->rateMatching_PUSCH);
sc_info->rateMatching_PUSCH = NULL;
}
if (sc_info->xOverhead_PUSCH) {
free(sc_info->xOverhead_PUSCH);
sc_info->xOverhead_PUSCH = NULL;
}
if (sc_info->maxMIMO_Layers_PUSCH) {
free(sc_info->maxMIMO_Layers_PUSCH);
sc_info->maxMIMO_Layers_PUSCH = NULL;
}
break;
case NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup: {
NR_PUSCH_ServingCellConfig_t *pusch_servingcellconfig = scd->uplinkConfig->pusch_ServingCellConfig->choice.setup;
UPDATE_IE(sc_info->rateMatching_PUSCH, pusch_servingcellconfig->rateMatching, long);
UPDATE_IE(sc_info->xOverhead_PUSCH, pusch_servingcellconfig->xOverhead, long);
if (pusch_servingcellconfig->ext1 && pusch_servingcellconfig->ext1->maxMIMO_Layers)
UPDATE_IE(sc_info->maxMIMO_Layers_PUSCH, pusch_servingcellconfig->ext1->maxMIMO_Layers, long);
if (pusch_servingcellconfig->codeBlockGroupTransmission)
HANDLE_SETUPRELEASE_DIRECT(sc_info->pusch_CGB_Transmission,
pusch_servingcellconfig->codeBlockGroupTransmission,
NR_PUSCH_CodeBlockGroupTransmission_t,
asn_DEF_NR_PUSCH_CodeBlockGroupTransmission);
break;
}
default:
AssertFatal(false, "Invalid case\n");
}
}
}
/// This function implements 38.331 Section 5.3.12: UE actions upon PUCCH/SRS release request
void release_PUCCH_SRS(NR_UE_MAC_INST_t *mac)
{
// release PUCCH-CSI-Resources configured in CSI-ReportConfig
NR_UE_ServingCell_Info_t *sc_info = &mac->sc_info;
NR_CSI_MeasConfig_t *meas_config = sc_info->csi_MeasConfig;
if (meas_config && meas_config->csi_ReportConfigToAddModList) {
for (int i = 0; i < meas_config->csi_ReportConfigToAddModList->list.count; i++) {
struct NR_CSI_ReportConfig__reportConfigType *type = &meas_config->csi_ReportConfigToAddModList->list.array[i]->reportConfigType;
switch (type->present) {
case NR_CSI_ReportConfig__reportConfigType_PR_periodic :
for (int j = type->choice.periodic->pucch_CSI_ResourceList.list.count; j > 0 ; j--)
asn_sequence_del(&type->choice.periodic->pucch_CSI_ResourceList.list, j - 1, 1);
break;
case NR_CSI_ReportConfig__reportConfigType_PR_semiPersistentOnPUCCH :
for (int j = type->choice.semiPersistentOnPUCCH->pucch_CSI_ResourceList.list.count; j > 0 ; j--)
asn_sequence_del(&type->choice.semiPersistentOnPUCCH->pucch_CSI_ResourceList.list, j - 1, 1);
break;
case NR_CSI_ReportConfig__reportConfigType_PR_semiPersistentOnPUSCH :
case NR_CSI_ReportConfig__reportConfigType_PR_aperiodic :
// no PUCCH config to release
break;
default :
AssertFatal(false, "Invalid CSI report type\n");
}
}
}
for (int bwp = 0; bwp < mac->ul_BWPs.count; bwp++) {
// release SchedulingRequestResourceConfig instances configured in PUCCH-Config
NR_PUCCH_Config_t *pucch_Config = mac->ul_BWPs.array[bwp]->pucch_Config;
if (pucch_Config)
for (int j = pucch_Config->schedulingRequestResourceToAddModList->list.count; j > 0 ; j--)
asn_sequence_del(&pucch_Config->schedulingRequestResourceToAddModList->list, j - 1, 1);
// release SRS-Resource instances configured in SRS-Config
// TODO not clear if only SRS-Resources or also the ResourceSet should be released
NR_SRS_Config_t *srs_Config = mac->ul_BWPs.array[bwp]->srs_Config;
if (srs_Config)
for (int j = srs_Config->srs_ResourceToAddModList->list.count; j > 0 ; j--)
asn_sequence_del(&srs_Config->srs_ResourceToAddModList->list, j - 1, 1);
}
}
void release_dl_BWP(NR_UE_MAC_INST_t *mac, int index)
{
NR_UE_DL_BWP_t *bwp = mac->dl_BWPs.array[index];
int bwp_id = bwp->bwp_id;
asn_sequence_del(&mac->dl_BWPs, index, 0);
free(bwp->cyclicprefix);
asn1cFreeStruc(asn_DEF_NR_PDSCH_TimeDomainResourceAllocationList, bwp->tdaList_Common);
asn1cFreeStruc(asn_DEF_NR_PDSCH_Config, bwp->pdsch_Config);
free(bwp);
NR_BWP_PDCCH_t *pdcch = &mac->config_BWP_PDCCH[bwp_id];
release_common_ss_cset(pdcch);
for (int i = pdcch->list_Coreset.count; i > 0 ; i--)
asn_sequence_del(&pdcch->list_Coreset, i - 1, 1);
for (int i = pdcch->list_SS.count; i > 0 ; i--)
asn_sequence_del(&pdcch->list_SS, i - 1, 1);
}
void release_ul_BWP(NR_UE_MAC_INST_t *mac, int index)
{
NR_UE_UL_BWP_t *bwp = mac->ul_BWPs.array[index];
asn_sequence_del(&mac->ul_BWPs, index, 0);
free(bwp->cyclicprefix);
asn1cFreeStruc(asn_DEF_NR_RACH_ConfigCommon, bwp->rach_ConfigCommon);
asn1cFreeStruc(asn_DEF_NR_PUSCH_TimeDomainResourceAllocationList, bwp->tdaList_Common);
asn1cFreeStruc(asn_DEF_NR_ConfiguredGrantConfig, bwp->configuredGrantConfig);
asn1cFreeStruc(asn_DEF_NR_PUSCH_Config, bwp->pusch_Config);
asn1cFreeStruc(asn_DEF_NR_PUCCH_Config, bwp->pucch_Config);
asn1cFreeStruc(asn_DEF_NR_PUCCH_ConfigCommon, bwp->pucch_ConfigCommon);
asn1cFreeStruc(asn_DEF_NR_SRS_Config, bwp->srs_Config);
free(bwp->msg3_DeltaPreamble);
bwp->msg3_DeltaPreamble = NULL;
free(bwp->p0_NominalWithGrant);
bwp->p0_NominalWithGrant = NULL;
free(bwp);
}
static void configure_BWPs(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd)
{
configure_dedicated_BWP_dl(mac, 0, scd->initialDownlinkBWP);
if (scd->downlinkBWP_ToReleaseList) {
for (int i = 0; i < scd->downlinkBWP_ToReleaseList->list.count; i++) {
for (int j = 0; j < mac->dl_BWPs.count; j++) {
if (*scd->downlinkBWP_ToReleaseList->list.array[i] == mac->dl_BWPs.array[i]->bwp_id)
release_dl_BWP(mac, i);
}
}
}
if (scd->downlinkBWP_ToAddModList) {
for (int i = 0; i < scd->downlinkBWP_ToAddModList->list.count; i++) {
NR_BWP_Downlink_t *bwp = scd->downlinkBWP_ToAddModList->list.array[i];
configure_common_BWP_dl(mac, bwp->bwp_Id, bwp->bwp_Common);
configure_dedicated_BWP_dl(mac, bwp->bwp_Id, bwp->bwp_Dedicated);
}
}
if (scd->firstActiveDownlinkBWP_Id) {
mac->current_DL_BWP = get_dl_bwp_structure(mac, *scd->firstActiveDownlinkBWP_Id, false);
AssertFatal(mac->current_DL_BWP, "Couldn't find DL-BWP %ld\n", *scd->firstActiveDownlinkBWP_Id);
}
if (scd->uplinkConfig) {
configure_dedicated_BWP_ul(mac, 0, scd->uplinkConfig->initialUplinkBWP);
if (scd->uplinkConfig->uplinkBWP_ToReleaseList) {
for (int i = 0; i < scd->uplinkConfig->uplinkBWP_ToReleaseList->list.count; i++) {
for (int j = 0; j < mac->ul_BWPs.count; j++) {
if (*scd->uplinkConfig->uplinkBWP_ToReleaseList->list.array[i] == mac->ul_BWPs.array[i]->bwp_id)
release_ul_BWP(mac, i);
}
}
}
if (scd->uplinkConfig->uplinkBWP_ToAddModList) {
for (int i = 0; i < scd->uplinkConfig->uplinkBWP_ToAddModList->list.count; i++) {
NR_BWP_Uplink_t *bwp = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[i];
configure_common_BWP_ul(mac, bwp->bwp_Id, bwp->bwp_Common);
configure_dedicated_BWP_ul(mac, bwp->bwp_Id, bwp->bwp_Dedicated);
}
}
if (scd->uplinkConfig->firstActiveUplinkBWP_Id) {
mac->current_UL_BWP = get_ul_bwp_structure(mac, *scd->uplinkConfig->firstActiveUplinkBWP_Id, false);
AssertFatal(mac->current_UL_BWP, "Couldn't find UL-BWP %ld\n", *scd->uplinkConfig->firstActiveUplinkBWP_Id);
}
}
}
static void handle_mac_uecap_info(NR_UE_MAC_INST_t *mac, NR_UE_NR_Capability_t *ue_Capability)
{
if (!ue_Capability->featureSets)
return;
if (ue_Capability->featureSets->featureSetsDownlinkPerCC) {
struct NR_FeatureSets__featureSetsDownlinkPerCC *fs_dlcc_list = ue_Capability->featureSets->featureSetsDownlinkPerCC;
for (int i = 0; i < fs_dlcc_list->list.count; i++) {
NR_FeatureSetDownlinkPerCC_t *fs_dl_cc = fs_dlcc_list->list.array[i];
if (mac->current_DL_BWP->scs != fs_dl_cc->supportedSubcarrierSpacingDL)
continue;
int dl_bw_mhz = mac->phy_config.config_req.carrier_config.dl_bandwidth;
if (!supported_bw_comparison(dl_bw_mhz, &fs_dl_cc->supportedBandwidthDL, fs_dl_cc->channelBW_90mhz))
continue;
if (fs_dl_cc->maxNumberMIMO_LayersPDSCH)
mac->uecap_maxMIMO_PDSCH_layers = 2 << *fs_dl_cc->maxNumberMIMO_LayersPDSCH;
}
}
if (ue_Capability->featureSets->featureSetsUplinkPerCC) {
struct NR_FeatureSets__featureSetsUplinkPerCC *fs_ulcc_list = ue_Capability->featureSets->featureSetsUplinkPerCC;
for (int i = 0; i < fs_ulcc_list->list.count; i++) {
NR_FeatureSetUplinkPerCC_t *fs_ul_cc = fs_ulcc_list->list.array[i];
if (mac->current_UL_BWP->scs != fs_ul_cc->supportedSubcarrierSpacingUL)
continue;
int ul_bw_mhz = mac->phy_config.config_req.carrier_config.uplink_bandwidth;
if (!supported_bw_comparison(ul_bw_mhz, &fs_ul_cc->supportedBandwidthUL, fs_ul_cc->channelBW_90mhz))
continue;
if (fs_ul_cc->maxNumberMIMO_LayersNonCB_PUSCH)
mac->uecap_maxMIMO_PUSCH_layers_nocb = 1 << *fs_ul_cc->maxNumberMIMO_LayersNonCB_PUSCH;
if (fs_ul_cc->mimo_CB_PUSCH && fs_ul_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH)
mac->uecap_maxMIMO_PUSCH_layers_cb = 1 << *fs_ul_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH;
}
}
}
void nr_rrc_mac_config_req_cg(module_id_t module_id,
int cc_idP,
NR_CellGroupConfig_t *cell_group_config,
NR_UE_NR_Capability_t *ue_Capability)
{
LOG_I(MAC,"[UE %d] Applying CellGroupConfig from gNodeB\n", module_id);
AssertFatal(cell_group_config, "CellGroupConfig should not be NULL\n");
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
if (cell_group_config->physicalCellGroupConfig)
configure_physicalcellgroup(mac, cell_group_config->physicalCellGroupConfig);
if (cell_group_config->spCellConfig) {
NR_SpCellConfig_t *spCellConfig = cell_group_config->spCellConfig;
NR_ServingCellConfig_t *scd = spCellConfig->spCellConfigDedicated;
mac->servCellIndex = spCellConfig->servCellIndex ? *spCellConfig->servCellIndex : 0;
if (spCellConfig->reconfigurationWithSync) {
LOG_A(NR_MAC, "Received reconfigurationWithSync\n");
handle_reconfiguration_with_sync(mac, cc_idP, spCellConfig->reconfigurationWithSync);
}
if (scd) {
configure_servingcell_info(mac, scd);
configure_BWPs(mac, scd);
}
}
if (cell_group_config->mac_CellGroupConfig)
configure_maccellgroup(mac, cell_group_config->mac_CellGroupConfig);
configure_logicalChannelBearer(mac,
cell_group_config->rlc_BearerToAddModList,
cell_group_config->rlc_BearerToReleaseList);
if (ue_Capability)
handle_mac_uecap_info(mac, ue_Capability);
// Setup the SSB to Rach Occasions mapping according to the config
// Only if RACH is configured for current BWP
if (mac->current_UL_BWP->rach_ConfigCommon)
build_ssb_to_ro_map(mac);
if (!mac->dl_config_request || !mac->ul_config_request)
ue_init_config_request(mac, mac->current_DL_BWP->scs);
}