mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
When the gNB answers RRCReestablishmentRequest with RRCSetup (TS 38.331 clause 5.3.3.4 fallback), the UE must release all bearers except SRB0 before applying the new masterCellGroup. CONFIG_RESET was queued after RLC release, so the MAC slot thread kept polling LCID 1 from a stale lc_ordered_list while the RLC entity was already NULL. Queue NR_MAC_RRC_CONFIG_RESET (RRC_SETUP_REESTAB_RESUME) first, then release PDCP, RLC, and SDAP. On the MAC thread, clear lc_ordered_list except SRB0 before release_mac_configuration() so the UL scheduler stops looping released logical channels until CONFIG_CG re-adds SRB1. Changes: - rrc_UE.c: move CONFIG_RESET to the start of nr_rrc_rrcsetup_fallback() - config_ue.c: drop non-SRB0 lc_ordered_list entries on RRC_SETUP_REESTAB_RESUME Closes: #128 Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
3029 lines
137 KiB
C
3029 lines
137 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
/*
|
|
* \brief UE configuration performed by RRC or as a consequence of RRC procedures
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include "mac_defs.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 "RRC/NR_UE/verify_RRC.h"
|
|
#include "RRC/NR_UE/L2_interface_ue.h"
|
|
#include "oai_asn1.h"
|
|
|
|
#define ASIGN_P_VAL(dst, src) \
|
|
do { \
|
|
if (src) \
|
|
dst = *src; \
|
|
else \
|
|
dst = -1; \
|
|
} while (0)
|
|
|
|
// Build the list of all the valid/transmitted SSBs according to the config
|
|
static void build_ssb_list(NR_UE_MAC_INST_t *mac)
|
|
{
|
|
// Create the list of transmitted SSBs
|
|
memset(&mac->ssb_list, 0, sizeof(ssb_list_info_t));
|
|
ssb_list_info_t *ssb_list = &mac->ssb_list;
|
|
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
|
|
ssb_list->nb_tx_ssb = 0;
|
|
|
|
for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
|
|
uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask;
|
|
// check if if current SSB is transmitted
|
|
if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) {
|
|
ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb;
|
|
ssb_list->nb_tx_ssb++;
|
|
} else
|
|
ssb_list->nb_ssb_per_index[ssb_index] = -1;
|
|
}
|
|
}
|
|
|
|
static int get_ta_offset(long *n_TimingAdvanceOffset)
|
|
{
|
|
if (!n_TimingAdvanceOffset)
|
|
return -1;
|
|
|
|
switch (*n_TimingAdvanceOffset) {
|
|
case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n0 :
|
|
return 0;
|
|
case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n25600 :
|
|
return 25600;
|
|
case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n39936 :
|
|
return 39936;
|
|
default :
|
|
AssertFatal(false, "Invalid n-TimingAdvanceOffset\n");
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, const frame_structure_t *fs)
|
|
{
|
|
tdd_table->tdd_period_in_slots = fs->numb_slots_period;
|
|
tdd_table->max_tdd_periodicity_list = malloc(fs->numb_slots_period * sizeof(*tdd_table->max_tdd_periodicity_list));
|
|
|
|
const tdd_period_config_t *pc = &fs->period_cfg;
|
|
for (int i = 0; i < fs->numb_slots_period; i++) {
|
|
fapi_nr_max_tdd_periodicity_t *period_list = &tdd_table->max_tdd_periodicity_list[i];
|
|
period_list->max_num_of_symbol_per_slot_list =
|
|
malloc(NR_SYMBOLS_PER_SLOT * sizeof(*period_list->max_num_of_symbol_per_slot_list));
|
|
if (pc->tdd_slot_bitmap[i].slot_type == TDD_NR_DOWNLINK_SLOT) {
|
|
for (int s = 0; s < NR_SYMBOLS_PER_SLOT; s++) {
|
|
period_list->max_num_of_symbol_per_slot_list[s].slot_config = 0;
|
|
}
|
|
}
|
|
if (pc->tdd_slot_bitmap[i].slot_type == TDD_NR_UPLINK_SLOT) {
|
|
for (int s = 0; s < NR_SYMBOLS_PER_SLOT; s++) {
|
|
period_list->max_num_of_symbol_per_slot_list[s].slot_config = 1;
|
|
}
|
|
}
|
|
if (pc->tdd_slot_bitmap[i].slot_type == TDD_NR_MIXED_SLOT) {
|
|
int dl_symb = pc->tdd_slot_bitmap[i].num_dl_symbols;
|
|
int ul_symb = pc->tdd_slot_bitmap[i].num_ul_symbols;
|
|
int g_symb = NR_SYMBOLS_PER_SLOT - dl_symb - ul_symb;
|
|
for (int s = 0; s < dl_symb; s++) {
|
|
period_list->max_num_of_symbol_per_slot_list[s].slot_config = 0;
|
|
}
|
|
for (int s = dl_symb; s < dl_symb + g_symb; s++) {
|
|
period_list->max_num_of_symbol_per_slot_list[s].slot_config = 2;
|
|
}
|
|
for (int s = dl_symb + g_symb; s < NR_SYMBOLS_PER_SLOT; s++) {
|
|
period_list->max_num_of_symbol_per_slot_list[s].slot_config = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
AssertFatal(mac->numerology == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing, "DL and SSB subcarrierSpacing must be the same!\n");
|
|
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);
|
|
|
|
/** Only set frequency if not already initialized (e.g., from handover reconfigurationWithSync)
|
|
* MAC maintains its own frequency state, don't overwrite it with command-line parameter which
|
|
* is related to the initial cell selection. */
|
|
if (cfg->carrier_config.dl_frequency == 0) {
|
|
// Initial cell selection: derive from command-line parameter
|
|
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 = mac->dl_frequency / 1000 - (dl_bw_khz >> 1);
|
|
LOG_I(NR_MAC,
|
|
"[UE %d] Initial cell selection: dl_frequency=%u kHz (from command-line, band=%d, scs=%ld)\n",
|
|
mac->ue_id,
|
|
cfg->carrier_config.dl_frequency,
|
|
mac->nr_band,
|
|
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
|
|
}
|
|
|
|
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;
|
|
|
|
AssertFatal(mac->numerology == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing, "UL and SSB subcarrierSpacing must be the same!\n");
|
|
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);
|
|
|
|
/** Only set UL frequency if not already initialized (e.g., from handover reconfigurationWithSync)
|
|
* MAC maintains its own frequency state, don't overwrite it with command-line parameter which
|
|
* is related to the initial cell selection. */
|
|
if (cfg->carrier_config.uplink_frequency == 0) {
|
|
// Initial cell selection: derive from DL frequency or frequencyInfoUL->absoluteFrequencyPointA
|
|
if (frequencyInfoUL->absoluteFrequencyPointA == NULL) {
|
|
cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency;
|
|
LOG_I(NR_MAC,
|
|
"Initial cell selection: uplink_frequency=%u kHz (from dl_frequency=%u kHz)\n",
|
|
cfg->carrier_config.uplink_frequency,
|
|
cfg->carrier_config.dl_frequency);
|
|
} else {
|
|
cfg->carrier_config.uplink_frequency = from_nrarfcn(*frequencyInfoUL->frequencyBandList->list.array[0]->freqBandIndicatorNR,
|
|
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
|
|
*frequencyInfoUL->absoluteFrequencyPointA)
|
|
/ 1000; // freq in kHz
|
|
LOG_I(NR_MAC,
|
|
"Initial cell selection: uplink_frequency=%u kHz (from absoluteFrequencyPointA=%ld, band=%ld, scs=%ld)\n",
|
|
cfg->carrier_config.uplink_frequency,
|
|
*frequencyInfoUL->absoluteFrequencyPointA,
|
|
*frequencyInfoUL->frequencyBandList->list.array[0]->freqBandIndicatorNR,
|
|
frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
frame_type_t frame_type = get_frame_type(mac->nr_band, mac->numerology);
|
|
// cell config
|
|
cfg->cell_config.phy_cell_id = mac->physCellId;
|
|
cfg->cell_config.frame_duplex_type = frame_type;
|
|
cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
|
|
|
|
// SSB config
|
|
cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
|
|
cfg->ssb_config.scs_common = mac->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;
|
|
cfg->ssb_table.ssb_case = set_ssb_case(mac->numerology, mac->nr_band);
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
int period_idx = mac->tdd_UL_DL_ConfigurationCommon ? get_tdd_period_idx(mac->tdd_UL_DL_ConfigurationCommon) : 0;
|
|
config_frame_structure(mac->numerology,
|
|
mac->tdd_UL_DL_ConfigurationCommon,
|
|
period_idx,
|
|
frame_type,
|
|
&mac->frame_structure);
|
|
|
|
// TDD Table Configuration
|
|
if (cfg->cell_config.frame_duplex_type == TDD)
|
|
set_tdd_config_nr_ue(&cfg->tdd_table, &mac->frame_structure);
|
|
|
|
// 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;
|
|
int format = get_format0(config_index, frame_type, mac->frequency_range);
|
|
cfg->prach_config.prach_sub_c_spacing = get_delta_f_RA_long(format);
|
|
}
|
|
|
|
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,
|
|
frame_type,
|
|
mac->frequency_range);
|
|
//prach_fd_occasion->num_unused_root_sequences = ???
|
|
}
|
|
}
|
|
|
|
// prepare data for orbit propagation based on SIB19 ephemeris data to be able to compute the round-trip-time between ue and sat
|
|
static void prepare_ue_sat_ta(const NR_PositionVelocity_r17_t *sat_pos, fapi_nr_ntn_config_t *ntn_ta)
|
|
{
|
|
// get sat position coordinates
|
|
const position_t pos_sat = {sat_pos->positionX_r17 * 1.3, sat_pos->positionY_r17 * 1.3, sat_pos->positionZ_r17 * 1.3};
|
|
|
|
// get sat velocity vector
|
|
const position_t vel_sat = {sat_pos->velocityVX_r17 * 0.06, sat_pos->velocityVY_r17 * 0.06, sat_pos->velocityVZ_r17 * 0.06};
|
|
|
|
// calculate orbital radius
|
|
const double radius_2 = pos_sat.X * pos_sat.X + pos_sat.Y * pos_sat.Y + pos_sat.Z * pos_sat.Z;
|
|
const double radius = sqrt(radius_2);
|
|
|
|
// calculate sat velocity magnitude
|
|
const double vel_sat_2 = vel_sat.X * vel_sat.X + vel_sat.Y * vel_sat.Y + vel_sat.Z * vel_sat.Z;
|
|
const double vel_mag = sqrt(vel_sat_2);
|
|
|
|
double omega; // angular velocity in rad/ms
|
|
position_t pos_sat_90; // sat position vector in 90° orbit
|
|
position_t vel_sat_90; // sat velocity vector in 90° orbit
|
|
|
|
// assuming circular orbit when satellite moves faster than 1000 m/s
|
|
// 1000 m/s are chosen because according to Wikipedia, this seems to be a reasonable minimal
|
|
// orbital velocity: https://en.wikipedia.org/wiki/Orbital_speed#Tangential_velocities_at_altitude
|
|
if (vel_mag > 1000) {
|
|
omega = vel_mag / (radius * 1000);
|
|
double scaling = radius / vel_mag;
|
|
pos_sat_90 = (position_t){vel_sat.X * scaling, vel_sat.Y * scaling, vel_sat.Z * scaling};
|
|
scaling = -vel_mag / radius;
|
|
vel_sat_90 = (position_t){pos_sat.X * scaling, pos_sat.Y * scaling, pos_sat.Z * scaling};
|
|
} else {
|
|
omega = 0;
|
|
pos_sat_90 = pos_sat;
|
|
vel_sat_90 = vel_sat;
|
|
}
|
|
|
|
LOG_I(NR_MAC,
|
|
"Satellite orbital radius %f m, pos_sat_0 = {%f, %f, %f}, pos_sat_90 = {%f, %f, %f}\n",
|
|
radius,
|
|
pos_sat.X,
|
|
pos_sat.Y,
|
|
pos_sat.Z,
|
|
pos_sat_90.X,
|
|
pos_sat_90.Y,
|
|
pos_sat_90.Z);
|
|
|
|
LOG_I(NR_MAC,
|
|
"Satellite velocity %f m/s, angular velocity = %e rad/ms, vel_sat_0 = {%f, %f, %f}, vel_sat_90 = {%f, %f, %f}\n",
|
|
vel_mag,
|
|
omega,
|
|
vel_sat.X,
|
|
vel_sat.Y,
|
|
vel_sat.Z,
|
|
vel_sat_90.X,
|
|
vel_sat_90.Y,
|
|
vel_sat_90.Z);
|
|
|
|
ntn_ta->omega = omega;
|
|
ntn_ta->pos_sat_0 = pos_sat;
|
|
ntn_ta->pos_sat_90 = pos_sat_90;
|
|
ntn_ta->vel_sat_0 = vel_sat;
|
|
ntn_ta->vel_sat_90 = vel_sat_90;
|
|
}
|
|
|
|
// populate ntn_ta structure from mac
|
|
static void configure_ntn_ta(fapi_nr_ntn_config_t *ntn_ta,
|
|
const NR_NTN_Config_r17_t *ntn_Config_r17,
|
|
int hfn,
|
|
int frame,
|
|
bool is_targetcell)
|
|
{
|
|
if (!ntn_Config_r17)
|
|
return;
|
|
|
|
// epochTime_r17 must be present (this is assured by function `eval_epoch_time()`)
|
|
const NR_EpochTime_r17_t *epoch_time_r17 = ntn_Config_r17->epochTime_r17;
|
|
AssertFatal(epoch_time_r17, "epoch_time_r17 should not be NULL here\n");
|
|
if (epoch_time_r17->sfn_r17 >= frame)
|
|
ntn_ta->epoch_hfn = hfn;
|
|
else
|
|
ntn_ta->epoch_hfn = hfn + 1;
|
|
ntn_ta->epoch_sfn = epoch_time_r17->sfn_r17;
|
|
ntn_ta->epoch_subframe = epoch_time_r17->subFrameNR_r17;
|
|
|
|
// handle cellSpecificKoffset_r17
|
|
if (ntn_Config_r17->cellSpecificKoffset_r17)
|
|
ntn_ta->cell_specific_k_offset = *ntn_Config_r17->cellSpecificKoffset_r17;
|
|
else // Need R - Release if not present
|
|
ntn_ta->cell_specific_k_offset = 0;
|
|
|
|
// Check if ta_Info_r17 is present and convert the time units
|
|
if (ntn_Config_r17->ta_Info_r17) {
|
|
// ta_Common_r17 (is in units of 4.072e-3 µs)
|
|
ntn_ta->N_common_ta_adj = ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6;
|
|
// ta_CommonDrift_r17 (is in units of 0.2e-3 µs/s)
|
|
if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17)
|
|
ntn_ta->N_common_ta_drift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3;
|
|
else // Need R - Release if not present
|
|
ntn_ta->N_common_ta_drift = 0;
|
|
// ta_CommonDriftVariant_r17 (is in units of 0.2e-4 µs/s²)
|
|
if (ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17)
|
|
ntn_ta->N_common_ta_drift_variant = *ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17 * 0.2e-4;
|
|
else // Need R - Release if not present
|
|
ntn_ta->N_common_ta_drift_variant = 0;
|
|
} else { // Need R - Release if not present
|
|
ntn_ta->N_common_ta_adj = 0;
|
|
ntn_ta->N_common_ta_drift = 0;
|
|
ntn_ta->N_common_ta_drift_variant = 0;
|
|
}
|
|
|
|
LOG_I(NR_MAC,
|
|
"NTN Config Rxd. Epoch HFN: %d, Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, "
|
|
"N_Common_Ta: %fms, drift: %fµs/s, variant: %fµs/s²\n",
|
|
ntn_ta->epoch_hfn,
|
|
ntn_ta->epoch_sfn,
|
|
ntn_ta->epoch_subframe,
|
|
ntn_ta->cell_specific_k_offset,
|
|
ntn_ta->N_common_ta_adj,
|
|
ntn_ta->N_common_ta_drift,
|
|
ntn_ta->N_common_ta_drift_variant);
|
|
|
|
// handle ephemerisInfo_r17
|
|
const NR_EphemerisInfo_r17_t *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17;
|
|
if (ephemeris_info) {
|
|
if (ephemeris_info->present == NR_EphemerisInfo_r17_PR_positionVelocity_r17) {
|
|
const NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17;
|
|
AssertFatal(position_velocity, "position_velocity should not be NULL here\n");
|
|
prepare_ue_sat_ta(position_velocity, ntn_ta);
|
|
} else {
|
|
LOG_W(NR_MAC, "NR UE currently supports only ephemerisInfo_r17 of type positionVelocity_r17\n");
|
|
ntn_ta->omega = 0;
|
|
ntn_ta->pos_sat_0 = (position_t){0, 0, 0};
|
|
ntn_ta->pos_sat_90 = (position_t){0, 0, 0};
|
|
ntn_ta->vel_sat_0 = (position_t){0, 0, 0};
|
|
ntn_ta->vel_sat_90 = (position_t){0, 0, 0};
|
|
}
|
|
} else { // Need R - Release if not present
|
|
ntn_ta->omega = 0;
|
|
ntn_ta->pos_sat_0 = (position_t){0, 0, 0};
|
|
ntn_ta->pos_sat_90 = (position_t){0, 0, 0};
|
|
ntn_ta->vel_sat_0 = (position_t){0, 0, 0};
|
|
ntn_ta->vel_sat_90 = (position_t){0, 0, 0};
|
|
}
|
|
|
|
ntn_ta->is_targetcell = is_targetcell;
|
|
ntn_ta->params_changed = true;
|
|
}
|
|
|
|
static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP, int hfn, int frame)
|
|
{
|
|
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;
|
|
frame_type_t frame_type = mac->frame_structure.frame_type;
|
|
|
|
// carrier config
|
|
LOG_D(MAC, "[UE %d] Entering UE Config Common\n", mac->ue_id);
|
|
mac->numerology = *scc->ssbSubcarrierSpacing;
|
|
|
|
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];
|
|
frame_type = get_frame_type(mac->nr_band, mac->numerology);
|
|
mac->frequency_range = get_freq_range_from_band(mac->nr_band);
|
|
|
|
AssertFatal(mac->numerology == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing, "DL and SSB subcarrierSpacing must be the same!\n");
|
|
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
|
|
LOG_I(NR_MAC,
|
|
"[UE %d] Set dl_frequency=%u kHz (from absoluteFrequencyPointA=%ld, band=%d, scs=%ld)\n",
|
|
mac->ue_id,
|
|
cfg->carrier_config.dl_frequency,
|
|
frequencyInfoDL->absoluteFrequencyPointA,
|
|
mac->nr_band,
|
|
*scc->ssbSubcarrierSpacing);
|
|
|
|
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;
|
|
|
|
AssertFatal(mac->numerology == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing, "UL and SSB subcarrierSpacing must be the same!\n");
|
|
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 = frame_type;
|
|
cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
|
|
|
|
// 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) {
|
|
cfg->ssb_table.ssb_offset_point_a = get_ssb_offset_to_pointA(*frequencyInfoDL->absoluteFrequencySSB,
|
|
frequencyInfoDL->absoluteFrequencyPointA,
|
|
cfg->ssb_config.scs_common,
|
|
mac->frequency_range);
|
|
cfg->ssb_table.ssb_period = *scc->ssb_periodicityServingCell;
|
|
// NSA -> take ssb offset from SCS
|
|
cfg->ssb_table.ssb_subcarrier_offset = get_ssb_subcarrier_offset(*frequencyInfoDL->absoluteFrequencySSB,
|
|
frequencyInfoDL->absoluteFrequencyPointA,
|
|
cfg->ssb_config.scs_common);
|
|
cfg->ssb_table.ssb_case = set_ssb_case(*scc->ssbSubcarrierSpacing, mac->nr_band);
|
|
}
|
|
|
|
switch (scc->ssb_PositionsInBurst->present) {
|
|
case 1 :
|
|
cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) 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);
|
|
}
|
|
|
|
int period_idx = mac->tdd_UL_DL_ConfigurationCommon ? get_tdd_period_idx(mac->tdd_UL_DL_ConfigurationCommon) : 0;
|
|
config_frame_structure(*scc->ssbSubcarrierSpacing,
|
|
mac->tdd_UL_DL_ConfigurationCommon,
|
|
period_idx,
|
|
frame_type,
|
|
&mac->frame_structure);
|
|
|
|
// TDD Table Configuration
|
|
if (cfg->cell_config.frame_duplex_type == TDD)
|
|
set_tdd_config_nr_ue(&cfg->tdd_table, &mac->frame_structure);
|
|
|
|
// 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;
|
|
int format = get_format0(config_index, frame_type, mac->frequency_range);
|
|
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));
|
|
|
|
// Get UL carrier SCS for PRACH k1 calculation
|
|
int ul_carrier_scs;
|
|
if (scc->uplinkConfigCommon->frequencyInfoUL
|
|
&& scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.count > 0) {
|
|
ul_carrier_scs = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
|
|
} else {
|
|
ul_carrier_scs = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
|
|
}
|
|
|
|
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
|
|
+ (get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing, ul_carrier_scs) * 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, frame_type, mac->frequency_range);
|
|
|
|
// 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);
|
|
configure_ntn_ta(&mac->phy_config.config_req.ntn_config, mac->sc_info.ntn_Config_r17, hfn, frame, true);
|
|
} else {
|
|
asn1cFreeStruc(asn_DEF_NR_NTN_Config_r17, mac->sc_info.ntn_Config_r17);
|
|
}
|
|
}
|
|
|
|
static void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch)
|
|
{
|
|
pdcch->otherSI_SS_id = -1;
|
|
pdcch->ra_SS_id = -1;
|
|
pdcch->paging_SS_id = -1;
|
|
asn1cFreeSeq(asn_DEF_NR_SearchSpace, pdcch->list_common_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);
|
|
}
|
|
|
|
NR_SearchSpace_t *get_common_search_space(const NR_UE_MAC_INST_t *mac, const NR_SearchSpaceId_t ss_id)
|
|
{
|
|
if (ss_id == 0)
|
|
return mac->search_space_zero;
|
|
|
|
NR_SearchSpace_t *css = NULL;
|
|
// if current DL BWP is not set, use first BWP
|
|
const int bwp_id = mac->current_DL_BWP ? mac->current_DL_BWP->bwp_id : 0;
|
|
for (int i = 0; i < mac->config_BWP_PDCCH[bwp_id].list_common_SS.count; i++) {
|
|
css = mac->config_BWP_PDCCH[bwp_id].list_common_SS.array[i];
|
|
if (css->searchSpaceId == ss_id) {
|
|
return css;
|
|
}
|
|
}
|
|
AssertFatal(css, "Couldn't find CSS with Id %ld\n", ss_id);
|
|
return css;
|
|
}
|
|
|
|
static void update_ss(void *ue_ss_in, void *nw_ss_in)
|
|
{
|
|
if (!nw_ss_in || !ue_ss_in)
|
|
return;
|
|
|
|
asn_anonymous_sequence_ *ue_ss = _A_SEQUENCE_FROM_VOID(ue_ss_in);
|
|
asn_anonymous_sequence_ *nw_ss = _A_SEQUENCE_FROM_VOID(nw_ss_in);
|
|
for (int i = 0; i < nw_ss->count; i++) {
|
|
NR_SearchSpace_t *source_ss = (NR_SearchSpace_t *)nw_ss->array[i];
|
|
NR_SearchSpace_t *target_ss = NULL;
|
|
for (int j = 0; j < ue_ss->count; j++) {
|
|
NR_SearchSpace_t **s = (NR_SearchSpace_t **)ue_ss->array;
|
|
if (s[j]->searchSpaceId == source_ss->searchSpaceId) {
|
|
target_ss = s[j];
|
|
break;
|
|
}
|
|
}
|
|
if (!target_ss) {
|
|
target_ss = calloc(1, sizeof(*target_ss));
|
|
ASN_SEQUENCE_ADD(ue_ss, target_ss);
|
|
}
|
|
modlist_ss(source_ss, target_ss);
|
|
}
|
|
}
|
|
|
|
static void configure_common_ss_coreset(NR_BWP_PDCCH_t *pdcch, NR_PDCCH_ConfigCommon_t *pdcch_ConfigCommon)
|
|
{
|
|
if (!pdcch_ConfigCommon)
|
|
return;
|
|
|
|
if (pdcch_ConfigCommon->commonSearchSpaceList)
|
|
update_ss((void *)&pdcch->list_common_SS, (void *)&pdcch_ConfigCommon->commonSearchSpaceList->list);
|
|
|
|
ASIGN_P_VAL(pdcch->otherSI_SS_id, pdcch_ConfigCommon->searchSpaceOtherSystemInformation);
|
|
ASIGN_P_VAL(pdcch->ra_SS_id, pdcch_ConfigCommon->ra_SearchSpace);
|
|
ASIGN_P_VAL(pdcch->paging_SS_id, 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) {
|
|
long *tci_id = calloc(1, sizeof(*tci_id));
|
|
*tci_id = id;
|
|
ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, tci_id);
|
|
}
|
|
}
|
|
} 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)
|
|
update_ss((void *)&pdcch->list_SS, (void *)&pdcch_Config->searchSpacesToAddModList->list);
|
|
|
|
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, int 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_lcid_rb_t rb)
|
|
{
|
|
NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lc_info->lcid);
|
|
if (rb.type != NR_LCID_NONE)
|
|
lc_info->rb = rb;
|
|
lc_info->rb_suspended = false;
|
|
if (rb.type == NR_LCID_SRB && !mac_lc_config->ul_SpecificParameters) {
|
|
// release configuration and reset to default
|
|
set_default_logicalchannelconfig(lc_info, rb.choice.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 nr_lcid_rb_t configure_lcid_rb(NR_RLC_BearerConfig_t *rlc_bearer)
|
|
{
|
|
nr_lcid_rb_t rb;
|
|
if (!rlc_bearer->servedRadioBearer) {
|
|
LOG_W(NR_MAC, "RLC bearer config does not contain servedRadioBearer.\n");
|
|
rb.type = NR_LCID_NONE;
|
|
return rb;
|
|
}
|
|
|
|
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) {
|
|
rb.type = NR_LCID_SRB;
|
|
rb.choice.srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
|
|
return rb;
|
|
}
|
|
|
|
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity) {
|
|
rb.type = NR_LCID_DRB;
|
|
rb.choice.drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity;
|
|
return rb;
|
|
}
|
|
LOG_E(NR_MAC, "Error. RLC should be linked to either DRB or SRB.\n");
|
|
rb.type = NR_LCID_NONE;
|
|
return rb;
|
|
}
|
|
|
|
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];
|
|
nr_lcid_rb_t rb = configure_lcid_rb(rlc_bearer);
|
|
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_configure_lc_config(mac, mac->lc_ordered_list.array[j], mac_lc_config, rb);
|
|
} 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, rb);
|
|
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, rb);
|
|
}
|
|
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 slots_per_frame)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static bool is_cset0_present(frequency_range_t const fr, uint8_t const kssb)
|
|
{
|
|
// TS 38.213 4.1 defines if CORESET 0 is present or not based on Kssb
|
|
return (fr == FR1) ? (kssb < 24) : (kssb < 12);
|
|
}
|
|
|
|
void nr_rrc_mac_sched_sib(module_id_t module_id, int sched_sib)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
if (sched_sib == 1) {
|
|
bool const is_c0 = is_cset0_present(mac->frequency_range, mac->ssb_subcarrier_offset);
|
|
mac->get_sib1 = is_c0;
|
|
AssertFatal(is_c0, "RRC scheduling SIB1 reception but MIB indicates no SIB1 present in current cell\n");
|
|
} else if (sched_sib > 1)
|
|
mac->get_otherSI[sched_sib - 2] = true;
|
|
|
|
if (mac->state == UE_NOT_SYNC && mac->get_sib1)
|
|
mac->state = UE_RECEIVING_SIB;
|
|
}
|
|
|
|
void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, bool barred)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
AssertFatal(mib, "MIB should not be NULL\n");
|
|
if (!mac->mib)
|
|
mac->mib = calloc(1, sizeof(*mac->mib));
|
|
if (barred)
|
|
mac->state = UE_BARRED;
|
|
else if (mac->state == UE_BARRED) {
|
|
// it is synched as we received MIB
|
|
// nr_ue_decode_mib is transitionining to the correct state
|
|
mac->state = UE_NOT_SYNC;
|
|
}
|
|
update_mib_conf(mac->mib, mib);
|
|
mac->phy_config.Mod_id = module_id;
|
|
mac->phy_config.CC_id = cc_idP;
|
|
|
|
nr_ue_decode_mib(mac, cc_idP);
|
|
if (get_softmodem_params()->phy_test)
|
|
mac->state = UE_CONNECTED;
|
|
else if (mac->state == UE_NOT_SYNC_RECONF)
|
|
mac->state = UE_PERFORMING_RA;
|
|
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
if (source->ext2) {
|
|
if (!target->ext2)
|
|
target->ext2 = calloc(1, sizeof(*target->ext2));
|
|
UPDATE_IE(target->ext2->harq_ProcessNumberSizeDCI_0_1_r17, source->ext2->harq_ProcessNumberSizeDCI_0_1_r17, long);
|
|
} else if (target->ext2) {
|
|
free_and_zero(target->ext2->harq_ProcessNumberSizeDCI_0_1_r17);
|
|
}
|
|
}
|
|
|
|
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");
|
|
if (source->ext3) {
|
|
if (!target->ext3)
|
|
target->ext3 = calloc(1, sizeof(*target->ext3));
|
|
UPDATE_IE(target->ext3->harq_ProcessNumberSizeDCI_1_1_r17, source->ext3->harq_ProcessNumberSizeDCI_1_1_r17, long);
|
|
} else if (target->ext3) {
|
|
free_and_zero(target->ext3->harq_ProcessNumberSizeDCI_1_1_r17);
|
|
}
|
|
}
|
|
|
|
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_UE_UL_BWP_t *bwp, 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;
|
|
if (source->alpha) {
|
|
bwp->h_b_f_c = 0;
|
|
}
|
|
UPDATE_IE(target->alpha, source->alpha, NR_Alpha_t);
|
|
if (source->p0) {
|
|
bwp->h_b_f_c = 0;
|
|
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_UE_UL_BWP_t *bwp, 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
|
|
struct NR_SRS_Config__srs_ResourceSetToAddModList *source_srs_list = source->srs_ResourceSetToAddModList;
|
|
if (source_srs_list) {
|
|
if (!target->srs_ResourceSetToAddModList)
|
|
target->srs_ResourceSetToAddModList = calloc(1, sizeof(*target->srs_ResourceSetToAddModList));
|
|
struct NR_SRS_Config__srs_ResourceSetToAddModList *target_srs_list = target->srs_ResourceSetToAddModList;
|
|
|
|
for (int i = 0; i < source_srs_list->list.count; i++) {
|
|
long srs_resource_id = source_srs_list->list.array[i]->srs_ResourceSetId;
|
|
int j;
|
|
for (j = 0; j < target_srs_list->list.count; j++) {
|
|
if (srs_resource_id == target_srs_list->list.array[j]->srs_ResourceSetId)
|
|
break;
|
|
}
|
|
if (j == target_srs_list->list.count) {
|
|
NR_SRS_ResourceSet_t *new = calloc(1, sizeof(*new));
|
|
ASN_SEQUENCE_ADD(&target_srs_list->list, new);
|
|
}
|
|
setup_srsresourceset(bwp, target_srs_list->list.array[j], source_srs_list->list.array[i]);
|
|
}
|
|
}
|
|
if (source->srs_ResourceSetToReleaseList) {
|
|
RELEASE_IE_FROMLIST(source->srs_ResourceSetToReleaseList,
|
|
target->srs_ResourceSetToAddModList,
|
|
srs_ResourceSetId);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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(bwp, 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(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);
|
|
bwp->srs_power_control_initialized = false;
|
|
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) {
|
|
// ssb_perRACH_OccasionAndCB_PreamblesPerSSB is need M
|
|
// if NULL we need to maintain the information
|
|
NR_SetupRelease_RACH_ConfigCommon_t *rachcommon = ul_common->rach_ConfigCommon;
|
|
if (rachcommon->present == NR_SetupRelease_RACH_ConfigCommon_PR_setup
|
|
&& rachcommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB)
|
|
mac->ssb_ro_preambles = get_ssb_ro_preambles_4step(rachcommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
|
|
HANDLE_SETUPRELEASE_DIRECT(bwp->rach_ConfigCommon, rachcommon, NR_RACH_ConfigCommon_t, asn_DEF_NR_RACH_ConfigCommon);
|
|
}
|
|
if (ul_common->ext1 && ul_common->ext1->msgA_ConfigCommon_r16) {
|
|
HANDLE_SETUPRELEASE_DIRECT(bwp->msgA_ConfigCommon_r16,
|
|
ul_common->ext1->msgA_ConfigCommon_r16,
|
|
NR_MsgA_ConfigCommon_r16_t,
|
|
asn_DEF_NR_MsgA_ConfigCommon_r16);
|
|
}
|
|
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_and_zero(bwp->msg3_DeltaPreamble);
|
|
free_and_zero(bwp->p0_NominalWithGrant);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void configure_timeAlignmentTimer(NR_timer_t *time_alignment_timer, NR_TimeAlignmentTimer_t timer_config, int scs)
|
|
{
|
|
uint32_t timer_ms = 0;
|
|
switch (timer_config) {
|
|
case NR_TimeAlignmentTimer_ms500 :
|
|
timer_ms = 500;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms750 :
|
|
timer_ms = 750;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms1280 :
|
|
timer_ms = 1280;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms1920 :
|
|
timer_ms = 1920;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms2560 :
|
|
timer_ms = 2560;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms5120 :
|
|
timer_ms = 5120;
|
|
break;
|
|
case NR_TimeAlignmentTimer_ms10240 :
|
|
timer_ms = 10240;
|
|
break;
|
|
case NR_TimeAlignmentTimer_infinity :
|
|
timer_ms = UINT_MAX;
|
|
break;
|
|
default :
|
|
AssertFatal(false, "Invalid timeAlignmentTimer\n");
|
|
}
|
|
// length of slot is (1/2^scs)ms
|
|
uint32_t n_slots = timer_ms != UINT_MAX ? (timer_ms << scs) : UINT_MAX;
|
|
bool timer_was_active = nr_timer_is_active(time_alignment_timer);
|
|
nr_timer_setup(time_alignment_timer, n_slots, 1); // 1 slot update rate
|
|
if (timer_was_active)
|
|
nr_timer_start(time_alignment_timer);
|
|
}
|
|
|
|
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);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
fapi_nr_synch_request_t sync_req = {.target_Nid_cell = -1, .ssb_bw_scan = true};
|
|
switch (cause) {
|
|
case GO_TO_IDLE:
|
|
/* TS 38.331 §5.3.11: enter RRC_IDLE and perform cell selection per TS 38.304. */
|
|
reset_ra(mac, true);
|
|
nr_ue_init_mac(mac);
|
|
release_mac_configuration(mac, cause);
|
|
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 GO_TO_IDLE_KEEP_CAMPED:
|
|
/* Normal no-redirection RRCRelease: keep the selected camped cell context for TS 38.304 §5.2.5/§7.1
|
|
* paging, while releasing connected-mode MAC state. RA stays idle until paging/NAS triggers access. */
|
|
// Stop any in-progress RA and discard PRACH resources
|
|
reset_ra(mac, true);
|
|
// Apply TS 38.321 §5.12 MAC reset (no PHY sync reinit)
|
|
reset_mac_inst(mac);
|
|
// Release dedicated MAC config (keep SIB1/common BWP0/paging PDCCH for the camped cell)
|
|
release_mac_configuration(mac, cause);
|
|
// Restore default MAC Cell Group timers/config (after the reset)
|
|
nr_ue_mac_default_configs(mac);
|
|
mac->ra.ra_state = nrRA_UE_IDLE;
|
|
mac->ra.RA_active = false;
|
|
mac->state = UE_IDLE;
|
|
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, false);
|
|
release_mac_configuration(mac, cause);
|
|
mac->state = UE_DETACHING;
|
|
break;
|
|
case REJECT:
|
|
reset_ra(mac, false);
|
|
reset_mac_inst(mac);
|
|
mac->state = UE_BARRED;
|
|
break;
|
|
case RRC_SETUP_REESTAB_RESUME:
|
|
for (int i = mac->lc_ordered_list.count; i > 0; i--) {
|
|
nr_lcordered_info_t *lc = mac->lc_ordered_list.array[i - 1];
|
|
if (lc->rb.type == NR_LCID_SRB && lc->rb.choice.srb_id == 0)
|
|
continue;
|
|
asn_sequence_del(&mac->lc_ordered_list, i - 1, 1);
|
|
}
|
|
release_mac_configuration(mac, cause);
|
|
nr_ue_mac_default_configs(mac);
|
|
break;
|
|
case UL_SYNC_LOST_T430_EXPIRED:
|
|
// TS 38.331 Section 5.2.2.6, TS 38.321 Section 5.2a
|
|
// Flush all HARQ buffers and Stop UL transmissions
|
|
handle_ulsync_loss(mac);
|
|
break;
|
|
default:
|
|
AssertFatal(false, "Invalid MAC reset cause %d\n", cause);
|
|
}
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
bool is_lcid_suspended(NR_UE_MAC_INST_t *mac, int lcid)
|
|
{
|
|
for (int j = 0; j < mac->lc_ordered_list.count; j++) {
|
|
nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j];
|
|
if (lc->lcid == lcid)
|
|
return lc->rb_suspended;
|
|
}
|
|
LOG_E(NR_MAC, "LCID %d not found in the MAC list\n", lcid);
|
|
return false;
|
|
}
|
|
|
|
void nr_rrc_mac_resume_rb(module_id_t module_id, bool is_srb, int rb_id)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
for (int j = 0; j < mac->lc_ordered_list.count; j++) {
|
|
nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j];
|
|
if (is_srb && lc->rb.type == NR_LCID_SRB && lc->rb.choice.srb_id == rb_id)
|
|
lc->rb_suspended = false;
|
|
if (!is_srb && lc->rb.type == NR_LCID_DRB && lc->rb.choice.drb_id == rb_id)
|
|
lc->rb_suspended = false;
|
|
}
|
|
}
|
|
|
|
static void configure_si_schedulingInfo(NR_UE_MAC_INST_t *mac,
|
|
NR_SI_SchedulingInfo_t *si_SchedulingInfo,
|
|
NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700)
|
|
{
|
|
asn_sequence_empty(&mac->si_SchedInfo.si_SchedInfo_list);
|
|
if (si_SchedulingInfo) {
|
|
mac->si_SchedInfo.si_WindowLength = si_SchedulingInfo->si_WindowLength;
|
|
for (int i = 0; i < si_SchedulingInfo->schedulingInfoList.list.count; i++) {
|
|
si_schedinfo_config_t *config = calloc_or_fail(1, sizeof(*config));
|
|
config->type = NR_SI_INFO;
|
|
config->si_WindowPosition = i + 1;
|
|
config->si_Periodicity = si_SchedulingInfo->schedulingInfoList.list.array[i]->si_Periodicity;
|
|
ASN_SEQUENCE_ADD(&mac->si_SchedInfo.si_SchedInfo_list, config);
|
|
}
|
|
}
|
|
if (si_SchedulingInfo_v1700) {
|
|
for (int i = 0; i < si_SchedulingInfo_v1700->schedulingInfoList2_r17.list.count; i++) {
|
|
si_schedinfo_config_t *config = calloc_or_fail(1, sizeof(*config));
|
|
config->type = NR_SI_INFO_v1700;
|
|
config->si_WindowPosition = si_SchedulingInfo_v1700->schedulingInfoList2_r17.list.array[i]->si_WindowPosition_r17;
|
|
config->si_Periodicity = si_SchedulingInfo_v1700->schedulingInfoList2_r17.list.array[i]->si_Periodicity_r17;
|
|
ASN_SEQUENCE_ADD(&mac->si_SchedInfo.si_SchedInfo_list, config);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @brief Parse SIB1 PCCH-Config (TS 38.331) into UE MAC paging_cfg (T, N, PF_offset, Ns, X and the
|
|
* per-PO start-MO list). */
|
|
static void configure_pcch_config(NR_UE_MAC_INST_t *mac, const NR_ServingCellConfigCommonSIB_t *scc)
|
|
{
|
|
DevAssert(mac);
|
|
DevAssert(scc);
|
|
const NR_PCCH_Config_t *pcch = &scc->downlinkConfigCommon.pcch_Config;
|
|
nr_ue_paging_cfg_t *paging_cfg = &mac->paging_cfg;
|
|
/* Reset the per-PO start-MO list */
|
|
paging_cfg->first_mo_of_po_count = 0;
|
|
memset(paging_cfg->first_mo_of_po, 0, sizeof(paging_cfg->first_mo_of_po));
|
|
|
|
paging_cfg->T = nr_pcch_default_paging_cycle_rf(pcch);
|
|
nr_pcch_n_and_paging_frame_offset(pcch, paging_cfg->T, &paging_cfg->N, &paging_cfg->PF_offset);
|
|
paging_cfg->Ns = nr_pcch_ns_per_pf(pcch);
|
|
|
|
/* TS 38.304 §7.1: X defaults to 1 when nrofPDCCH-MonitoringOccasionPerSSB-InPO-r16 is absent
|
|
* (one PDCCH MO per SSB in a PO) */
|
|
paging_cfg->X = 1;
|
|
if (pcch->ext1 && pcch->ext1->nrofPDCCH_MonitoringOccasionPerSSB_InPO_r16) {
|
|
const long x = *pcch->ext1->nrofPDCCH_MonitoringOccasionPerSSB_InPO_r16;
|
|
AssertFatal(x >= 2 && x <= NR_PCCH_MAX_MO_PER_SSB_IN_PO,
|
|
"TS 38.331 PCCH-Config: nrofPDCCH-MonitoringOccasionPerSSB-InPO-r16=%ld out of range (2..%d)\n",
|
|
x,
|
|
NR_PCCH_MAX_MO_PER_SSB_IN_PO);
|
|
paging_cfg->X = x;
|
|
}
|
|
|
|
// TS 38.304 §7.1 / TS 38.331 PCCH-Config: when firstPDCCH-MonitoringOccasionOfPO is present, it
|
|
// explicitly defines the starting PDCCH MO index of each PO within the PF, overriding the default
|
|
// (i_s * S * X) computation.
|
|
if (pcch->firstPDCCH_MonitoringOccasionOfPO) {
|
|
for (uint8_t i = 0; i < sizeofArray(paging_cfg->first_mo_of_po); i++) {
|
|
int v;
|
|
if (!nr_pcch_first_pdcch_start_mo(pcch->firstPDCCH_MonitoringOccasionOfPO, i, &v))
|
|
break;
|
|
paging_cfg->first_mo_of_po[i] = v;
|
|
paging_cfg->first_mo_of_po_count++;
|
|
}
|
|
}
|
|
|
|
LOG_D(NR_MAC,
|
|
"PCCH-Config parsed: T=%u N=%u Ns=%u PF_offset=%u X=%u first_mo_of_po_count=%u\n",
|
|
paging_cfg->T,
|
|
paging_cfg->N,
|
|
paging_cfg->Ns,
|
|
paging_cfg->PF_offset,
|
|
paging_cfg->X,
|
|
paging_cfg->first_mo_of_po_count);
|
|
}
|
|
|
|
/** @brief RRC to MAC: push 5G-S-TMSI for paging UE_ID derivation (TS 38.304 §7.1).
|
|
* Lifecycle:
|
|
* - RRC_IDLE after first NAS registration: 5G-S-TMSI known -> UE_ID = TMSI mod 1024.
|
|
* - RRC_INACTIVE: same as above (UE also has fullI-RNTI).
|
|
* The "no 5G-S-TMSI" window between MIB/SIB1 reception and NAS_5GMM_IND is legitimate per spec,
|
|
* the UE must still monitor PF/PO with UE_ID = 0 for broadcast-style notifications.
|
|
* @note Pass UINT64_MAX to invalidate (no 5G-S-TMSI). */
|
|
void nr_rrc_mac_config_req_paging_ue_id(module_id_t module_id, uint64_t fiveG_S_TMSI)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
/* TS 38.304 §7.1: UE_ID = 5G-S-TMSI mod 1024, or 0 when no 5G-S-TMSI is allocated. */
|
|
mac->paging_cfg.ue_id = (fiveG_S_TMSI == UINT64_MAX) ? 0 : fiveG_S_TMSI % 1024;
|
|
LOG_I(NR_MAC, "[UE %d] paging UE_ID=%u\n", mac->ue_id, mac->paging_cfg.ue_id);
|
|
pthread_mutex_unlock(&mac->if_mutex);
|
|
}
|
|
|
|
static void nr_mac_start_ra(NR_UE_MAC_INST_t *mac, module_id_t module_id, nr_mac_ra_start_cause_t cause)
|
|
{
|
|
switch (cause) {
|
|
case NR_MAC_RA_START_SETUP:
|
|
case NR_MAC_RA_START_T300:
|
|
reset_ra(mac, false);
|
|
reset_mac_inst(mac);
|
|
mac->msg3_C_RNTI = false;
|
|
mac->state = UE_PERFORMING_RA;
|
|
break;
|
|
case NR_MAC_RA_START_REESTABLISHMENT: {
|
|
fapi_nr_synch_request_t sync_req = {.target_Nid_cell = mac->physCellId, .ssb_bw_scan = false};
|
|
reset_mac_inst(mac);
|
|
nr_ue_mac_default_configs(mac);
|
|
nr_ue_reset_sync_state(mac, true);
|
|
release_mac_configuration(mac, RE_ESTABLISHMENT);
|
|
for (int j = 0; j < mac->lc_ordered_list.count; j++) {
|
|
nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j];
|
|
if (lc->rb.type == NR_LCID_SRB && lc->rb.choice.srb_id == 0)
|
|
continue;
|
|
lc->rb_suspended = true;
|
|
}
|
|
configure_timeAlignmentTimer(&mac->time_alignment_timer, mac->timeAlignmentTimerCommon, mac->current_UL_BWP->scs);
|
|
nr_ue_send_synch_request(mac, module_id, 0, &sync_req);
|
|
break;
|
|
}
|
|
default:
|
|
AssertFatal(false, "unknown nr_mac_ra_start_cause_t %d\n", cause);
|
|
}
|
|
}
|
|
|
|
/** @brief All RRC-initiated RA entry points */
|
|
void nr_rrc_mac_start_ra(module_id_t module_id, nr_mac_ra_start_cause_t cause)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
|
|
nr_mac_start_ra(mac, module_id, cause);
|
|
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
NR_SI_SchedulingInfo_t *si_SchedulingInfo = sib1->si_SchedulingInfo;
|
|
NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700 = NULL;
|
|
if (sib1->nonCriticalExtension && sib1->nonCriticalExtension->nonCriticalExtension
|
|
&& sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension) {
|
|
si_SchedulingInfo_v1700 = sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->si_SchedulingInfo_v1700;
|
|
}
|
|
NR_ServingCellConfigCommonSIB_t *scc = sib1->servingCellConfigCommon;
|
|
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);
|
|
configure_si_schedulingInfo(mac, si_SchedulingInfo, si_SchedulingInfo_v1700);
|
|
configure_pcch_config(mac, scc);
|
|
|
|
config_common_ue_sa(mac, scc, cc_idP);
|
|
|
|
// Build the list of all the valid/transmitted SSBs according to the config
|
|
LOG_D(NR_MAC, "Build SSB list\n");
|
|
build_ssb_list(mac);
|
|
|
|
int bwp_id = 0;
|
|
configure_common_BWP_dl(mac, bwp_id, &scc->downlinkConfigCommon.initialDownlinkBWP);
|
|
if (scc->uplinkConfigCommon) {
|
|
mac->timeAlignmentTimerCommon = scc->uplinkConfigCommon->timeAlignmentTimerCommon;
|
|
configure_common_BWP_ul(mac, 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");
|
|
configure_timeAlignmentTimer(&mac->time_alignment_timer, mac->timeAlignmentTimerCommon, mac->current_UL_BWP->scs);
|
|
}
|
|
if (mac->state == UE_RECEIVING_SIB && can_start_ra)
|
|
mac->state = UE_PERFORMING_RA;
|
|
|
|
mac->if_module->phy_config_request(&mac->phy_config);
|
|
mac->phy_config.config_req.ntn_config.params_changed = false;
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, int hfn, int frame, bool can_start_ra)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
|
|
if (sib19) {
|
|
// update ntn_Config_r17 with received values
|
|
UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t);
|
|
configure_ntn_ta(&mac->phy_config.config_req.ntn_config, mac->sc_info.ntn_Config_r17, hfn, frame, false);
|
|
mac->if_module->phy_config_request(&mac->phy_config);
|
|
mac->phy_config.config_req.ntn_config.params_changed = false;
|
|
}
|
|
if (mac->state == UE_RECEIVING_SIB && can_start_ra)
|
|
mac->state = UE_PERFORMING_RA;
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
|
|
int cc_idP,
|
|
int hfn,
|
|
int frame,
|
|
const NR_ReconfigurationWithSync_t *reconfWithSync)
|
|
{
|
|
reset_mac_inst(mac);
|
|
mac->crnti = reconfWithSync->newUE_Identity;
|
|
LOG_I(NR_MAC, "Configuring CRNTI %x\n", mac->crnti);
|
|
|
|
RA_config_t *ra = &mac->ra;
|
|
bool is_cfra = false;
|
|
if (reconfWithSync->rach_ConfigDedicated) {
|
|
AssertFatal(reconfWithSync->rach_ConfigDedicated->present == NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink,
|
|
"RACH on supplementaryUplink not supported\n");
|
|
NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = reconfWithSync->rach_ConfigDedicated->choice.uplink;
|
|
if (rach_ConfigDedicated->cfra)
|
|
is_cfra = true;
|
|
if (rach_ConfigDedicated->ext1 && rach_ConfigDedicated->ext1->cfra_TwoStep_r16)
|
|
is_cfra = true;
|
|
UPDATE_IE(ra->rach_ConfigDedicated, reconfWithSync->rach_ConfigDedicated->choice.uplink, NR_RACH_ConfigDedicated_t);
|
|
}
|
|
|
|
// in case of CBRA and reconfiguration with sync (handover)
|
|
// the UE sends MSG3 with C-RNTI to identify itself
|
|
if (!is_cfra)
|
|
mac->msg3_C_RNTI = true;
|
|
|
|
if (reconfWithSync->spCellConfigCommon) {
|
|
NR_ServingCellConfigCommon_t *scc = reconfWithSync->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, hfn, frame);
|
|
// Build the list of all the valid/transmitted SSBs according to the config
|
|
LOG_D(NR_MAC,"Build SSB list\n");
|
|
build_ssb_list(mac);
|
|
|
|
const int bwp_id = 0;
|
|
if (scc->downlinkConfigCommon)
|
|
configure_common_BWP_dl(mac, bwp_id, scc->downlinkConfigCommon->initialDownlinkBWP);
|
|
if (scc->uplinkConfigCommon)
|
|
configure_common_BWP_ul(mac, bwp_id, scc->uplinkConfigCommon->initialUplinkBWP);
|
|
|
|
// Update PDCCH config as MAC configuration has changed
|
|
// Used only in SA mode.
|
|
mac->update_pdcch_config = IS_SA_MODE(get_softmodem_params());
|
|
}
|
|
|
|
mac->state = UE_NOT_SYNC_RECONF;
|
|
ra->ra_state = nrRA_UE_IDLE;
|
|
nr_ue_mac_default_configs(mac);
|
|
|
|
// PHY CONFIG request should be sent, ahead of SYNC request
|
|
// As SYNC request processes the new config
|
|
mac->if_module->phy_config_request(&mac->phy_config);
|
|
mac->phy_config.config_req.ntn_config.params_changed = false;
|
|
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);
|
|
}
|
|
|
|
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;
|
|
break;
|
|
default:
|
|
AssertFatal(false, "Invalid periodicBSR_Timer %ld\n", periodicBSR);
|
|
}
|
|
return timer;
|
|
}
|
|
|
|
static uint32_t get_data_inactivity_timer(long setup)
|
|
{
|
|
uint32_t timer_s = 0;
|
|
switch (setup) {
|
|
case NR_DataInactivityTimer_s1 :
|
|
timer_s = 1;
|
|
break;
|
|
case NR_DataInactivityTimer_s2 :
|
|
timer_s = 2;
|
|
break;
|
|
case NR_DataInactivityTimer_s3 :
|
|
timer_s = 3;
|
|
break;
|
|
case NR_DataInactivityTimer_s5 :
|
|
timer_s = 5;
|
|
break;
|
|
case NR_DataInactivityTimer_s7 :
|
|
timer_s = 7;
|
|
break;
|
|
case NR_DataInactivityTimer_s10 :
|
|
timer_s = 10;
|
|
break;
|
|
case NR_DataInactivityTimer_s15 :
|
|
timer_s = 15;
|
|
break;
|
|
case NR_DataInactivityTimer_s20 :
|
|
timer_s = 20;
|
|
break;
|
|
case NR_DataInactivityTimer_s40 :
|
|
timer_s = 40;
|
|
break;
|
|
case NR_DataInactivityTimer_s50 :
|
|
timer_s = 50;
|
|
break;
|
|
case NR_DataInactivityTimer_s60 :
|
|
timer_s = 60;
|
|
break;
|
|
case NR_DataInactivityTimer_s80 :
|
|
timer_s = 80;
|
|
break;
|
|
case NR_DataInactivityTimer_s100 :
|
|
timer_s = 100;
|
|
break;
|
|
case NR_DataInactivityTimer_s120 :
|
|
timer_s = 120;
|
|
break;
|
|
case NR_DataInactivityTimer_s150 :
|
|
timer_s = 150;
|
|
break;
|
|
case NR_DataInactivityTimer_s180 :
|
|
timer_s = 180;
|
|
break;
|
|
default :
|
|
AssertFatal(false, "Invalid data inactivity timer\n");
|
|
}
|
|
return timer_s;
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
int slots_per_subframe = mac->frame_structure.numb_slots_frame / 10;
|
|
if (mcg->bsr_Config) {
|
|
uint32_t periodic_sf = nr_get_sf_periodicBSRTimer(mcg->bsr_Config->periodicBSR_Timer);
|
|
uint32_t target = periodic_sf < UINT_MAX ? periodic_sf * slots_per_subframe : 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 * slots_per_subframe, 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 * slots_per_subframe, 1); // 1 slot update rate
|
|
}
|
|
}
|
|
if (mcg->tag_Config) {
|
|
if (mcg->tag_Config->tag_ToReleaseList) {
|
|
for (int i = 0; i < mcg->tag_Config->tag_ToReleaseList->list.count; i++) {
|
|
for (int j = 0; j < mac->TAG_list.count; j++) {
|
|
if (*mcg->tag_Config->tag_ToReleaseList->list.array[i] == mac->TAG_list.array[j]->tag_Id)
|
|
asn_sequence_del(&mac->TAG_list, j, 1);
|
|
}
|
|
}
|
|
}
|
|
if (mcg->tag_Config->tag_ToAddModList) {
|
|
for (int i = 0; i < mcg->tag_Config->tag_ToAddModList->list.count; i++) {
|
|
int j;
|
|
for (j = 0; j < mac->TAG_list.count; j++) {
|
|
if (mac->TAG_list.array[j]->tag_Id == mcg->tag_Config->tag_ToAddModList->list.array[i]->tag_Id)
|
|
break;
|
|
}
|
|
if (j < mac->TAG_list.count) {
|
|
UPDATE_IE(mac->TAG_list.array[j], mcg->tag_Config->tag_ToAddModList->list.array[i], NR_TAG_t);
|
|
}
|
|
else {
|
|
NR_TAG_t *local_tag = NULL;
|
|
UPDATE_IE(local_tag, mcg->tag_Config->tag_ToAddModList->list.array[i], NR_TAG_t);
|
|
ASN_SEQUENCE_ADD(&mac->TAG_list, local_tag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (mcg->phr_Config) {
|
|
nr_phr_info_t *phr_info = &si->phr_info;
|
|
phr_info->is_configured = mcg->phr_Config->choice.setup != NULL;
|
|
if (phr_info->is_configured) {
|
|
struct NR_PHR_Config *config = mcg->phr_Config->choice.setup;
|
|
AssertFatal(config->multiplePHR == 0, "mulitplePHR not supported");
|
|
phr_info->PathlossChange_db = config->phr_Tx_PowerFactorChange;
|
|
const int periodic_timer_sf_enum_to_sf[] = {10, 20, 50, 100, 200, 500, 1000, UINT_MAX};
|
|
int periodic_timer_sf = periodic_timer_sf_enum_to_sf[config->phr_PeriodicTimer];
|
|
nr_timer_setup(&phr_info->periodicPHR_Timer, periodic_timer_sf * slots_per_subframe, 1);
|
|
const int prohibit_timer_sf_enum_to_sf[] = {0, 10, 20, 50, 100, 200, 500, 1000};
|
|
int prohibit_timer_sf = prohibit_timer_sf_enum_to_sf[config->phr_ProhibitTimer];
|
|
nr_timer_setup(&phr_info->prohibitPHR_Timer, prohibit_timer_sf * slots_per_subframe, 1);
|
|
phr_info->phr_reporting = (1 << phr_cause_phr_config);
|
|
}
|
|
}
|
|
|
|
if (mcg->ext1 && mcg->ext1->dataInactivityTimer) {
|
|
struct NR_SetupRelease_DataInactivityTimer *setup_release = mcg->ext1->dataInactivityTimer;
|
|
if (setup_release->present == NR_SetupRelease_DataInactivityTimer_PR_release)
|
|
free(mac->data_inactivity_timer);
|
|
if (setup_release->present == NR_SetupRelease_DataInactivityTimer_PR_setup) {
|
|
if (!mac->data_inactivity_timer)
|
|
mac->data_inactivity_timer = calloc(1, sizeof(*mac->data_inactivity_timer));
|
|
uint32_t timer_s = get_data_inactivity_timer(setup_release->choice.setup); // timer in seconds
|
|
int scs = mac->current_DL_BWP->scs;
|
|
nr_timer_setup(mac->data_inactivity_timer, (timer_s * 1000) << scs, 1); // 1 slot update rate
|
|
}
|
|
}
|
|
}
|
|
|
|
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,
|
|
module_id_t ue_id)
|
|
{
|
|
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);
|
|
}
|
|
if (!check_csi_report_consistency(sc_info->csi_MeasConfig))
|
|
nr_mac_rrc_verification_failed(ue_id);
|
|
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, mac->ue_id);
|
|
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
|
|
asn1cFreeStruc(asn_DEF_NR_PDSCH_CodeBlockGroupTransmission, sc_info->pdsch_CGB_Transmission);
|
|
free_and_zero(sc_info->xOverhead_PDSCH);
|
|
free_and_zero(sc_info->maxMIMO_Layers_PDSCH);
|
|
free_and_zero(sc_info->nrofHARQ_ProcessesForPDSCH);
|
|
free_and_zero(sc_info->nrofHARQ_ProcessesForPDSCH_v1700);
|
|
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);
|
|
UPDATE_IE(sc_info->nrofHARQ_ProcessesForPDSCH, pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH, long);
|
|
if (pdsch_servingcellconfig->ext3)
|
|
UPDATE_IE(sc_info->nrofHARQ_ProcessesForPDSCH_v1700, pdsch_servingcellconfig->ext3->nrofHARQ_ProcessesForPDSCH_v1700, long);
|
|
else
|
|
free_and_zero(sc_info->nrofHARQ_ProcessesForPDSCH_v1700);
|
|
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:
|
|
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
|
|
asn1cFreeStruc(asn_DEF_NR_PUSCH_CodeBlockGroupTransmission, sc_info->pusch_CGB_Transmission);
|
|
free_and_zero(sc_info->rateMatching_PUSCH);
|
|
free_and_zero(sc_info->xOverhead_PUSCH);
|
|
free_and_zero(sc_info->maxMIMO_Layers_PUSCH);
|
|
free_and_zero(sc_info->nrofHARQ_ProcessesForPUSCH_r17);
|
|
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);
|
|
if (pusch_servingcellconfig->ext3)
|
|
UPDATE_IE(sc_info->nrofHARQ_ProcessesForPUSCH_r17, pusch_servingcellconfig->ext3->nrofHARQ_ProcessesForPUSCH_r17, long);
|
|
else
|
|
free_and_zero(sc_info->nrofHARQ_ProcessesForPUSCH_r17);
|
|
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_and_zero(bwp->msg3_DeltaPreamble);
|
|
free_and_zero(bwp->p0_NominalWithGrant);
|
|
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[j]->bwp_id)
|
|
release_dl_BWP(mac, j);
|
|
}
|
|
}
|
|
}
|
|
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[j]->bwp_id)
|
|
release_ul_BWP(mac, j);
|
|
}
|
|
}
|
|
}
|
|
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,
|
|
int hfn,
|
|
int frame,
|
|
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);
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
int ret = pthread_mutex_lock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
AssertFatal(cell_group_config, "CellGroupConfig should not be NULL\n");
|
|
|
|
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, hfn, frame, spCellConfig->reconfigurationWithSync);
|
|
}
|
|
if (scd) {
|
|
mac->tag_Id = scd->tag_Id;
|
|
configure_servingcell_info(mac, scd);
|
|
configure_BWPs(mac, scd);
|
|
}
|
|
}
|
|
|
|
if (cell_group_config->mac_CellGroupConfig)
|
|
configure_maccellgroup(mac, cell_group_config->mac_CellGroupConfig);
|
|
|
|
for (int j = 0; j < mac->TAG_list.count; j++) {
|
|
// apply the Timing Advance Command for the indicated TAG
|
|
if (mac->TAG_list.array[j]->tag_Id == mac->tag_Id)
|
|
configure_timeAlignmentTimer(&mac->time_alignment_timer, mac->TAG_list.array[j]->timeAlignmentTimer, mac->current_UL_BWP->scs);
|
|
}
|
|
|
|
configure_logicalChannelBearer(mac, cell_group_config->rlc_BearerToAddModList, cell_group_config->rlc_BearerToReleaseList);
|
|
|
|
if (ue_Capability)
|
|
handle_mac_uecap_info(mac, ue_Capability);
|
|
|
|
if (!mac->dl_config_request || !mac->ul_config_request)
|
|
ue_init_config_request(mac, mac->frame_structure.numb_slots_frame);
|
|
ret = pthread_mutex_unlock(&mac->if_mutex);
|
|
AssertFatal(!ret, "mutex failed %d\n", ret);
|
|
}
|
|
|
|
void nr_rrc_mac_config_req_meas(module_id_t module_id, const nr_neighbor_cell_info_t *neighbor_cells, int num_neighbors)
|
|
{
|
|
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
|
|
|
for (int i = 0; i < num_neighbors && i < NUMBER_OF_NEIGHBORING_CELLS_MAX; i++) {
|
|
fapi_nr_neighboring_cell_t *phy_cell = &mac->phy_config.config_req.meas_config.nr_neighboring_cell[i];
|
|
phy_cell->Nid_cell = neighbor_cells[i].Nid_cell;
|
|
phy_cell->ssb_freq = neighbor_cells[i].ssb_freq;
|
|
phy_cell->active = neighbor_cells[i].active;
|
|
}
|
|
|
|
mac->if_module->phy_config_request(&mac->phy_config);
|
|
}
|