Files
openairinterface5g/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
T

4078 lines
188 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* \file ue_procedures.c
* \brief procedures related to UE
* \author R. Knopp, K.H. HSU, G. Casati
* \date 2018
* \version 0.1
* \company Eurecom / NTUST
* \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr, guido.casati@iis.fraunhofer.de
* \note
* \warning
*/
#include <stdio.h>
#include <math.h>
/* exe */
#include "executables/nr-softmodem.h"
/* RRC*/
#include "RRC/NR_UE/rrc_proto.h"
#include "NR_RACH-ConfigCommon.h"
#include "NR_RACH-ConfigGeneric.h"
#include "NR_FrequencyInfoDL.h"
#include "NR_PDCCH-ConfigCommon.h"
/* MAC */
#include "mac_defs.h"
#include "NR_MAC_COMMON/nr_mac.h"
#include "NR_MAC_UE/mac_proto.h"
#include "NR_MAC_UE/mac_extern.h"
#include "common/utils/nr/nr_common.h"
/* PHY */
#include "SCHED_NR_UE/defs.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/NR_TRANSPORT/nr_dci.h"
/*Openair Packet Tracer */
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "executables/softmodem-common.h"
/* utils */
#include "assertions.h"
/* Tools */
#include "asn1_conversions.h"
#include "SIMULATION/TOOLS/sim.h" // for taus
#include "common/utils/LOG/log.h"
#include "SIMULATION/TOOLS/sim.h" // for taus
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include <stdio.h>
#include <math.h>
static prach_association_pattern_t prach_assoc_pattern;
static ssb_list_info_t ssb_list;
//#define ENABLE_MAC_PAYLOAD_DEBUG 1
//#define DEBUG_EXTRACT_DCI
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
static void build_ro_list(NR_ServingCellConfigCommon_t *scc, uint8_t unpaired) {
int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers
int y2; // PRACH Configuration Index table additional variable used to compute the valid frame numbers
uint8_t slot_shift_for_map;
uint8_t map_shift;
boolean_t even_slot_invalid;
int64_t s_map;
uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot
uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot
uint8_t N_dur; // Duration of a PRACH occasion (nb of symbols)
uint8_t frame; // Maximum is NB_FRAMES_IN_MAX_ASSOCIATION_PATTERN_PERIOD
uint8_t slot; // Maximum is the number of slots in a frame @ SCS 240kHz
uint16_t format = 0xffff;
uint8_t format2 = 0xff;
int nb_fdm;
uint8_t config_index, mu;
uint32_t pointa;
int msg1_FDM;
uint8_t prach_conf_period_idx;
uint8_t nb_of_frames_per_prach_conf_period;
uint8_t prach_conf_period_frame_idx;
int64_t *prach_config_info_p;
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
if (setup->msg1_SubcarrierSpacing)
mu = *setup->msg1_SubcarrierSpacing;
else
mu = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
pointa = frequencyInfoDL->absoluteFrequencyPointA;
msg1_FDM = rach_ConfigGeneric->msg1_FDM;
switch (msg1_FDM){
case 0:
case 1:
case 2:
case 3:
nb_fdm = 1 << msg1_FDM;
break;
default:
AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", msg1_FDM);
}
// Create the PRACH occasions map
// ==============================
// WIP: For now assume no rejected PRACH occasions because of conflict with SSB or TDD_UL_DL_ConfigurationCommon schedule
// Identify the proper PRACH Configuration Index table according to the operating frequency
LOG_D(MAC,"Pointa %u, mu = %u, PRACH config index = %u, unpaired = %u\n", pointa, mu, config_index, unpaired);
prach_config_info_p = get_prach_config_info(pointa, config_index, unpaired);
if (pointa > 2016666) { //FR2
x = prach_config_info_p[2];
y = prach_config_info_p[3];
y2 = prach_config_info_p[4];
s_map = prach_config_info_p[5];
prach_conf_start_symbol = prach_config_info_p[6];
N_t_slot = prach_config_info_p[8];
N_dur = prach_config_info_p[9];
if (prach_config_info_p[1] != -1)
format2 = (uint8_t) prach_config_info_p[1];
format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);
slot_shift_for_map = mu-2;
if ( (mu == 3) && (prach_config_info_p[7] == 1) )
even_slot_invalid = true;
else
even_slot_invalid = false;
}
else { // FR1
x = prach_config_info_p[2];
y = prach_config_info_p[3];
y2 = y;
s_map = prach_config_info_p[4];
prach_conf_start_symbol = prach_config_info_p[5];
N_t_slot = prach_config_info_p[7];
N_dur = prach_config_info_p[8];
if (prach_config_info_p[1] != -1)
format2 = (uint8_t) prach_config_info_p[1];
format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);
slot_shift_for_map = mu;
if ( (mu == 1) && (prach_config_info_p[6] <= 1) )
// no prach in even slots @ 30kHz for 1 prach per subframe
even_slot_invalid = true;
else
even_slot_invalid = false;
} // FR2 / FR1
prach_assoc_pattern.nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x;
nb_of_frames_per_prach_conf_period = x;
LOG_D(MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern.nb_of_prach_conf_period_in_max_period);
// Fill in the PRACH occasions table for every slot in every frame in every PRACH configuration periods in the maximum association pattern period
// ----------------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------------------------------------
// For every PRACH configuration periods
// -------------------------------------
for (prach_conf_period_idx=0; prach_conf_period_idx<prach_assoc_pattern.nb_of_prach_conf_period_in_max_period; prach_conf_period_idx++) {
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion = 0;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_frame = nb_of_frames_per_prach_conf_period;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_slot = nr_slots_per_frame[mu];
LOG_D(MAC,"PRACH Conf Period Idx %d\n", prach_conf_period_idx);
// For every frames in a PRACH configuration period
// ------------------------------------------------
for (prach_conf_period_frame_idx=0; prach_conf_period_frame_idx<nb_of_frames_per_prach_conf_period; prach_conf_period_frame_idx++) {
frame = (prach_conf_period_idx * nb_of_frames_per_prach_conf_period) + prach_conf_period_frame_idx;
LOG_D(MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", prach_conf_period_frame_idx, frame);
// Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
if ( (frame%x)==y || (frame%x)==y2 ) {
// For every slot in a frame
// -------------------------
for (slot=0; slot<nr_slots_per_frame[mu]; slot++) {
// Is it a valid slot?
map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
if ( (s_map>>map_shift)&0x01 ) {
// Valid slot
// Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
if ( even_slot_invalid && (slot%2 == 0) )
continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
// We're good: valid frame and valid slot
// Compute all the PRACH occasions in the slot
uint8_t n_prach_occ_in_time;
uint8_t n_prach_occ_in_freq;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_time = N_t_slot;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_freq = nb_fdm;
for (n_prach_occ_in_time=0; n_prach_occ_in_time<N_t_slot; n_prach_occ_in_time++) {
uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
LOG_D(MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time);
for (n_prach_occ_in_freq=0; n_prach_occ_in_freq<nb_fdm; n_prach_occ_in_freq++) {
prach_occasion_info_t *prach_occasion_p = &prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].prach_occasion[n_prach_occ_in_time][n_prach_occ_in_freq];
prach_occasion_p->start_symbol = start_symbol;
prach_occasion_p->fdm = n_prach_occ_in_freq;
prach_occasion_p->frame = frame;
prach_occasion_p->slot = slot;
prach_occasion_p->format = format;
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion++;
LOG_D(MAC,"Adding a PRACH occasion: frame %u, slot-symbol %d-%d, occ_in_time-occ_in-freq %d-%d, nb ROs in conf period %d, for this slot: RO# in time %d, RO# in freq %d\n",
frame, slot, start_symbol, n_prach_occ_in_time, n_prach_occ_in_freq, prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].nb_of_prach_occasion,
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_time,
prach_assoc_pattern.prach_conf_period_list[prach_conf_period_idx].prach_occasion_slot_map[prach_conf_period_frame_idx][slot].nb_of_prach_occasion_in_freq);
} // For every freq in the slot
} // For every time occasions in the slot
} // Valid slot?
} // For every slots in a frame
} // Valid frame?
} // For every frames in a prach configuration period
} // For every prach configuration periods in the maximum association pattern period (160ms)
}
// Build the list of all the valid/transmitted SSBs according to the config
static void build_ssb_list(NR_ServingCellConfigCommon_t *scc) {
// Create the list of transmitted SSBs
// ===================================
BIT_STRING_t *ssb_bitmap;
uint64_t ssb_positionsInBurst;
uint8_t ssb_idx = 0;
switch (scc->ssb_PositionsInBurst->present) {
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint8(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=3; bit_nb<=3; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint8(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=7; bit_nb<=7; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap:
ssb_bitmap = &scc->ssb_PositionsInBurst->choice.longBitmap;
ssb_positionsInBurst = BIT_STRING_to_uint64(ssb_bitmap);
LOG_D(MAC,"SSB config: SSB_positions_in_burst 0x%lx\n", ssb_positionsInBurst);
for (uint8_t bit_nb=63; bit_nb<=63; bit_nb--) {
// If SSB is transmitted
if ((ssb_positionsInBurst>>bit_nb) & 0x01) {
ssb_list.nb_tx_ssb++;
ssb_list.tx_ssb[ssb_idx].transmitted = true;
LOG_D(MAC,"SSB idx %d transmitted\n", ssb_idx);
}
ssb_idx++;
}
break;
default:
AssertFatal(false,"ssb_PositionsInBurst not present\n");
break;
}
}
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
static void map_ssb_to_ro(NR_ServingCellConfigCommon_t *scc) {
// Map SSBs to PRACH occasions
// ===========================
// WIP: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB
uint16_t required_nb_of_prach_occasion; // Nb of RACH occasions required to map all the SSBs
uint8_t required_nb_of_prach_conf_period; // Nb of PRACH configuration periods required to map all the SSBs
// Determine the SSB to RACH mapping ratio
// =======================================
switch (ssb_perRACH_config){
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 8;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 4;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf:
multiple_ssb_per_ro = false;
ssb_rach_ratio = 2;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 1;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 2;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 4;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 8;
break;
case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen:
multiple_ssb_per_ro = true;
ssb_rach_ratio = 16;
break;
default:
AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config);
break;
}
LOG_D(MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro);
// Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
// ==============================================================================================================
// WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same number of PRACH occasions
// (No PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule)
// There is only one possible association period which can contain up to 16 PRACH configuration periods
LOG_D(MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n");
if (true == multiple_ssb_per_ro) {
required_nb_of_prach_occasion = ((ssb_list.nb_tx_ssb-1) + ssb_rach_ratio) / ssb_rach_ratio;
}
else {
required_nb_of_prach_occasion = ssb_list.nb_tx_ssb * ssb_rach_ratio;
}
required_nb_of_prach_conf_period = ((required_nb_of_prach_occasion-1) + prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion) / prach_assoc_pattern.prach_conf_period_list[0].nb_of_prach_occasion;
if (required_nb_of_prach_conf_period == 1) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 1;
}
else if (required_nb_of_prach_conf_period == 2) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 2;
}
else if (required_nb_of_prach_conf_period <= 4) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 4;
}
else if (required_nb_of_prach_conf_period <= 8) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 8;
}
else if (required_nb_of_prach_conf_period <= 16) {
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period = 16;
}
else {
AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period);
}
prach_assoc_pattern.nb_of_assoc_period = 1; // WIP: only one possible association period
prach_assoc_pattern.prach_association_period_list[0].nb_of_frame = prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period * prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
prach_assoc_pattern.nb_of_frame = prach_assoc_pattern.prach_association_period_list[0].nb_of_frame;
LOG_D(MAC,"Assoc period %d, Nb of frames in assoc period %d\n",
prach_assoc_pattern.prach_association_period_list[0].nb_of_prach_conf_period,
prach_assoc_pattern.prach_association_period_list[0].nb_of_frame);
// Proceed to the SSB to RO mapping
// ================================
uint8_t association_period_idx; // Association period index within the association pattern
uint8_t ssb_idx = 0;
uint8_t prach_configuration_period_idx; // PRACH Configuration period index within the association pattern
prach_conf_period_t *prach_conf_period_p;
// Map all the association periods within the association pattern period
LOG_D(MAC,"Proceed to the SSB to RO mapping\n");
for (association_period_idx=0; association_period_idx<prach_assoc_pattern.nb_of_assoc_period; association_period_idx++) {
uint8_t n_prach_conf=0; // PRACH Configuration period index within the association period
uint8_t frame=0;
uint8_t slot=0;
uint8_t ro_in_time=0;
uint8_t ro_in_freq=0;
// Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
prach_configuration_period_idx = 0; // WIP: only one possible association period so the starting PRACH configuration period is automatically 0
// Check if we need to map multiple SSBs per RO or multiple ROs per SSB
if (true == multiple_ssb_per_ro) {
// --------------------
// --------------------
// Multiple SSBs per RO
// --------------------
// --------------------
// WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
ssb_idx = 0;
// Go through the list of PRACH config periods within this association period
for (n_prach_conf=0; n_prach_conf<prach_assoc_pattern.prach_association_period_list[association_period_idx].nb_of_prach_conf_period; n_prach_conf++, prach_configuration_period_idx++) {
// Build the association period with its association PRACH Configuration indexes
prach_conf_period_p = &prach_assoc_pattern.prach_conf_period_list[prach_configuration_period_idx];
prach_assoc_pattern.prach_association_period_list[association_period_idx].prach_conf_period_list[n_prach_conf] = prach_conf_period_p;
// Go through all the ROs within the PRACH config period
for (frame=0; frame<prach_conf_period_p->nb_of_frame; frame++) {
for (slot=0; slot<prach_conf_period_p->nb_of_slot; slot++) {
for (ro_in_time=0; ro_in_time<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_time; ro_in_time++) {
for (ro_in_freq=0; ro_in_freq<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *ro_p = &prach_conf_period_p->prach_occasion_slot_map[frame][slot].prach_occasion[ro_in_time][ro_in_freq];
// Go through the list of transmitted SSBs and map the required amount of SSBs to this RO
// WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
for (; ssb_idx<MAX_NB_SSB; ssb_idx++) {
// Map only the transmitted ssb_idx
if (true == ssb_list.tx_ssb[ssb_idx].transmitted) {
ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
ro_p->nb_mapped_ssb++;
ssb_list.tx_ssb[ssb_idx].mapped_ro[ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > ssb_list.tx_ssb[ssb_idx].nb_mapped_ro,"Too many mapped ROs (%d) to a single SSB\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
LOG_D(MAC,"Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", ssb_idx, ro_p->slot, ro_p->start_symbol, slot, ro_in_time, ro_in_freq, prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(MAC,"Nb mapped ROs for this ssb idx: in the association period only %u\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
// If all the required SSBs are mapped to this RO, exit the loop of SSBs
if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
ssb_idx++;
break;
}
} // if ssb_idx is transmitted
} // for ssb_idx
// Exit the loop of ROs if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for ro_in_freq
// Exit the loop of ROs if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for ro_in_time
// Exit the loop of slots if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for slot
// Exit the loop frames if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for frame
// Exit the loop of PRACH configurations if there is no more SSB to map
if (MAX_NB_SSB == ssb_idx) break;
} // for n_prach_conf
// WIP: note that there is no re-mapping of the SSBs within the association period since there is no invalid ROs in the PRACH config periods that would create this situation
} // if multiple_ssbs_per_ro
else {
// --------------------
// --------------------
// Multiple ROs per SSB
// --------------------
// --------------------
n_prach_conf = 0;
// Go through the list of transmitted SSBs
for (ssb_idx=0; ssb_idx<MAX_NB_SSB; ssb_idx++) {
uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index
// Map only the transmitted ssb_idx
if (true == ssb_list.tx_ssb[ssb_idx].transmitted) {
// Map all the required ROs to this SSB
// Go through the list of PRACH config periods within this association period
for (; n_prach_conf<prach_assoc_pattern.prach_association_period_list[association_period_idx].nb_of_prach_conf_period; n_prach_conf++, prach_configuration_period_idx++) {
// Build the association period with its association PRACH Configuration indexes
prach_conf_period_p = &prach_assoc_pattern.prach_conf_period_list[prach_configuration_period_idx];
prach_assoc_pattern.prach_association_period_list[association_period_idx].prach_conf_period_list[n_prach_conf] = prach_conf_period_p;
for (; frame<prach_conf_period_p->nb_of_frame; frame++) {
for (; slot<prach_conf_period_p->nb_of_slot; slot++) {
for (; ro_in_time<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_time; ro_in_time++) {
for (; ro_in_freq<prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *ro_p = &prach_conf_period_p->prach_occasion_slot_map[frame][slot].prach_occasion[ro_in_time][ro_in_freq];
ro_p->mapped_ssb_idx[0] = ssb_idx;
ro_p->nb_mapped_ssb = 1;
ssb_list.tx_ssb[ssb_idx].mapped_ro[ssb_list.tx_ssb[ssb_idx].nb_mapped_ro] = ro_p;
ssb_list.tx_ssb[ssb_idx].nb_mapped_ro++;
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > ssb_list.tx_ssb[ssb_idx].nb_mapped_ro,"Too many mapped ROs (%d) to a single SSB\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro);
nb_mapped_ro_in_association_period++;
LOG_D(MAC,"Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n", ssb_idx, ro_p->slot, ro_p->start_symbol, slot, ro_in_time, ro_in_freq, prach_conf_period_p->prach_occasion_slot_map[frame][slot].nb_of_prach_occasion_in_freq);
LOG_D(MAC,"Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n", ssb_list.tx_ssb[ssb_idx].nb_mapped_ro, nb_mapped_ro_in_association_period);
// Exit the loop if this SSB has been mapped to all the required ROs
// WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an association period:
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
ro_in_freq++;
break;
}
} // for ro_in_freq
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else ro_in_freq = 0; // else go to the next time symbol in that slot and reset the freq index
} // for ro_in_time
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else ro_in_time = 0; // else go to the next slot in that PRACH config period and reset the symbol index
} // for slot
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else slot = 0; // else go to the next frame in that PRACH config period and reset the slot index
} // for frame
// Exit the loop if this SSB has been mapped to all the required ROs
if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
break;
}
else frame = 0; // else go to the next PRACH config period in that association period and reset the frame index
} // for n_prach_conf
} // if ssb_idx is transmitted
} // for ssb_idx
} // else if multiple_ssbs_per_ro
} // for association_period_index
}
// Returns a RACH occasion if any matches the SSB idx, the frame and the slot
static int get_nr_prach_info_from_ssb_index(uint8_t ssb_idx,
int frame,
int slot,
prach_occasion_info_t **prach_occasion_info_pp) {
ssb_info_t *ssb_info_p;
prach_occasion_slot_t *prach_occasion_slot_p = NULL;
*prach_occasion_info_pp = NULL;
// Search for a matching RO slot in the SSB_to_RO map
// A valid RO slot will match:
// - ssb_idx mapped to one of the ROs in that RO slot
// - exact slot number
// - frame offset
ssb_info_p = &ssb_list.tx_ssb[ssb_idx];
for (uint8_t n_mapped_ro=0; n_mapped_ro<ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) &&
(ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern.nb_of_frame))) {
uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern.prach_conf_period_list[0].nb_of_frame;
prach_occasion_slot_p = &prach_assoc_pattern.prach_conf_period_list[prach_config_period_nb].prach_occasion_slot_map[frame_nb_in_prach_config_period][slot];
}
}
// If there is a matching RO slot in the SSB_to_RO map
if (NULL != prach_occasion_slot_p)
{
// A random RO mapped to the SSB index should be selected in the slot
// First count the number of times the SSB index is found in that RO
uint8_t nb_mapped_ssb = 0;
for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *prach_occasion_info_p = &prach_occasion_slot_p->prach_occasion[ro_in_time][ro_in_freq];
for (uint8_t ssb_nb=0; ssb_nb<prach_occasion_info_p->nb_mapped_ssb; ssb_nb++) {
if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
nb_mapped_ssb++;
}
}
}
}
// Choose a random SSB nb
uint8_t random_ssb_nb = 0;
random_ssb_nb = ((taus()) % nb_mapped_ssb);
// Select the RO according to the chosen random SSB nb
nb_mapped_ssb=0;
for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
prach_occasion_info_t *prach_occasion_info_p = &prach_occasion_slot_p->prach_occasion[ro_in_time][ro_in_freq];
for (uint8_t ssb_nb=0; ssb_nb<prach_occasion_info_p->nb_mapped_ssb; ssb_nb++) {
if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
if (nb_mapped_ssb == random_ssb_nb) {
*prach_occasion_info_pp = prach_occasion_info_p;
return 1;
}
else {
nb_mapped_ssb++;
}
}
}
}
}
}
return 0;
}
// Build the SSB to RO mapping upon RRC configuration update
void build_ssb_to_ro_map(NR_ServingCellConfigCommon_t *scc, uint8_t unpaired){
// Clear all the lists and maps
memset(&prach_assoc_pattern, 0, sizeof(prach_association_pattern_t));
memset(&ssb_list, 0, sizeof(ssb_list_info_t));
// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
LOG_D(MAC,"Build RO list\n");
build_ro_list(scc, unpaired);
// Build the list of all the valid/transmitted SSBs according to the config
LOG_D(MAC,"Build SSB list\n");
build_ssb_list(scc);
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
LOG_D(MAC,"Map SSB to RO\n");
map_ssb_to_ro(scc);
LOG_D(MAC,"Map SSB to RO done\n");
}
void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
fapi_nr_dl_config_request_t *dl_config,
fapi_nr_ul_config_request_t *ul_config,
fapi_nr_tx_request_t *tx_request,
module_id_t mod_id,
int cc_id,
frame_t frame,
int slot,
int thread_id){
scheduled_response->dl_config = dl_config;
scheduled_response->ul_config = ul_config;
scheduled_response->tx_request = tx_request;
scheduled_response->module_id = mod_id;
scheduled_response->CC_id = cc_id;
scheduled_response->frame = frame;
scheduled_response->slot = slot;
scheduled_response->thread_id = thread_id;
}
uint32_t get_ssb_slot(uint32_t ssb_index){
// this function now only support f <= 3GHz
return ssb_index & 0x3 ;
// return first_symbol(case, freq, ssb_index) / 14
}
int8_t nr_ue_decode_mib(module_id_t module_id,
int cc_id,
uint8_t gNB_index,
uint8_t extra_bits, // 8bits 38.212 c7.1.1
uint32_t ssb_length,
uint32_t ssb_index,
void *pduP,
uint16_t cell_id)
{
LOG_I(MAC,"[L2][MAC] decode mib\n");
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
nr_mac_rrc_data_ind_ue( module_id, cc_id, gNB_index, NR_BCCH_BCH, (uint8_t *) pduP, 3 ); // fixed 3 bytes MIB PDU
AssertFatal(mac->mib != NULL, "nr_ue_decode_mib() mac->mib == NULL\n");
//if(mac->mib != NULL){
uint16_t frame = (mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused);
uint16_t frame_number_4lsb = 0;
for (int i=0; i<4; i++)
frame_number_4lsb |= ((extra_bits>>i)&1)<<(3-i);
uint8_t half_frame_bit = ( extra_bits >> 4 ) & 0x1; // extra bits[4]
uint8_t ssb_subcarrier_offset_msb = ( extra_bits >> 5 ) & 0x1; // extra bits[5]
uint8_t ssb_subcarrier_offset = (uint8_t)mac->mib->ssb_SubcarrierOffset;
frame = frame << 4;
frame = frame | frame_number_4lsb;
if(ssb_length == 64){
for (int i=0; i<3; i++)
ssb_index += (((extra_bits>>(7-i))&0x01)<<(3+i));
}else{
if(ssb_subcarrier_offset_msb){
ssb_subcarrier_offset = ssb_subcarrier_offset | 0x10;
}
}
LOG_D(MAC,"system frame number(6 MSB bits): %d\n", mac->mib->systemFrameNumber.buf[0]);
LOG_D(MAC,"system frame number(with LSB): %d\n", (int)frame);
LOG_D(MAC,"subcarrier spacing (0=15or60, 1=30or120): %d\n", (int)mac->mib->subCarrierSpacingCommon);
LOG_D(MAC,"ssb carrier offset(with MSB): %d\n", (int)ssb_subcarrier_offset);
LOG_D(MAC,"dmrs type A position (0=pos2,1=pos3): %d\n", (int)mac->mib->dmrs_TypeA_Position);
LOG_D(MAC,"cell barred (0=barred,1=notBarred): %d\n", (int)mac->mib->cellBarred);
LOG_D(MAC,"intra frequency reselection (0=allowed,1=notAllowed): %d\n", (int)mac->mib->intraFreqReselection);
LOG_D(MAC,"half frame bit(extra bits): %d\n", (int)half_frame_bit);
LOG_D(MAC,"ssb index(extra bits): %d\n", (int)ssb_index);
subcarrier_spacing_t scs_ssb = scs_30kHz; // default for
//const uint32_t scs_index = 0;
const uint32_t num_slot_per_frame = 20;
subcarrier_spacing_t scs_pdcch;
// assume carrier frequency < 6GHz
if(mac->mib->subCarrierSpacingCommon == NR_MIB__subCarrierSpacingCommon_scs15or60){
scs_pdcch = scs_15kHz;
}else{ //NR_MIB__subCarrierSpacingCommon_scs30or120
scs_pdcch = scs_30kHz;
}
channel_bandwidth_t min_channel_bw = bw_10MHz; // deafult for testing
uint32_t is_condition_A = (ssb_subcarrier_offset == 0); // 38.213 ch.13
frequency_range_t frequency_range = FR1;
uint32_t index_4msb = (mac->mib->pdcch_ConfigSIB1.controlResourceSetZero);
uint32_t index_4lsb = (mac->mib->pdcch_ConfigSIB1.searchSpaceZero);
int32_t num_rbs = -1;
int32_t num_symbols = -1;
int32_t rb_offset = -1;
LOG_D(MAC,"<<<<<<<<<configSIB1: controlResourceSetZero %d searchSpaceZero %d scs_ssb %d scs_pdcch %d switch %d ",
index_4msb,index_4lsb,scs_ssb,scs_pdcch, (scs_ssb << 5)|scs_pdcch);
// type0-pdcch coreset
switch( (scs_ssb << 5)|scs_pdcch ){
case (scs_15kHz << 5) | scs_15kHz :
AssertFatal(index_4msb < 15, "38.213 Table 13-1 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_1_c2[index_4msb];
num_symbols = table_38213_13_1_c3[index_4msb];
rb_offset = table_38213_13_1_c4[index_4msb];
break;
case (scs_15kHz << 5) | scs_30kHz:
AssertFatal(index_4msb < 14, "38.213 Table 13-2 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_2_c2[index_4msb];
num_symbols = table_38213_13_2_c3[index_4msb];
rb_offset = table_38213_13_2_c4[index_4msb];
break;
case (scs_30kHz << 5) | scs_15kHz:
if((min_channel_bw & bw_5MHz) | (min_channel_bw & bw_10MHz)){
AssertFatal(index_4msb < 9, "38.213 Table 13-3 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_3_c2[index_4msb];
num_symbols = table_38213_13_3_c3[index_4msb];
rb_offset = table_38213_13_3_c4[index_4msb];
}else if(min_channel_bw & bw_40MHz){
AssertFatal(index_4msb < 9, "38.213 Table 13-5 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_5_c2[index_4msb];
num_symbols = table_38213_13_5_c3[index_4msb];
rb_offset = table_38213_13_5_c4[index_4msb];
}else{ ; }
break;
case (scs_30kHz << 5) | scs_30kHz:
if((min_channel_bw & bw_5MHz) | (min_channel_bw & bw_10MHz)){
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_4_c2[index_4msb];
num_symbols = table_38213_13_4_c3[index_4msb];
rb_offset = table_38213_13_4_c4[index_4msb];
LOG_D(MAC,"<<<<<<<<<index_4msb %d num_rbs %d num_symb %d rb_offset %d\n",index_4msb,num_rbs,num_symbols,rb_offset );
}else if(min_channel_bw & bw_40MHz){
AssertFatal(index_4msb < 10, "38.213 Table 13-6 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_6_c2[index_4msb];
num_symbols = table_38213_13_6_c3[index_4msb];
rb_offset = table_38213_13_6_c4[index_4msb];
}else{ ; }
break;
case (scs_120kHz << 5) | scs_60kHz:
AssertFatal(index_4msb < 12, "38.213 Table 13-7 4 MSB out of range\n");
if(index_4msb & 0x7){
mac->type0_pdcch_ss_mux_pattern = 1;
}else if(index_4msb & 0x18){
mac->type0_pdcch_ss_mux_pattern = 2;
}else{ ; }
num_rbs = table_38213_13_7_c2[index_4msb];
num_symbols = table_38213_13_7_c3[index_4msb];
if(!is_condition_A && (index_4msb == 8 || index_4msb == 10)){
rb_offset = table_38213_13_7_c4[index_4msb] - 1;
}else{
rb_offset = table_38213_13_7_c4[index_4msb];
}
break;
case (scs_120kHz << 5) | scs_120kHz:
AssertFatal(index_4msb < 8, "38.213 Table 13-8 4 MSB out of range\n");
if(index_4msb & 0x3){
mac->type0_pdcch_ss_mux_pattern = 1;
}else if(index_4msb & 0x0c){
mac->type0_pdcch_ss_mux_pattern = 3;
}
num_rbs = table_38213_13_8_c2[index_4msb];
num_symbols = table_38213_13_8_c3[index_4msb];
if(!is_condition_A && (index_4msb == 4 || index_4msb == 6)){
rb_offset = table_38213_13_8_c4[index_4msb] - 1;
}else{
rb_offset = table_38213_13_8_c4[index_4msb];
}
break;
case (scs_240kHz << 5) | scs_60kHz:
AssertFatal(index_4msb < 4, "38.213 Table 13-9 4 MSB out of range\n");
mac->type0_pdcch_ss_mux_pattern = 1;
num_rbs = table_38213_13_9_c2[index_4msb];
num_symbols = table_38213_13_9_c3[index_4msb];
rb_offset = table_38213_13_9_c4[index_4msb];
break;
case (scs_240kHz << 5) | scs_120kHz:
AssertFatal(index_4msb < 8, "38.213 Table 13-10 4 MSB out of range\n");
if(index_4msb & 0x3){
mac->type0_pdcch_ss_mux_pattern = 1;
}else if(index_4msb & 0x0c){
mac->type0_pdcch_ss_mux_pattern = 2;
}
num_rbs = table_38213_13_10_c2[index_4msb];
num_symbols = table_38213_13_10_c3[index_4msb];
if(!is_condition_A && (index_4msb == 4 || index_4msb == 6)){
rb_offset = table_38213_13_10_c4[index_4msb]-1;
}else{
rb_offset = table_38213_13_10_c4[index_4msb];
}
break;
default:
break;
}
AssertFatal(num_rbs != -1, "Type0 PDCCH coreset num_rbs undefined");
AssertFatal(num_symbols != -1, "Type0 PDCCH coreset num_symbols undefined");
AssertFatal(rb_offset != -1, "Type0 PDCCH coreset rb_offset undefined");
//uint32_t cell_id = 0; // obtain from L1 later
//mac->type0_pdcch_dci_config.coreset.rb_start = rb_offset;
//mac->type0_pdcch_dci_config.coreset.rb_end = rb_offset + num_rbs - 1;
uint64_t mask = 0x0;
uint8_t i;
for(i=0; i<(num_rbs/6); ++i){ // 38.331 Each bit corresponds a group of 6 RBs
mask = mask >> 1;
mask = mask | 0x100000000000;
}
//LOG_I(MAC,">>>>>>>>mask %x num_rbs %d rb_offset %d\n", mask, num_rbs, rb_offset);
/*
mac->type0_pdcch_dci_config.coreset.frequency_domain_resource = mask;
mac->type0_pdcch_dci_config.coreset.rb_offset = rb_offset; // additional parameter other than coreset
//mac->type0_pdcch_dci_config.type0_pdcch_coreset.duration = num_symbols;
mac->type0_pdcch_dci_config.coreset.cce_reg_mapping_type = CCE_REG_MAPPING_TYPE_INTERLEAVED;
mac->type0_pdcch_dci_config.coreset.cce_reg_interleaved_reg_bundle_size = 6; // L 38.211 7.3.2.2
mac->type0_pdcch_dci_config.coreset.cce_reg_interleaved_interleaver_size = 2; // R 38.211 7.3.2.2
mac->type0_pdcch_dci_config.coreset.cce_reg_interleaved_shift_index = cell_id;
mac->type0_pdcch_dci_config.coreset.precoder_granularity = PRECODER_GRANULARITY_SAME_AS_REG_BUNDLE;
mac->type0_pdcch_dci_config.coreset.pdcch_dmrs_scrambling_id = cell_id;
*/
// type0-pdcch search space
float big_o;
float big_m;
uint32_t temp;
SFN_C_TYPE sfn_c=SFN_C_IMPOSSIBLE; // only valid for mux=1
uint32_t n_c=UINT_MAX;
uint32_t number_of_search_space_per_slot=UINT_MAX;
// uint32_t first_symbol_index=UINT_MAX;
// uint32_t search_space_duration; // element of search space
// 38.213 table 10.1-1
/// MUX PATTERN 1
if(mac->type0_pdcch_ss_mux_pattern == 1 && frequency_range == FR1){
big_o = table_38213_13_11_c1[index_4lsb];
number_of_search_space_per_slot = table_38213_13_11_c2[index_4lsb];
big_m = table_38213_13_11_c3[index_4lsb];
temp = (uint32_t)(big_o*pow(2, scs_pdcch)) + (uint32_t)(ssb_index*big_m);
n_c = temp / num_slot_per_frame;
if((temp/num_slot_per_frame) & 0x1){
sfn_c = SFN_C_MOD_2_EQ_1;
}else{
sfn_c = SFN_C_MOD_2_EQ_0;
}
// if((index_4lsb == 1 || index_4lsb == 3 || index_4lsb == 5 || index_4lsb == 7) && (ssb_index&1)){
// first_symbol_index = num_symbols;
// }else{
// first_symbol_index = table_38213_13_11_c4[index_4lsb];
// }
// 38.213 chapter 13: over two consecutive slots
// search_space_duration = 2;
}
if(mac->type0_pdcch_ss_mux_pattern == 1 && frequency_range == FR2){
big_o = table_38213_13_12_c1[index_4lsb];
number_of_search_space_per_slot = table_38213_13_11_c2[index_4lsb];
big_m = table_38213_13_12_c3[index_4lsb];
// if((index_4lsb == 1 || index_4lsb == 3 || index_4lsb == 5 || index_4lsb == 10) && (ssb_index&1)){
// first_symbol_index = 7;
// }else if((index_4lsb == 6 || index_4lsb == 7 || index_4lsb == 8 || index_4lsb == 11) && (ssb_index&1)){
// first_symbol_index = num_symbols;
// }else{
// first_symbol_index = 0;
// }
// 38.213 chapter 13: over two consecutive slots
//search_space_duration = 2;
}
/// MUX PATTERN 2
if(mac->type0_pdcch_ss_mux_pattern == 2){
if((scs_ssb == scs_120kHz) && (scs_pdcch == scs_60kHz)){
// 38.213 Table 13-13
AssertFatal(index_4lsb == 0, "38.213 Table 13-13 4 LSB out of range\n");
// PDCCH monitoring occasions (SFN and slot number) same as SSB frame-slot
// sfn_c = SFN_C_EQ_SFN_SSB;
n_c = get_ssb_slot(ssb_index);
// switch(ssb_index & 0x3){ // ssb_index(i) mod 4
// case 0:
// first_symbol_index = 0;
// break;
// case 1:
// first_symbol_index = 1;
// break;
// case 2:
// first_symbol_index = 6;
// break;
// case 3:
// first_symbol_index = 7;
// break;
// default: break;
// }
}else if((scs_ssb == scs_240kHz) && (scs_pdcch == scs_120kHz)){
// 38.213 Table 13-14
AssertFatal(index_4lsb == 0, "38.213 Table 13-14 4 LSB out of range\n");
// PDCCH monitoring occasions (SFN and slot number) same as SSB frame-slot
// sfn_c = SFN_C_EQ_SFN_SSB;
n_c = get_ssb_slot(ssb_index);
switch(ssb_index & 0x7){ // ssb_index(i) mod 8
case 0:
// first_symbol_index = 0;
break;
case 1:
// first_symbol_index = 1;
break;
case 2:
// first_symbol_index = 2;
break;
case 3:
// first_symbol_index = 3;
break;
case 4:
// first_symbol_index = 12;
n_c = get_ssb_slot(ssb_index) - 1;
break;
case 5:
// first_symbol_index = 13;
n_c = get_ssb_slot(ssb_index) - 1;
break;
case 6:
// first_symbol_index = 0;
break;
case 7:
// first_symbol_index = 1;
break;
default: break;
}
}else{ ; }
// 38.213 chapter 13: over one slot
// search_space_duration = 1;
}
/// MUX PATTERN 3
if(mac->type0_pdcch_ss_mux_pattern == 3){
if((scs_ssb == scs_120kHz) && (scs_pdcch == scs_120kHz)){
// 38.213 Table 13-15
AssertFatal(index_4lsb == 0, "38.213 Table 13-15 4 LSB out of range\n");
// PDCCH monitoring occasions (SFN and slot number) same as SSB frame-slot
// sfn_c = SFN_C_EQ_SFN_SSB;
n_c = get_ssb_slot(ssb_index);
// switch(ssb_index & 0x3){ // ssb_index(i) mod 4
// case 0:
// first_symbol_index = 4;
// break;
// case 1:
// first_symbol_index = 8;
// break;
// case 2:
// first_symbol_index = 2;
// break;
// case 3:
// first_symbol_index = 6;
// break;
// default: break;
// }
}else{ ; }
// 38.213 chapter 13: over one slot
// search_space_duration = 1;
}
AssertFatal(number_of_search_space_per_slot!=UINT_MAX,"");
/*
uint32_t coreset_duration = num_symbols * number_of_search_space_per_slot;
mac->type0_pdcch_dci_config.number_of_candidates[0] = table_38213_10_1_1_c2[0];
mac->type0_pdcch_dci_config.number_of_candidates[1] = table_38213_10_1_1_c2[1];
mac->type0_pdcch_dci_config.number_of_candidates[2] = table_38213_10_1_1_c2[2]; // CCE aggregation level = 4
mac->type0_pdcch_dci_config.number_of_candidates[3] = table_38213_10_1_1_c2[3]; // CCE aggregation level = 8
mac->type0_pdcch_dci_config.number_of_candidates[4] = table_38213_10_1_1_c2[4]; // CCE aggregation level = 16
mac->type0_pdcch_dci_config.duration = search_space_duration;
mac->type0_pdcch_dci_config.coreset.duration = coreset_duration; // coreset
AssertFatal(first_symbol_index!=UINT_MAX,"");
mac->type0_pdcch_dci_config.monitoring_symbols_within_slot = (0x3fff << first_symbol_index) & (0x3fff >> (14-coreset_duration-first_symbol_index)) & 0x3fff;
*/
AssertFatal(sfn_c!=SFN_C_IMPOSSIBLE,"");
AssertFatal(n_c!=UINT_MAX,"");
mac->type0_pdcch_ss_sfn_c = sfn_c;
mac->type0_pdcch_ss_n_c = n_c;
// fill in the elements in config request inside P5 message
mac->phy_config.Mod_id = module_id;
mac->phy_config.CC_id = cc_id;
mac->dl_config_request.sfn = frame;
mac->dl_config_request.slot = (ssb_index>>1) + ((ssb_index>>4)<<1); // not valid for 240kHz SCS
//}
return 0;
}
// TODO: change to UE parameter, scs: 15KHz, slot duration: 1ms
uint32_t get_ssb_frame(uint32_t test){
return test;
}
/*
* This function returns the slot offset K2 corresponding to a given time domain
* indication value from RRC configuration.
*/
long get_k2(NR_UE_MAC_INST_t *mac, uint8_t time_domain_ind) {
long k2 = -1;
// Get K2 from RRC configuration
NR_PUSCH_Config_t *pusch_config=mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL;
if (pusch_config->pusch_TimeDomainAllocationList) {
pusch_TimeDomainAllocationList = pusch_config->pusch_TimeDomainAllocationList->choice.setup;
}
else if (mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) {
pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
}
if (pusch_TimeDomainAllocationList) {
if (time_domain_ind >= pusch_TimeDomainAllocationList->list.count) {
LOG_E(MAC, "time_domain_ind %d >= pusch->TimeDomainAllocationList->list.count %d\n",
time_domain_ind, pusch_TimeDomainAllocationList->list.count);
return -1;
}
k2 = *pusch_TimeDomainAllocationList->list.array[time_domain_ind]->k2;
}
LOG_D(MAC, "get_k2(): k2 is %ld\n", k2);
return k2;
}
/*
* This function returns the UL config corresponding to a given UL slot
* from MAC instance .
*/
fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int slot) {
//Check if request to access ul_config is for a UL slot
if (is_nr_UL_slot(mac->scc, slot) == 0) {
LOG_W(MAC, "Slot %d is not a UL slot. get_ul_config_request() called for wrong slot!!!\n", slot);
return NULL;
}
// Calculate the index of the UL slot in mac->ul_config_request list. This is
// based on the TDD pattern (slot configuration period) and number of UL+mixed
// slots in the period. TS 38.213 Sec 11.1
int mu = mac->ULbwp[0]->bwp_Common->genericParameters.subcarrierSpacing;
NR_TDD_UL_DL_Pattern_t *tdd_pattern = &mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1;
const int num_slots_per_tdd = nr_slots_per_frame[mu] >> (7 - tdd_pattern->dl_UL_TransmissionPeriodicity);
const int num_slots_ul = tdd_pattern->nrofUplinkSlots + (tdd_pattern->nrofUplinkSymbols!=0);
int index = (slot + num_slots_ul - num_slots_per_tdd) % num_slots_per_tdd;
LOG_D(MAC, "nr_ue_procedures: get_ul_config_request() slots per tdd %d, num_slots_ul %d, index %d\n",
num_slots_per_tdd,
num_slots_ul,
index);
return &mac->ul_config_request[index];
}
// Performs :
// 1. TODO: Call RRC for link status return to PHY
// 2. TODO: Perform SR/BSR procedures for scheduling feedback
// 3. TODO: Perform PHR procedures
NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_indication_t *ul_info){
uint32_t search_space_mask = 0;
if (dl_info){
module_id_t mod_id = dl_info->module_id;
uint32_t gNB_index = dl_info->gNB_index;
int cc_id = dl_info->cc_id;
frame_t rx_frame = dl_info->frame;
slot_t rx_slot = dl_info->slot;
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
fapi_nr_dl_config_request_t *dl_config = &mac->dl_config_request;
nr_scheduled_response_t scheduled_response;
nr_dcireq_t dcireq;
// check type0 from 38.213 13 if we have no CellGroupConfig
// TODO: implementation to be completed
if (mac->scg == NULL) {
if(dl_info->ssb_index != -1){
if(mac->type0_pdcch_ss_mux_pattern == 1){
// 38.213 chapter 13
if((mac->type0_pdcch_ss_sfn_c == SFN_C_MOD_2_EQ_0) && !(rx_frame & 0x1) && (rx_slot == mac->type0_pdcch_ss_n_c)){
search_space_mask = search_space_mask | type0_pdcch;
mac->type0_pdcch_consecutive_slots = mac->type0_pdcch_dci_config.coreset.duration;
}
if((mac->type0_pdcch_ss_sfn_c == SFN_C_MOD_2_EQ_1) && (rx_frame & 0x1) && (rx_slot == mac->type0_pdcch_ss_n_c)){
search_space_mask = search_space_mask | type0_pdcch;
mac->type0_pdcch_consecutive_slots = mac->type0_pdcch_dci_config.coreset.duration;
}
}
if(mac->type0_pdcch_ss_mux_pattern == 2){
// 38.213 Table 13-13, 13-14
if((rx_frame == get_ssb_frame(rx_frame)) && (rx_slot == mac->type0_pdcch_ss_n_c)){
search_space_mask = search_space_mask | type0_pdcch;
mac->type0_pdcch_consecutive_slots = mac->type0_pdcch_dci_config.coreset.duration;
}
}
if(mac->type0_pdcch_ss_mux_pattern == 3){
// 38.213 Table 13-15
if((rx_frame == get_ssb_frame(rx_frame)) && (rx_slot == mac->type0_pdcch_ss_n_c)){
search_space_mask = search_space_mask | type0_pdcch;
mac->type0_pdcch_consecutive_slots = mac->type0_pdcch_dci_config.coreset.duration;
}
}
} // ssb_index != -1
// Type0 PDCCH search space
if((search_space_mask & type0_pdcch) || ( mac->type0_pdcch_consecutive_slots != 0 )){
mac->type0_pdcch_consecutive_slots = mac->type0_pdcch_consecutive_slots - 1;
dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15 = mac->type0_pdcch_dci_config;
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DCI;
/*
dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.rnti = 0xaaaa; // to be set
dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.N_RB_BWP = 106; // to be set
LOG_I(MAC,"nr_ue_scheduler Type0 PDCCH with rnti %x, BWP %d\n",
dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.rnti,
dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.N_RB_BWP);
*/
dl_config->number_pdus = dl_config->number_pdus + 1;
fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id);
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
mac->if_module->scheduled_response(&scheduled_response);
}
} else { // we have an scg
dcireq.module_id = mod_id;
dcireq.gNB_index = gNB_index;
dcireq.cc_id = cc_id;
dcireq.frame = rx_frame;
dcireq.slot = rx_slot;
dcireq.dl_config_req.number_pdus = 0;
nr_ue_dcireq(&dcireq); //to be replaced with function pointer later
fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id);
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){
mac->if_module->scheduled_response(&scheduled_response);
}
/*
if(search_space_mask & type0a_pdcch){
}
if(search_space_mask & type1_pdcch){
}
if(search_space_mask & type2_pdcch){
}
if(search_space_mask & type3_pdcch){
}
*/
}
} else if (ul_info) {
module_id_t mod_id = ul_info->module_id;
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
RA_config_t *ra = &mac->ra;
if (ra->ra_state == WAIT_RAR){
if (ra->RA_active && ul_info->slot_tx == ra->msg3_slot && ul_info->frame_tx == ra->msg3_frame){
uint8_t ulsch_input_buffer[MAX_ULSCH_PAYLOAD_BYTES];
nr_scheduled_response_t scheduled_response;
fapi_nr_tx_request_t tx_req;
//fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, ul_info->slot_tx);
fapi_nr_ul_config_request_t *ul_config = &mac->ul_config_request[0];
fapi_nr_ul_config_request_pdu_t *ul_config_list = &ul_config->ul_config_list[ul_config->number_pdus];
uint16_t TBS_bytes = ul_config_list->pusch_config_pdu.pusch_data.tb_size;
//if (IS_SOFTMODEM_NOS1){
// // Getting IP traffic to be transmitted
// data_existing = nr_ue_get_sdu(mod_id,
// cc_id,
// frame_tx,
// slot_tx,
// 0,
// ulsch_input_buffer,
// TBS_bytes,
// &access_mode);
//}
//Random traffic to be transmitted if there is no IP traffic available for this Tx opportunity
//if (!IS_SOFTMODEM_NOS1 || !data_existing) {
//Use zeros for the header bytes in noS1 mode, in order to make sure that the LCID is not valid
//and block this traffic from being forwarded to the upper layers at the gNB
LOG_D(MAC, "Random data to be tranmsitted (TBS_bytes %d): \n", TBS_bytes);
//Give the first byte a dummy value (a value not corresponding to any valid LCID based on 38.321, Table 6.2.1-2)
//in order to distinguish the PHY random packets at the MAC layer of the gNB receiver from the normal packets that should
//have a valid LCID (nr_process_mac_pdu function)
ulsch_input_buffer[0] = 0x31;
for (int i = 1; i < TBS_bytes; i++) {
ulsch_input_buffer[i] = (unsigned char) rand();
//printf(" input encoder a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
}
//}
LOG_D(MAC, "[UE %d] Frame %d, Subframe %d Adding Msg3 UL Config Request for rnti: %x\n",
ul_info->module_id,
ul_info->frame_tx,
ul_info->slot_tx,
ra->t_crnti);
// Config UL TX PDU
tx_req.slot = ul_info->slot_tx;
tx_req.sfn = ul_info->frame_tx;
tx_req.number_of_pdus = 1;
tx_req.tx_request_body[0].pdu_length = TBS_bytes;
tx_req.tx_request_body[0].pdu_index = 0;
tx_req.tx_request_body[0].pdu = ulsch_input_buffer;
ul_config_list->pdu_type = FAPI_NR_UL_CONFIG_TYPE_PUSCH;
ul_config->number_pdus++;
// scheduled_response
fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, ul_info->module_id, ul_info->cc_id, ul_info->frame_rx, ul_info->slot_rx, ul_info->thread_id);
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){
mac->if_module->scheduled_response(&scheduled_response);
}
if (!ra->cfra){
nr_Msg3_transmitted(ul_info->module_id, ul_info->cc_id, ul_info->frame_tx, ul_info->gNB_index);
}
}
} else if (ra->ra_state == RA_SUCCEEDED || get_softmodem_params()->phy_test) {
uint8_t nb_dmrs_re_per_rb;
uint8_t ulsch_input_buffer[MAX_ULSCH_PAYLOAD_BYTES];
uint8_t data_existing = 0;
uint16_t TBS_bytes;
uint32_t TBS;
int i, N_PRB_oh;
int cc_id = ul_info->cc_id;
frame_t rx_frame = ul_info->frame_rx;
slot_t rx_slot = ul_info->slot_rx;
frame_t frame_tx = ul_info->frame_tx;
slot_t slot_tx = ul_info->slot_tx;
uint8_t access_mode = SCHEDULED_ACCESS;
fapi_nr_ul_config_request_t *ul_config_req = get_ul_config_request(mac, slot_tx);
// Schedule ULSCH only if the current frame and slot match those in ul_config_req
// AND if a UL DCI has been received (as indicated by num_pdus).
if ((frame_tx == ul_config_req->sfn && slot_tx == ul_config_req->slot) &&
ul_config_req->number_pdus > 0) {
// program PUSCH with UL DCI parameters
nr_scheduled_response_t scheduled_response;
fapi_nr_tx_request_t tx_req;
nfapi_nr_ue_ptrs_ports_t ptrs_ports_list;
for (int j = 0; j < ul_config_req->number_pdus; j++) {
fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = &ul_config_req->ul_config_list[j];
if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
// These should come from RRC config!!!
uint8_t ptrs_mcs1 = 2;
uint8_t ptrs_mcs2 = 4;
uint8_t ptrs_mcs3 = 10;
uint16_t n_rb0 = 25;
uint16_t n_rb1 = 75;
uint8_t ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, ulcfg_pdu->pusch_config_pdu.mcs_index, ulcfg_pdu->pusch_config_pdu.mcs_table);
uint8_t ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, ulcfg_pdu->pusch_config_pdu.rb_size);
uint16_t l_prime_mask = get_l_prime(ulcfg_pdu->pusch_config_pdu.nr_of_symbols, typeB, pusch_dmrs_pos0, pusch_len1);
uint16_t ul_dmrs_symb_pos = l_prime_mask << ulcfg_pdu->pusch_config_pdu.start_symbol_index;
uint8_t dmrs_config_type = 0;
uint16_t number_dmrs_symbols = 0;
// PTRS ports configuration
// TbD: ptrs_dmrs_port and ptrs_port_index are not initialised!
ptrs_ports_list.ptrs_re_offset = 0;
// Num PRB Overhead from PUSCH-ServingCellConfig
if (mac->scg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->xOverhead == NULL)
N_PRB_oh = 0;
else
N_PRB_oh = *mac->scg->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->xOverhead;
ulcfg_pdu->pusch_config_pdu.ul_dmrs_symb_pos = ul_dmrs_symb_pos;
ulcfg_pdu->pusch_config_pdu.dmrs_config_type = dmrs_config_type;
ulcfg_pdu->pusch_config_pdu.num_dmrs_cdm_grps_no_data = 1;
ulcfg_pdu->pusch_config_pdu.nrOfLayers = 1;
ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator = 0;
ulcfg_pdu->pusch_config_pdu.pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
ulcfg_pdu->pusch_config_pdu.pusch_ptrs.ptrs_time_density = ptrs_time_density;
ulcfg_pdu->pusch_config_pdu.pusch_ptrs.ptrs_freq_density = ptrs_freq_density;
ulcfg_pdu->pusch_config_pdu.pusch_ptrs.ptrs_ports_list = &ptrs_ports_list;
//ulcfg_pdu->pusch_config_pdu.target_code_rate = nr_get_code_rate_ul(ulcfg_pdu->pusch_config_pdu.mcs_index, ulcfg_pdu->pusch_config_pdu.mcs_table);
//ulcfg_pdu->pusch_config_pdu.qam_mod_order = nr_get_Qm_ul(ulcfg_pdu->pusch_config_pdu.mcs_index, ulcfg_pdu->pusch_config_pdu.mcs_table);
if (1 << ulcfg_pdu->pusch_config_pdu.pusch_ptrs.ptrs_time_density >= ulcfg_pdu->pusch_config_pdu.nr_of_symbols) {
ulcfg_pdu->pusch_config_pdu.pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
}
get_num_re_dmrs(&ulcfg_pdu->pusch_config_pdu,
&nb_dmrs_re_per_rb,
&number_dmrs_symbols);
TBS = nr_compute_tbs(ulcfg_pdu->pusch_config_pdu.qam_mod_order,
ulcfg_pdu->pusch_config_pdu.target_code_rate,
ulcfg_pdu->pusch_config_pdu.rb_size,
ulcfg_pdu->pusch_config_pdu.nr_of_symbols,
nb_dmrs_re_per_rb*number_dmrs_symbols,
N_PRB_oh,
0,
ulcfg_pdu->pusch_config_pdu.nrOfLayers);
TBS_bytes = TBS/8;
ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size = TBS_bytes;
if (IS_SOFTMODEM_NOS1){
// Getting IP traffic to be transmitted
data_existing = nr_ue_get_sdu(mod_id,
cc_id,
frame_tx,
slot_tx,
0,
ulsch_input_buffer,
TBS_bytes,
&access_mode);
}
//Random traffic to be transmitted if there is no IP traffic available for this Tx opportunity
if (!IS_SOFTMODEM_NOS1 || !data_existing) {
//Use zeros for the header bytes in noS1 mode, in order to make sure that the LCID is not valid
//and block this traffic from being forwarded to the upper layers at the gNB
LOG_D(PHY, "Random data to be tranmsitted: \n");
//Give the first byte a dummy value (a value not corresponding to any valid LCID based on 38.321, Table 6.2.1-2)
//in order to distinguish the PHY random packets at the MAC layer of the gNB receiver from the normal packets that should
//have a valid LCID (nr_process_mac_pdu function)
ulsch_input_buffer[0] = 0x31;
for (i = 1; i < TBS_bytes; i++) {
ulsch_input_buffer[i] = (unsigned char) rand();
//printf(" input encoder a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
}
}
#ifdef DEBUG_MAC_PDU
LOG_D(PHY, "Is data existing ?: %d \n", data_existing);
LOG_I(PHY, "Printing MAC PDU to be encoded, TBS is: %d \n", TBS_bytes);
for (i = 0; i < TBS_bytes; i++) {
printf("%02x", ulsch_input_buffer[i]);
}
printf("\n");
#endif
// Config UL TX PDU
tx_req.slot = slot_tx;
tx_req.sfn = frame_tx;
// tx_req->tx_config // TbD
tx_req.number_of_pdus++;
tx_req.tx_request_body[j].pdu_length = TBS_bytes;
tx_req.tx_request_body[j].pdu_index = j;
tx_req.tx_request_body[j].pdu = ulsch_input_buffer;
}
}
fill_scheduled_response(&scheduled_response, NULL, ul_config_req, &tx_req, mod_id, cc_id, rx_frame, rx_slot, ul_info->thread_id);
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){
mac->if_module->scheduled_response(&scheduled_response);
}
}
}
}
return UE_CONNECTION_OK;
}
// PUSCH Msg3 scheduled by RAR UL grant according to 8.3 of TS 38.213
// Note: Msg3 tx in the uplink symbols of mixed slot
void nr_ue_msg3_scheduler(NR_UE_MAC_INST_t *mac,
frame_t current_frame,
sub_frame_t current_slot,
uint8_t Msg3_tda_id){
int delta = 0;
RA_config_t *ra = &mac->ra;
NR_BWP_Uplink_t *ubwp = mac->ULbwp[0];
int mu = ubwp->bwp_Common->genericParameters.subcarrierSpacing;
struct NR_PUSCH_TimeDomainResourceAllocationList *pusch_TimeDomainAllocationList = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
// k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1
// PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon
uint8_t k2 = *pusch_TimeDomainAllocationList->list.array[Msg3_tda_id]->k2;
switch (mu) {
case 0:
delta = 2;
break;
case 1:
delta = 3;
break;
case 2:
delta = 4;
break;
case 3:
delta = 6;
break;
}
ra->msg3_slot = (current_slot + k2 + delta) % nr_slots_per_frame[mu];
if (current_slot + k2 + delta > nr_slots_per_frame[mu])
ra->msg3_frame = (current_frame + 1) % 1024;
else
ra->msg3_frame = current_frame;
#ifdef DEBUG_MSG3
LOG_D(MAC, "[DEBUG_MSG3] current_slot %d k2 %d delta %d temp_slot %d msg3_frame %d msg3_slot %d \n", current_slot, k2, delta, current_slot + k2 + delta, ra->msg3_frame, ra->msg3_slot);
#endif
}
// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
// - todo:
// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config
void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t slotP, int thread_id) {
uint16_t format, format0, format1, ncs;
int is_nr_prach_slot;
prach_occasion_info_t *prach_occasion_info_p;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
RA_config_t *ra = &mac->ra;
//fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slotP);
fapi_nr_ul_config_request_t *ul_config = &mac->ul_config_request[0];
fapi_nr_ul_config_prach_pdu *prach_config_pdu;
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
fapi_nr_prach_config_t *prach_config = &cfg->prach_config;
nr_scheduled_response_t scheduled_response;
NR_ServingCellConfigCommon_t *scc = mac->scc;
NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
ra->RA_offset = 2; // to compensate the rx frame offset at the gNB
ra->generate_nr_prach = 0; // Reset flag for PRACH generation
if (is_nr_UL_slot(scc, slotP)) {
// WIP Need to get the proper selected ssb_idx
// Initial beam selection functionality is not available yet
uint8_t selected_gnb_ssb_idx = 0;
// Get any valid PRACH occasion in the current slot for the selected SSB index
is_nr_prach_slot = get_nr_prach_info_from_ssb_index(selected_gnb_ssb_idx,
(int)frameP,
(int)slotP,
&prach_occasion_info_p);
if (is_nr_prach_slot && ra->ra_state == RA_UE_IDLE) {
AssertFatal(NULL != prach_occasion_info_p,"PRACH Occasion Info not returned in a valid NR Prach Slot\n");
ra->generate_nr_prach = 1;
format = prach_occasion_info_p->format;
format0 = format & 0xff; // single PRACH format
format1 = (format >> 8) & 0xff; // dual PRACH format
ul_config->sfn = frameP;
ul_config->slot = slotP;
ul_config->ul_config_list[ul_config->number_pdus].pdu_type = FAPI_NR_UL_CONFIG_TYPE_PRACH;
prach_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].prach_config_pdu;
memset(prach_config_pdu, 0, sizeof(fapi_nr_ul_config_prach_pdu));
ul_config->number_pdus += 1;
ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig);
prach_config_pdu->phys_cell_id = *scc->physCellId;
prach_config_pdu->num_prach_ocas = 1;
prach_config_pdu->prach_slot = prach_occasion_info_p->slot;
prach_config_pdu->prach_start_symbol = prach_occasion_info_p->start_symbol;
prach_config_pdu->num_ra = prach_occasion_info_p->fdm;
prach_config_pdu->num_cs = ncs;
prach_config_pdu->root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index;
prach_config_pdu->restricted_set = prach_config->restricted_set_config;
prach_config_pdu->freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1;
LOG_D(MAC,"Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", frameP, prach_config_pdu->prach_slot, prach_config_pdu->prach_start_symbol, prach_config_pdu->num_ra);
// Search which SSB is mapped in the RO (among all the SSBs mapped to this RO)
for (prach_config_pdu->ssb_nb_in_ro=0; prach_config_pdu->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb; prach_config_pdu->ssb_nb_in_ro++) {
if (prach_occasion_info_p->mapped_ssb_idx[prach_config_pdu->ssb_nb_in_ro] == selected_gnb_ssb_idx)
break;
}
AssertFatal(prach_config_pdu->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb, "%u not found in the mapped SSBs to the PRACH occasion", selected_gnb_ssb_idx);
if (format1 != 0xff) {
switch(format0) { // dual PRACH format
case 0xa1:
prach_config_pdu->prach_format = 11;
break;
case 0xa2:
prach_config_pdu->prach_format = 12;
break;
case 0xa3:
prach_config_pdu->prach_format = 13;
break;
default:
AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
}
} else {
switch(format0) { // single PRACH format
case 0:
prach_config_pdu->prach_format = 0;
break;
case 1:
prach_config_pdu->prach_format = 1;
break;
case 2:
prach_config_pdu->prach_format = 2;
break;
case 3:
prach_config_pdu->prach_format = 3;
break;
case 0xa1:
prach_config_pdu->prach_format = 4;
break;
case 0xa2:
prach_config_pdu->prach_format = 5;
break;
case 0xa3:
prach_config_pdu->prach_format = 6;
break;
case 0xb1:
prach_config_pdu->prach_format = 7;
break;
case 0xb4:
prach_config_pdu->prach_format = 8;
break;
case 0xc0:
prach_config_pdu->prach_format = 9;
break;
case 0xc2:
prach_config_pdu->prach_format = 10;
break;
default:
AssertFatal(1 == 0, "Invalid PRACH format");
}
} // if format1
} // is_nr_prach_slot
fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, thread_id);
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
mac->if_module->scheduled_response(&scheduled_response);
} // if is_nr_UL_slot
}
/*
* This code contains all the functions needed to process all dci fields.
* These tables and functions are going to be called by function nr_ue_process_dci
*/
int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
uint16_t n_RB_ULBWP,
uint16_t n_RB_DLBWP,
uint16_t riv
){
/*
* TS 38.214 subclause 5.1.2.2 Resource allocation in frequency domain (downlink)
* when the scheduling grant is received with DCI format 1_0, then downlink resource allocation type 1 is used
*/
if(dlsch_config_pdu != NULL){
/*
* TS 38.214 subclause 5.1.2.2.1 Downlink resource allocation type 0
*/
/*
* TS 38.214 subclause 5.1.2.2.2 Downlink resource allocation type 1
*/
dlsch_config_pdu->number_rbs = NRRIV2BW(riv,n_RB_DLBWP);
dlsch_config_pdu->start_rb = NRRIV2PRBOFFSET(riv,n_RB_DLBWP);
// Sanity check in case a false or erroneous DCI is received
if ((dlsch_config_pdu->number_rbs < 1 ) || (dlsch_config_pdu->number_rbs > n_RB_DLBWP - dlsch_config_pdu->start_rb)) {
// DCI is invalid!
LOG_W(MAC, "Frequency domain assignment values are invalid! #RBs: %d, Start RB: %d, n_RB_DLBWP: %d \n", dlsch_config_pdu->number_rbs, dlsch_config_pdu->start_rb, n_RB_DLBWP);
return -1;
}
}
if(pusch_config_pdu != NULL){
/*
* TS 38.214 subclause 6.1.2.2 Resource allocation in frequency domain (uplink)
*/
/*
* TS 38.214 subclause 6.1.2.2.1 Uplink resource allocation type 0
*/
/*
* TS 38.214 subclause 6.1.2.2.2 Uplink resource allocation type 1
*/
pusch_config_pdu->rb_size = NRRIV2BW(riv,n_RB_ULBWP);
pusch_config_pdu->rb_start = NRRIV2PRBOFFSET(riv,n_RB_ULBWP);
// Sanity check in case a false or erroneous DCI is received
if ((pusch_config_pdu->rb_size < 1) || (pusch_config_pdu->rb_size > n_RB_ULBWP - pusch_config_pdu->rb_start)) {
// DCI is invalid!
LOG_W(MAC, "Frequency domain assignment values are invalid! #RBs: %d, Start RB: %d, n_RB_ULBWP: %d \n",pusch_config_pdu->rb_size, pusch_config_pdu->rb_start, n_RB_ULBWP);
return -1;
}
}
return 0;
}
int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac,
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
uint8_t time_domain_ind
){
int dmrs_typeA_pos = mac->scc->dmrs_TypeA_Position;
// uint8_t k_offset=0;
uint8_t sliv_S=0;
uint8_t sliv_L=0;
uint8_t table_5_1_2_1_1_2_time_dom_res_alloc_A[16][3]={ // for PDSCH from TS 38.214 subclause 5.1.2.1.1
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?12:11}, // row index 1
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?10:9}, // row index 2
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?9:8}, // row index 3
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?7:6}, // row index 4
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?5:4}, // row index 5
{0,(dmrs_typeA_pos == 0)?9:10,(dmrs_typeA_pos == 0)?4:4}, // row index 6
{0,(dmrs_typeA_pos == 0)?4:6, (dmrs_typeA_pos == 0)?4:4}, // row index 7
{0,5,7}, // row index 8
{0,5,2}, // row index 9
{0,9,2}, // row index 10
{0,12,2}, // row index 11
{0,1,13}, // row index 12
{0,1,6}, // row index 13
{0,2,4}, // row index 14
{0,4,7}, // row index 15
{0,8,4} // row index 16
};
/*uint8_t table_5_1_2_1_1_3_time_dom_res_alloc_A_extCP[16][3]={ // for PDSCH from TS 38.214 subclause 5.1.2.1.1
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?6:5}, // row index 1
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?10:9}, // row index 2
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?9:8}, // row index 3
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?7:6}, // row index 4
{0,(dmrs_typeA_pos == 0)?2:3, (dmrs_typeA_pos == 0)?5:4}, // row index 5
{0,(dmrs_typeA_pos == 0)?6:8, (dmrs_typeA_pos == 0)?4:2}, // row index 6
{0,(dmrs_typeA_pos == 0)?4:6, (dmrs_typeA_pos == 0)?4:4}, // row index 7
{0,5,6}, // row index 8
{0,5,2}, // row index 9
{0,9,2}, // row index 10
{0,10,2}, // row index 11
{0,1,11}, // row index 12
{0,1,6}, // row index 13
{0,2,4}, // row index 14
{0,4,6}, // row index 15
{0,8,4} // row index 16
};*/
/*uint8_t table_5_1_2_1_1_4_time_dom_res_alloc_B[16][3]={ // for PDSCH from TS 38.214 subclause 5.1.2.1.1
{0,2,2}, // row index 1
{0,4,2}, // row index 2
{0,6,2}, // row index 3
{0,8,2}, // row index 4
{0,10,2}, // row index 5
{1,2,2}, // row index 6
{1,4,2}, // row index 7
{0,2,4}, // row index 8
{0,4,4}, // row index 9
{0,6,4}, // row index 10
{0,8,4}, // row index 11
{0,10,4}, // row index 12
{0,2,7}, // row index 13
{0,(dmrs_typeA_pos == 0)?2:3,(dmrs_typeA_pos == 0)?12:11}, // row index 14
{1,2,4}, // row index 15
{0,0,0} // row index 16
};*/
/*uint8_t table_5_1_2_1_1_5_time_dom_res_alloc_C[16][3]={ // for PDSCH from TS 38.214 subclause 5.1.2.1.1
{0,2,2}, // row index 1
{0,4,2}, // row index 2
{0,6,2}, // row index 3
{0,8,2}, // row index 4
{0,10,2}, // row index 5
{0,0,0}, // row index 6
{0,0,0}, // row index 7
{0,2,4}, // row index 8
{0,4,4}, // row index 9
{0,6,4}, // row index 10
{0,8,4}, // row index 11
{0,10,4}, // row index 12
{0,2,7}, // row index 13
{0,(dmrs_typeA_pos == 0)?2:3,(dmrs_typeA_pos == 0)?12:11}, // row index 14
{0,0,6}, // row index 15
{0,2,6} // row index 16
};*/
uint8_t mu_pusch = 1;
// definition table j Table 6.1.2.1.1-4
uint8_t j = (mu_pusch==3)?3:(mu_pusch==2)?2:1;
uint8_t table_6_1_2_1_1_2_time_dom_res_alloc_A[16][3]={ // for PUSCH from TS 38.214 subclause 6.1.2.1.1
{j, 0,14}, // row index 1
{j, 0,12}, // row index 2
{j, 0,10}, // row index 3
{j, 2,10}, // row index 4
{j, 4,10}, // row index 5
{j, 4,8}, // row index 6
{j, 4,6}, // row index 7
{j+1,0,14}, // row index 8
{j+1,0,12}, // row index 9
{j+1,0,10}, // row index 10
{j+2,0,14}, // row index 11
{j+2,0,12}, // row index 12
{j+2,0,10}, // row index 13
{j, 8,6}, // row index 14
{j+3,0,14}, // row index 15
{j+3,0,10} // row index 16
};
/*uint8_t table_6_1_2_1_1_3_time_dom_res_alloc_A_extCP[16][3]={ // for PUSCH from TS 38.214 subclause 6.1.2.1.1
{j, 0,8}, // row index 1
{j, 0,12}, // row index 2
{j, 0,10}, // row index 3
{j, 2,10}, // row index 4
{j, 4,4}, // row index 5
{j, 4,8}, // row index 6
{j, 4,6}, // row index 7
{j+1,0,8}, // row index 8
{j+1,0,12}, // row index 9
{j+1,0,10}, // row index 10
{j+2,0,6}, // row index 11
{j+2,0,12}, // row index 12
{j+2,0,10}, // row index 13
{j, 8,4}, // row index 14
{j+3,0,8}, // row index 15
{j+3,0,10} // row index 16
};*/
/*
* TS 38.214 subclause 5.1.2.1 Resource allocation in time domain (downlink)
*/
if(dlsch_config_pdu != NULL){
NR_PDSCH_TimeDomainResourceAllocationList_t *pdsch_TimeDomainAllocationList = NULL;
if (mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList)
pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->pdsch_TimeDomainAllocationList->choice.setup;
else if (mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList)
pdsch_TimeDomainAllocationList = mac->DLbwp[0]->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList;
if (pdsch_TimeDomainAllocationList) {
if (time_domain_ind >= pdsch_TimeDomainAllocationList->list.count) {
LOG_E(MAC, "time_domain_ind %d >= pdsch->TimeDomainAllocationList->list.count %d\n",
time_domain_ind, pdsch_TimeDomainAllocationList->list.count);
dlsch_config_pdu->start_symbol = 0;
dlsch_config_pdu->number_symbols = 0;
return -1;
}
int startSymbolAndLength = pdsch_TimeDomainAllocationList->list.array[time_domain_ind]->startSymbolAndLength;
int S,L;
SLIV2SL(startSymbolAndLength,&S,&L);
dlsch_config_pdu->start_symbol=S;
dlsch_config_pdu->number_symbols=L;
}
else {// Default configuration from tables
// k_offset = table_5_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][0];
sliv_S = table_5_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][1];
sliv_L = table_5_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][2];
// k_offset = table_5_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][0];
// sliv_S = table_5_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][1];
// sliv_L = table_5_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][2];
// k_offset = table_5_1_2_1_1_4_time_dom_res_alloc_B[nr_pdci_info_extracted->time_dom_resource_assignment][0];
// sliv_S = table_5_1_2_1_1_4_time_dom_res_alloc_B[nr_pdci_info_extracted->time_dom_resource_assignment][1];
// sliv_L = table_5_1_2_1_1_4_time_dom_res_alloc_B[nr_pdci_info_extracted->time_dom_resource_assignment][2];
// k_offset = table_5_1_2_1_1_5_time_dom_res_alloc_C[nr_pdci_info_extracted->time_dom_resource_assignment][0];
// sliv_S = table_5_1_2_1_1_5_time_dom_res_alloc_C[nr_pdci_info_extracted->time_dom_resource_assignment][1];
// sliv_L = table_5_1_2_1_1_5_time_dom_res_alloc_C[nr_pdci_info_extracted->time_dom_resource_assignment][2];
dlsch_config_pdu->number_symbols = sliv_L;
dlsch_config_pdu->start_symbol = sliv_S;
}
} /*
* TS 38.214 subclause 6.1.2.1 Resource allocation in time domain (uplink)
*/
if(pusch_config_pdu != NULL){
NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL;
if (mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList) {
pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList->choice.setup;
}
else if (mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) {
pusch_TimeDomainAllocationList = mac->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
}
if (pusch_TimeDomainAllocationList) {
if (time_domain_ind >= pusch_TimeDomainAllocationList->list.count) {
LOG_E(MAC, "time_domain_ind %d >= pusch->TimeDomainAllocationList->list.count %d\n",
time_domain_ind, pusch_TimeDomainAllocationList->list.count);
pusch_config_pdu->start_symbol_index=0;
pusch_config_pdu->nr_of_symbols=0;
return -1;
}
int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[time_domain_ind]->startSymbolAndLength;
int S,L;
SLIV2SL(startSymbolAndLength,&S,&L);
pusch_config_pdu->start_symbol_index=S;
pusch_config_pdu->nr_of_symbols=L;
}
else {
// k_offset = table_6_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][0];
sliv_S = table_6_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][1];
sliv_L = table_6_1_2_1_1_2_time_dom_res_alloc_A[time_domain_ind-1][2];
// k_offset = table_6_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][0];
// sliv_S = table_6_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][1];
// sliv_L = table_6_1_2_1_1_3_time_dom_res_alloc_A_extCP[nr_pdci_info_extracted->time_dom_resource_assignment][2];
pusch_config_pdu->nr_of_symbols = sliv_L;
pusch_config_pdu->start_symbol_index = sliv_S;
}
}
return 0;
}
int nr_ue_process_dci_indication_pdu(module_id_t module_id,int cc_id, int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci) {
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
LOG_D(MAC,"Received dci indication (rnti %x,dci format %d,n_CCE %d,payloadSize %d,payload %llx)\n",
dci->rnti,dci->dci_format,dci->n_CCE,dci->payloadSize,*(unsigned long long*)dci->payloadBits);
int dci_format = nr_extract_dci_info(mac,dci->dci_format,dci->payloadSize,dci->rnti,(uint64_t *)dci->payloadBits,def_dci_pdu_rel15);
return (nr_ue_process_dci(module_id, cc_id, gNB_index, frame, slot, def_dci_pdu_rel15, dci->rnti, dci_format));
}
int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, frame_t frame, int slot, dci_pdu_rel15_t *dci, uint16_t rnti, uint32_t dci_format){
int mu = 0;
long k2 = 0;
int pucch_res_set_cnt = 0, valid = 0;
uint16_t frame_tx = 0, slot_tx = 0;
bool valid_ptrs_setup = 0;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
RA_config_t *ra = &mac->ra;
NR_BWP_Id_t bwp_id = mac->UL_BWP_Id;
fapi_nr_dl_config_request_t *dl_config = &mac->dl_config_request;
fapi_nr_ul_config_request_t *ul_config = NULL;
//const uint16_t n_RB_DLBWP = dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.N_RB_BWP; //make sure this has been set
AssertFatal(mac->DLbwp[0]!=NULL,"DLbwp[0] should not be zero here!\n");
AssertFatal(mac->ULbwp[0]!=NULL,"DLbwp[0] should not be zero here!\n");
const uint16_t n_RB_DLBWP = (ra->ra_state == WAIT_RAR) ? NRRIV2BW(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE) : NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
const uint16_t n_RB_ULBWP = NRRIV2BW(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
LOG_D(MAC,"nr_ue_process_dci at MAC layer with dci_format=%d (DL BWP %d, UL BWP %d)\n",dci_format,n_RB_DLBWP,n_RB_ULBWP);
NR_PDSCH_Config_t *pdsch_config=mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup;
NR_PUSCH_Config_t *pusch_config=mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
switch(dci_format){
case NR_UL_DCI_FORMAT_0_0:
/*
* with CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI
* 0 IDENTIFIER_DCI_FORMATS:
* 10 FREQ_DOM_RESOURCE_ASSIGNMENT_UL: PUSCH hopping with resource allocation type 1 not considered
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 6.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 17 FREQ_HOPPING_FLAG: 0 bit if only resource allocation type 0
* 24 MCS:
* 25 NDI:
* 26 RV:
* 27 HARQ_PROCESS_NUMBER:
* 32 TPC_PUSCH:
* 49 PADDING_NR_DCI: (Note 2) If DCI format 0_0 is monitored in common search space
* 50 SUL_IND_0_0:
*/
// Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// where K2 is the offset between the slot in which UL DCI is received and the slot
// in which ULSCH should be scheduled. K2 is configured in RRC configuration.
// Get the numerology to calculate the Tx frame and slot
mu = mac->ULbwp[0]->bwp_Common->genericParameters.subcarrierSpacing;
// Get slot offset K2 which will be used to calculate TX slot
k2 = get_k2(mac, dci->time_domain_assignment.val);
if (k2 < 0) // This can happen when a false DCI is received
return -1;
// Calculate TX slot and frame
slot_tx = (slot + k2) % nr_slots_per_frame[mu];
frame_tx = ((slot + k2) > nr_slots_per_frame[mu]) ? (frame + 1) % 1024 : frame;
// Get UL config request corresponding slot_tx
ul_config = get_ul_config_request(mac, slot_tx);
//AssertFatal(ul_config != NULL, "nr_ue_process_dci(): ul_config is NULL\n");
if (!ul_config) {
LOG_W(MAC, "nr_ue_process_dci(): ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!\n",frame,slot);
return -1;
}
ul_config->ul_config_list[ul_config->number_pdus].pdu_type = FAPI_NR_UL_CONFIG_TYPE_PUSCH;
ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu.rnti = rnti;
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu_0_0 = &ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu;
/* IDENTIFIER_DCI_FORMATS */
/* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_0,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val) < 0)
return -1;
/* TIME_DOM_RESOURCE_ASSIGNMENT */
if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_0,NULL,dci->time_domain_assignment.val) < 0)
return -1;
LOG_D(MAC, "In %s: received UL grant (rb_start %d, rb_size %d, start_symbol_index %d, nr_of_symbols %d) \n",
__FUNCTION__,
pusch_config_pdu_0_0->rb_start,
pusch_config_pdu_0_0->rb_size,
pusch_config_pdu_0_0->start_symbol_index,
pusch_config_pdu_0_0->nr_of_symbols);
if (ra->RA_active && mac->crnti){
nr_ra_succeeded(module_id, frame, slot);
}
/* FREQ_HOPPING_FLAG */
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
pusch_config_pdu_0_0->frequency_hopping = dci->frequency_hopping_flag.val;
/* MCS */
pusch_config_pdu_0_0->mcs_index = dci->mcs;
/* MCS TABLE */
if (mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
pusch_config_pdu_0_0->transform_precoding = 1;
else
pusch_config_pdu_0_0->transform_precoding = 0;
if (pusch_config_pdu_0_0->transform_precoding == transform_precoder_disabled)
pusch_config_pdu_0_0->mcs_table = get_pusch_mcs_table(pusch_config->mcs_Table, 0,
dci_format, NR_RNTI_TC, NR_SearchSpace__searchSpaceType_PR_common, false);
else
pusch_config_pdu_0_0->mcs_table = get_pusch_mcs_table(pusch_config->mcs_TableTransformPrecoder, 1,
dci_format, NR_RNTI_TC, NR_SearchSpace__searchSpaceType_PR_common, false);
pusch_config_pdu_0_0->target_code_rate = nr_get_code_rate_ul(pusch_config_pdu_0_0->mcs_index, pusch_config_pdu_0_0->mcs_table);
pusch_config_pdu_0_0->qam_mod_order = nr_get_Qm_ul(pusch_config_pdu_0_0->mcs_index, pusch_config_pdu_0_0->mcs_table);
if (pusch_config_pdu_0_0->target_code_rate == 0 || pusch_config_pdu_0_0->qam_mod_order == 0) {
LOG_W(MAC, "Invalid code rate or Mod order, likely due to unexpected UL DCI. Ignoring DCI! \n");
return -1;
}
/* NDI */
pusch_config_pdu_0_0->pusch_data.new_data_indicator = dci->ndi;
/* RV */
pusch_config_pdu_0_0->pusch_data.rv_index = dci->rv;
/* HARQ_PROCESS_NUMBER */
pusch_config_pdu_0_0->pusch_data.harq_process_id = dci->harq_pid;
/* TPC_PUSCH */
// according to TS 38.213 Table Table 7.1.1-1
if (dci->tpc == 0) {
pusch_config_pdu_0_0->absolute_delta_PUSCH = -4;
}
if (dci->tpc == 1) {
pusch_config_pdu_0_0->absolute_delta_PUSCH = -1;
}
if (dci->tpc == 2) {
pusch_config_pdu_0_0->absolute_delta_PUSCH = 1;
}
if (dci->tpc == 3) {
pusch_config_pdu_0_0->absolute_delta_PUSCH = 4;
}
/* SUL_IND_0_0 */ // To be implemented, FIXME!!!
ul_config->slot = slot_tx;
ul_config->sfn = frame_tx;
ul_config->number_pdus = ul_config->number_pdus + 1;
LOG_D(MAC, "nr_ue_process_dci(): Calculated frame and slot for pusch Tx: %d.%d, number of pdus %d\n", ul_config->sfn, ul_config->slot, ul_config->number_pdus);
break;
case NR_UL_DCI_FORMAT_0_1:
/*
* with CRC scrambled by C-RNTI or CS-RNTI or SP-CSI-RNTI or new-RNTI
* 0 IDENTIFIER_DCI_FORMATS:
* 1 CARRIER_IND
* 2 SUL_IND_0_1
* 7 BANDWIDTH_PART_IND
* 10 FREQ_DOM_RESOURCE_ASSIGNMENT_UL: PUSCH hopping with resource allocation type 1 not considered
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 6.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 17 FREQ_HOPPING_FLAG: 0 bit if only resource allocation type 0
* 24 MCS:
* 25 NDI:
* 26 RV:
* 27 HARQ_PROCESS_NUMBER:
* 29 FIRST_DAI
* 30 SECOND_DAI
* 32 TPC_PUSCH:
* 36 SRS_RESOURCE_IND:
* 37 PRECOD_NBR_LAYERS:
* 38 ANTENNA_PORTS:
* 40 SRS_REQUEST:
* 42 CSI_REQUEST:
* 43 CBGTI
* 45 PTRS_DMRS
* 46 BETA_OFFSET_IND
* 47 DMRS_SEQ_INI
* 48 UL_SCH_IND
* 49 PADDING_NR_DCI: (Note 2) If DCI format 0_0 is monitored in common search space
*/
// Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// where K2 is the offset between the slot in which UL DCI is received and the slot
// in which ULSCH should be scheduled. K2 is configured in RRC configuration.
// Get the numerology to calculate the Tx frame and slot
mu = mac->ULbwp[0]->bwp_Common->genericParameters.subcarrierSpacing;
// Get slot offset K2 which will be used to calculate TX slot
k2 = get_k2(mac, dci->time_domain_assignment.val);
if (k2 < 0) // This can happen when a false DCI is received
return -1;
// Calculate TX slot and frame
slot_tx = (slot + k2) % nr_slots_per_frame[mu];
frame_tx = ((slot + k2) > nr_slots_per_frame[mu]) ? (frame + 1) % 1024 : frame;
// Get UL config request corresponding slot_tx
ul_config = get_ul_config_request(mac, slot_tx);
//AssertFatal(ul_config != NULL, "nr_ue_process_dci(): ul_config is NULL\n");
if (!ul_config) {
LOG_W(MAC, "nr_ue_process_dci(): ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!\n",frame,slot);
return -1;
}
ul_config->ul_config_list[ul_config->number_pdus].pdu_type = FAPI_NR_UL_CONFIG_TYPE_PUSCH;
ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu.rnti = rnti;
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu_0_1 = &ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu;
/* IDENTIFIER_DCI_FORMATS */
/* CARRIER_IND */
/* SUL_IND_0_1 */
/* BANDWIDTH_PART_IND */
config_bwp_ue(mac, &dci->bwp_indicator.val, &dci_format);
//pusch_config_pdu_0_1->bandwidth_part_ind = dci->bwp_indicator.val;
/* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_1,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val) < 0)
return -1;
/* TIME_DOM_RESOURCE_ASSIGNMENT */
if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_1,NULL,dci->time_domain_assignment.val) < 0)
return -1;
LOG_D(MAC, "In %s: received UL grant (rb_start %d, rb_size %d, start_symbol_index %d, nr_of_symbols %d) \n",
__FUNCTION__,
pusch_config_pdu_0_1->rb_start,
pusch_config_pdu_0_1->rb_size,
pusch_config_pdu_0_1->start_symbol_index,
pusch_config_pdu_0_1->nr_of_symbols);
if (ra->RA_active && mac->crnti){
nr_ra_succeeded(module_id, frame, slot);
}
/* FREQ_HOPPING_FLAG */
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
pusch_config_pdu_0_1->frequency_hopping = dci->frequency_hopping_flag.val;
/* MCS */
pusch_config_pdu_0_1->mcs_index = dci->mcs;
/* MCS TABLE */
if (pusch_config->transformPrecoder == NULL) {
if (mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
pusch_config_pdu_0_1->transform_precoding = 1;
else
pusch_config_pdu_0_1->transform_precoding = 0;
}
else
pusch_config_pdu_0_1->transform_precoding = *pusch_config->transformPrecoder;
if (pusch_config_pdu_0_1->transform_precoding == transform_precoder_disabled)
pusch_config_pdu_0_1->mcs_table = get_pusch_mcs_table(pusch_config->mcs_Table, 0,
dci_format, NR_RNTI_C, NR_SearchSpace__searchSpaceType_PR_ue_Specific, false);
else
pusch_config_pdu_0_1->mcs_table = get_pusch_mcs_table(pusch_config->mcs_TableTransformPrecoder, 1,
dci_format, NR_RNTI_C, NR_SearchSpace__searchSpaceType_PR_ue_Specific, false);
pusch_config_pdu_0_1->target_code_rate = nr_get_code_rate_ul(pusch_config_pdu_0_1->mcs_index, pusch_config_pdu_0_1->mcs_table);
pusch_config_pdu_0_1->qam_mod_order = nr_get_Qm_ul(pusch_config_pdu_0_1->mcs_index, pusch_config_pdu_0_1->mcs_table);
if (pusch_config_pdu_0_1->target_code_rate == 0 || pusch_config_pdu_0_1->qam_mod_order == 0) {
LOG_W(MAC, "Invalid code rate or Mod order, likely due to unexpected UL DCI. Ignoring DCI! \n");
return -1;
}
/* NDI */
pusch_config_pdu_0_1->pusch_data.new_data_indicator = dci->ndi;
/* RV */
pusch_config_pdu_0_1->pusch_data.rv_index = dci->rv;
/* HARQ_PROCESS_NUMBER */
pusch_config_pdu_0_1->pusch_data.harq_process_id = dci->harq_pid;
/* FIRST_DAI */ //To be implemented, FIXME!!!
/* SECOND_DAI */ //To be implemented, FIXME!!!
/* TPC_PUSCH */
// according to TS 38.213 Table Table 7.1.1-1
if (dci->tpc == 0) {
pusch_config_pdu_0_1->absolute_delta_PUSCH = -4;
}
if (dci->tpc == 1) {
pusch_config_pdu_0_1->absolute_delta_PUSCH = -1;
}
if (dci->tpc == 2) {
pusch_config_pdu_0_1->absolute_delta_PUSCH = 1;
}
if (dci->tpc == 3) {
pusch_config_pdu_0_1->absolute_delta_PUSCH = 4;
}
/* SRS_RESOURCE_IND */
//FIXME!!
/* PRECOD_NBR_LAYERS */
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.tx_config == tx_config_nonCodebook));
// 0 bits if the higher layer parameter txConfig = nonCodeBook
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.tx_config == tx_config_codebook)){
uint8_t n_antenna_port = 0; //FIXME!!!
if (n_antenna_port == 1); // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits
if (n_antenna_port == 4){ // 4 antenna port and the higher layer parameter txConfig = codebook
// Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled)
&& ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 2) ||
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 3) ||
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 4))){
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_partialAndNonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_nonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5];
}
}
// Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1
if (((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled)
|| (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled))
&& (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 1)){
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_partialAndNonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_nonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11];
}
}
}
if (n_antenna_port == 4){ // 2 antenna port and the higher layer parameter txConfig = codebook
// Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled)
&& (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 2)){
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_nonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15];
}
}
// Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1
if (((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled)
|| (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled))
&& (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 1)){
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17];
}
if (mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.codebook_subset == codebook_subset_nonCoherent){
pusch_config_pdu_0_1->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18];
pusch_config_pdu_0_1->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19];
}
}
}
}
/* ANTENNA_PORTS */
uint8_t rank=0; // We need to initialize rank FIXME!!!
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-6
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = dci->antenna_ports.val; //TBC
}
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-7
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = (dci->antenna_ports.val > 3)?(dci->antenna_ports.val-4):(dci->antenna_ports.val); //TBC
//pusch_config_pdu_0_1->n_front_load_symb = (dci->antenna_ports > 3)?2:1; //FIXME
}
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-8/9/10/11
if (rank == 1){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
pusch_config_pdu_0_1->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val); //TBC
}
if (rank == 2){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?0:2):0;
//pusch_config_pdu_0_1->dmrs_ports[1] = (dci->antenna_ports > 1)?(dci->antenna_ports > 2 ?2:3):1;
}
if (rank == 3){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = 0;
//pusch_config_pdu_0_1->dmrs_ports[1] = 1;
//pusch_config_pdu_0_1->dmrs_ports[2] = 2;
}
if (rank == 4){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = 0;
//pusch_config_pdu_0_1->dmrs_ports[1] = 1;
//pusch_config_pdu_0_1->dmrs_ports[2] = 2;
//pusch_config_pdu_0_1->dmrs_ports[3] = 3;
}
}
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-12/13/14/15
if (rank == 1){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
pusch_config_pdu_0_1->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val; //TBC
//pusch_config_pdu_0_1->n_front_load_symb = (dci->antenna_ports.val > 6)?2:1; //FIXME
}
if (rank == 2){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_13[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_13[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; // FIXME
}
if (rank == 3){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_14[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_14[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->dmrs_ports[2] = table_7_3_1_1_2_14[dci->antenna_ports.val][3];
//pusch_config_pdu_0_1->n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
}
if (rank == 4){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_15[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_15[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->dmrs_ports[2] = table_7_3_1_1_2_15[dci->antenna_ports.val][3];
//pusch_config_pdu_0_1->dmrs_ports[3] = table_7_3_1_1_2_15[dci->antenna_ports.val][4];
//pusch_config_pdu_0_1->n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
}
}
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 2) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-16/17/18/19
if (rank == 1){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val > 5)?3:2):1; //TBC
pusch_config_pdu_0_1->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val; //TBC
}
if (rank == 2){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?((dci->antenna_ports.val > 2)?3:2):1; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_17[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_17[dci->antenna_ports.val][2];
}
if (rank == 3){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?3:2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_18[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_18[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->dmrs_ports[2] = table_7_3_1_1_2_18[dci->antenna_ports.val][3];
}
if (rank == 4){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = dci->antenna_ports.val + 2; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = 0;
//pusch_config_pdu_0_1->dmrs_ports[1] = 1;
//pusch_config_pdu_0_1->dmrs_ports[2] = 2;
//pusch_config_pdu_0_1->dmrs_ports[3] = 3;
}
}
if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 2) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-20/21/22/23
if (rank == 1){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_20[dci->antenna_ports.val][0]; //TBC
pusch_config_pdu_0_1->dmrs_ports = table_7_3_1_1_2_20[dci->antenna_ports.val][1]; //TBC
//pusch_config_pdu_0_1->n_front_load_symb = table_7_3_1_1_2_20[dci->antenna_ports.val][2]; //FIXME
}
if (rank == 2){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_21[dci->antenna_ports.val][0]; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_21[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_21[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME
}
if (rank == 3){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_22[dci->antenna_ports.val][0]; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_22[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_22[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->dmrs_ports[2] = table_7_3_1_1_2_22[dci->antenna_ports.val][3];
//pusch_config_pdu_0_1->n_front_load_symb = table_7_3_1_1_2_22[dci->antenna_ports.val][4]; //FIXME
}
if (rank == 4){
pusch_config_pdu_0_1->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_23[dci->antenna_ports.val][0]; //TBC
pusch_config_pdu_0_1->dmrs_ports = 0; //FIXME
//pusch_config_pdu_0_1->dmrs_ports[0] = table_7_3_1_1_2_23[dci->antenna_ports.val][1];
//pusch_config_pdu_0_1->dmrs_ports[1] = table_7_3_1_1_2_23[dci->antenna_ports.val][2];
//pusch_config_pdu_0_1->dmrs_ports[2] = table_7_3_1_1_2_23[dci->antenna_ports.val][3];
//pusch_config_pdu_0_1->dmrs_ports[3] = table_7_3_1_1_2_23[dci->antenna_ports.val][4];
//pusch_config_pdu_0_1->n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME
}
}
/* SRS_REQUEST */
// if SUL is supported in the cell, there is an additional bit in thsi field and the value of this bit represents table 7.1.1.1-1 TS 38.212 FIXME!!!
//pusch_config_pdu_0_1->srs_config.aperiodicSRS_ResourceTrigger = (dci->srs_request.val & 0x11); // as per Table 7.3.1.1.2-24 TS 38.212 //FIXME
/* CSI_REQUEST */
//pusch_config_pdu_0_1->csi_reportTriggerSize = dci->csi_request.val; //FIXME
/* CBGTI */
//pusch_config_pdu_0_1->maxCodeBlockGroupsPerTransportBlock = dci->cbgti.val; //FIXME
/* PTRS_DMRS */
if (((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_disabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.dmrs_ul_for_pusch_mapping_type_a.ptrs_uplink_config == 0)) ||
((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.transform_precoder == transform_precoder_enabled) &&
(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.max_rank == 1))){
} else {
//pusch_config_pdu_0_1->ptrs_dmrs_association_port = dci->ptrs_dmrs_association.val; //FIXME
}
/* BETA_OFFSET_IND */
// Table 9.3-3 in [5, TS 38.213]
//pusch_config_pdu_0_1->beta_offset_ind = dci->beta_offset_indicator.val; //FIXME
/* DMRS_SEQ_INI */
// FIXME!!
/* UL_SCH_IND */
// A value of "1" indicates UL-SCH shall be transmitted on the PUSCH and
// a value of "0" indicates UL-SCH shall not be transmitted on the PUSCH
ul_config->slot = slot_tx;
ul_config->sfn = frame_tx;
ul_config->number_pdus = ul_config->number_pdus + 1;
LOG_D(MAC, "nr_ue_process_dci(): Calculated frame and slot for pusch Tx: %d.%d, number of pdus %d\n", ul_config->sfn, ul_config->slot, ul_config->number_pdus);
break;
case NR_DL_DCI_FORMAT_1_0:
/*
* with CRC scrambled by C-RNTI or CS-RNTI or new-RNTI
* 0 IDENTIFIER_DCI_FORMATS:
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 24 MCS:
* 25 NDI:
* 26 RV:
* 27 HARQ_PROCESS_NUMBER:
* 28 DAI_: For format1_1: 4 if more than one serving cell are configured in the DL and the higher layer parameter HARQ-ACK-codebook=dynamic, where the 2 MSB bits are the counter DAI and the 2 LSB bits are the total DAI
* 33 TPC_PUCCH:
* 34 PUCCH_RESOURCE_IND:
* 35 PDSCH_TO_HARQ_FEEDBACK_TIME_IND:
* 55 RESERVED_NR_DCI
* with CRC scrambled by P-RNTI
* 8 SHORT_MESSAGE_IND
* 9 SHORT_MESSAGES
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 24 MCS:
* 31 TB_SCALING
* 55 RESERVED_NR_DCI
* with CRC scrambled by SI-RNTI
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 24 MCS:
* 26 RV:
* 55 RESERVED_NR_DCI
* with CRC scrambled by RA-RNTI
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 24 MCS:
* 31 TB_SCALING
* 55 RESERVED_NR_DCI
* with CRC scrambled by TC-RNTI
* 0 IDENTIFIER_DCI_FORMATS:
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 24 MCS:
* 25 NDI:
* 26 RV:
* 27 HARQ_PROCESS_NUMBER:
* 28 DAI_: For format1_1: 4 if more than one serving cell are configured in the DL and the higher layer parameter HARQ-ACK-codebook=dynamic, where the 2 MSB bits are the counter DAI and the 2 LSB bits are the total DAI
* 33 TPC_PUCCH:
*/
dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.rnti = rnti;
//fapi_nr_dl_config_dlsch_pdu_rel15_t dlsch_config_pdu_1_0 = dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.dlsch_config_rel15;
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu_1_0 = &dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.dlsch_config_rel15;
dlsch_config_pdu_1_0->BWPSize = NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
dlsch_config_pdu_1_0->BWPStart = NRRIV2PRBOFFSET(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
dlsch_config_pdu_1_0->SubcarrierSpacing = mac->DLbwp[0]->bwp_Common->genericParameters.subcarrierSpacing;
/* IDENTIFIER_DCI_FORMATS */
/* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_0,0,n_RB_DLBWP,dci->frequency_domain_assignment.val) < 0)
return -1;
/* TIME_DOM_RESOURCE_ASSIGNMENT */
if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_0,dci->time_domain_assignment.val) < 0)
return -1;
/* dmrs symbol positions*/
dlsch_config_pdu_1_0->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
mac->scc->dmrs_TypeA_Position,
dlsch_config_pdu_1_0->number_symbols);
dlsch_config_pdu_1_0->dmrsConfigType = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1;
/* number of DM-RS CDM groups without data according to subclause 5.1.6.2 of 3GPP TS 38.214 version 15.9.0 Release 15 */
if (dlsch_config_pdu_1_0->number_symbols == 2)
dlsch_config_pdu_1_0->n_dmrs_cdm_groups = 1;
else
dlsch_config_pdu_1_0->n_dmrs_cdm_groups = 2;
/* VRB_TO_PRB_MAPPING */
dlsch_config_pdu_1_0->vrb_to_prb_mapping = (dci->vrb_to_prb_mapping.val == 0) ? vrb_to_prb_mapping_non_interleaved:vrb_to_prb_mapping_interleaved;
/* MCS TABLE INDEX */
dlsch_config_pdu_1_0->mcs_table = (pdsch_config->mcs_Table) ? (*pdsch_config->mcs_Table + 1) : 0;
/* MCS */
dlsch_config_pdu_1_0->mcs = dci->mcs;
// Basic sanity check for MCS value to check for a false or erroneous DCI
if (dlsch_config_pdu_1_0->mcs > 28) {
LOG_W(MAC, "MCS value % d out of bounds! Possibly due to false DCI. Ignoring DCI!!\n", dlsch_config_pdu_1_0->mcs);
return -1;
}
/* NDI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/
dlsch_config_pdu_1_0->ndi = dci->ndi;
/* RV (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/
dlsch_config_pdu_1_0->rv = dci->rv;
/* HARQ_PROCESS_NUMBER (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/
dlsch_config_pdu_1_0->harq_process_nbr = dci->harq_pid;
/* DAI (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/
dlsch_config_pdu_1_0->dai = dci->dai[0].val;
/* TB_SCALING (only if CRC scrambled by P-RNTI or RA-RNTI) */
// according to TS 38.214 Table 5.1.3.2-3
if (dci->tb_scaling == 0) dlsch_config_pdu_1_0->scaling_factor_S = 1;
if (dci->tb_scaling == 1) dlsch_config_pdu_1_0->scaling_factor_S = 0.5;
if (dci->tb_scaling == 2) dlsch_config_pdu_1_0->scaling_factor_S = 0.25;
if (dci->tb_scaling == 3) dlsch_config_pdu_1_0->scaling_factor_S = 0; // value not defined in table
/* TPC_PUCCH (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI or TC-RNTI)*/
// according to TS 38.213 Table 7.2.1-1
if (dci->tpc == 0) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = -1;
if (dci->tpc == 1) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = 0;
if (dci->tpc == 2) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = 1;
if (dci->tpc == 3) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = 3;
/* PUCCH_RESOURCE_IND (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI)*/
//if (dci->pucch_resource_indicator == 0) dlsch_config_pdu_1_0->pucch_resource_id = 1; //pucch-ResourceId obtained from the 1st value of resourceList FIXME!!!
//if (dci->pucch_resource_indicator == 1) dlsch_config_pdu_1_0->pucch_resource_id = 2; //pucch-ResourceId obtained from the 2nd value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 2) dlsch_config_pdu_1_0->pucch_resource_id = 3; //pucch-ResourceId obtained from the 3rd value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 3) dlsch_config_pdu_1_0->pucch_resource_id = 4; //pucch-ResourceId obtained from the 4th value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 4) dlsch_config_pdu_1_0->pucch_resource_id = 5; //pucch-ResourceId obtained from the 5th value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 5) dlsch_config_pdu_1_0->pucch_resource_id = 6; //pucch-ResourceId obtained from the 6th value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 6) dlsch_config_pdu_1_0->pucch_resource_id = 7; //pucch-ResourceId obtained from the 7th value of resourceList FIXME!!
//if (dci->pucch_resource_indicator == 7) dlsch_config_pdu_1_0->pucch_resource_id = 8; //pucch-ResourceId obtained from the 8th value of resourceList FIXME!!
dlsch_config_pdu_1_0->pucch_resource_id = dci->pucch_resource_indicator;
// Sanity check for pucch_resource_indicator value received to check for false DCI.
valid = 0;
pucch_res_set_cnt = mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.count;
for (int id = 0; id < pucch_res_set_cnt; id++) {
if (dlsch_config_pdu_1_0->pucch_resource_id < mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.array[id]->resourceList.list.count) {
valid = 1;
break;
}
}
if (!valid) {
LOG_W(MAC, "pucch_resource_indicator value %d is out of bounds. Possibly due to false DCI. Ignoring DCI!\n", dlsch_config_pdu_1_0->pucch_resource_id);
return -1;
}
/* PDSCH_TO_HARQ_FEEDBACK_TIME_IND (only if CRC scrambled by C-RNTI or CS-RNTI or new-RNTI)*/
dlsch_config_pdu_1_0->pdsch_to_harq_feedback_time_ind = dci->pdsch_to_harq_feedback_timing_indicator.val;
LOG_D(MAC,"(nr_ue_procedures.c) rnti = %x dl_config->number_pdus = %d\n",
dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.rnti,
dl_config->number_pdus);
LOG_D(MAC,"(nr_ue_procedures.c) frequency_domain_resource_assignment=%d \t number_rbs=%d \t start_rb=%d\n",
dci->frequency_domain_assignment.val,
dlsch_config_pdu_1_0->number_rbs,
dlsch_config_pdu_1_0->start_rb);
LOG_D(MAC,"(nr_ue_procedures.c) time_domain_resource_assignment=%d \t number_symbols=%d \t start_symbol=%d\n",
dci->time_domain_assignment.val,
dlsch_config_pdu_1_0->number_symbols,
dlsch_config_pdu_1_0->start_symbol);
LOG_D(MAC,"(nr_ue_procedures.c) vrb_to_prb_mapping=%d \n>>> mcs=%d\n>>> ndi=%d\n>>> rv=%d\n>>> harq_process_nbr=%d\n>>> dai=%d\n>>> scaling_factor_S=%f\n>>> tpc_pucch=%d\n>>> pucch_res_ind=%d\n>>> pdsch_to_harq_feedback_time_ind=%d\n",
dlsch_config_pdu_1_0->vrb_to_prb_mapping,
dlsch_config_pdu_1_0->mcs,
dlsch_config_pdu_1_0->ndi,
dlsch_config_pdu_1_0->rv,
dlsch_config_pdu_1_0->harq_process_nbr,
dlsch_config_pdu_1_0->dai,
dlsch_config_pdu_1_0->scaling_factor_S,
dlsch_config_pdu_1_0->accumulated_delta_PUCCH,
dlsch_config_pdu_1_0->pucch_resource_id,
dlsch_config_pdu_1_0->pdsch_to_harq_feedback_time_ind);
if (ra->RA_window_cnt >= 0 && rnti == ra->ra_rnti){
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH;
} else {
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH;
}
// dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.N_RB_BWP = n_RB_DLBWP;
LOG_D(MAC,"(nr_ue_procedures.c) pdu_type=%d\n\n",dl_config->dl_config_list[dl_config->number_pdus].pdu_type);
dl_config->number_pdus = dl_config->number_pdus + 1;
break;
case NR_DL_DCI_FORMAT_1_1:
/*
* with CRC scrambled by C-RNTI or CS-RNTI or new-RNTI
* 0 IDENTIFIER_DCI_FORMATS:
* 1 CARRIER_IND:
* 7 BANDWIDTH_PART_IND:
* 11 FREQ_DOM_RESOURCE_ASSIGNMENT_DL:
* 12 TIME_DOM_RESOURCE_ASSIGNMENT: 0, 1, 2, 3, or 4 bits as defined in Subclause 5.1.2.1 of [6, TS 38.214]. The bitwidth for this field is determined as log2(I) bits,
* 13 VRB_TO_PRB_MAPPING: 0 bit if only resource allocation type 0
* 14 PRB_BUNDLING_SIZE_IND:
* 15 RATE_MATCHING_IND:
* 16 ZP_CSI_RS_TRIGGER:
* 18 TB1_MCS:
* 19 TB1_NDI:
* 20 TB1_RV:
* 21 TB2_MCS:
* 22 TB2_NDI:
* 23 TB2_RV:
* 27 HARQ_PROCESS_NUMBER:
* 28 DAI_: For format1_1: 4 if more than one serving cell are configured in the DL and the higher layer parameter HARQ-ACK-codebook=dynamic, where the 2 MSB bits are the counter DAI and the 2 LSB bits are the total DAI
* 33 TPC_PUCCH:
* 34 PUCCH_RESOURCE_IND:
* 35 PDSCH_TO_HARQ_FEEDBACK_TIME_IND:
* 38 ANTENNA_PORTS:
* 39 TCI:
* 40 SRS_REQUEST:
* 43 CBGTI:
* 44 CBGFI:
* 47 DMRS_SEQ_INI:
*/
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH;
dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.rnti = rnti;
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu_1_1 = &dl_config->dl_config_list[dl_config->number_pdus].dlsch_config_pdu.dlsch_config_rel15;
/* IDENTIFIER_DCI_FORMATS */
/* CARRIER_IND */
/* BANDWIDTH_PART_IND */
// dlsch_config_pdu_1_1->bandwidth_part_ind = dci->bandwidth_part_ind;
/* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_1,0,n_RB_DLBWP,dci->frequency_domain_assignment.val) < 0)
return -1;
/* TIME_DOM_RESOURCE_ASSIGNMENT */
if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_1,dci->time_domain_assignment.val) < 0)
return -1;
/* dmrs symbol positions*/
dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
mac->scc->dmrs_TypeA_Position,
dlsch_config_pdu_1_1->number_symbols);
dlsch_config_pdu_1_1->dmrsConfigType = mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1;
/* TODO: fix number of DM-RS CDM groups without data according to subclause 5.1.6.2 of 3GPP TS 38.214,
using tables 7.3.1.2.2-1, 7.3.1.2.2-2, 7.3.1.2.2-3, 7.3.1.2.2-4 of 3GPP TS 38.212 */
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = 1;
/* VRB_TO_PRB_MAPPING */
if (mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.resource_allocation != 0)
dlsch_config_pdu_1_1->vrb_to_prb_mapping = (dci->vrb_to_prb_mapping.val == 0) ? vrb_to_prb_mapping_non_interleaved:vrb_to_prb_mapping_interleaved;
/* PRB_BUNDLING_SIZE_IND */
dlsch_config_pdu_1_1->prb_bundling_size_ind = dci->prb_bundling_size_indicator.val;
/* RATE_MATCHING_IND */
dlsch_config_pdu_1_1->rate_matching_ind = dci->rate_matching_indicator.val;
/* ZP_CSI_RS_TRIGGER */
dlsch_config_pdu_1_1->zp_csi_rs_trigger = dci->zp_csi_rs_trigger.val;
/* MCS (for transport block 1)*/
dlsch_config_pdu_1_1->mcs = dci->mcs;
// Basic sanity check for MCS value to check for a false or erroneous DCI
if (dlsch_config_pdu_1_1->mcs > 28) {
LOG_W(MAC, "MCS value % d out of bounds! Possibly due to false DCI. Ignoring DCI!!\n", dlsch_config_pdu_1_1->mcs);
return -1;
}
/* NDI (for transport block 1)*/
dlsch_config_pdu_1_1->ndi = dci->ndi;
/* RV (for transport block 1)*/
dlsch_config_pdu_1_1->rv = dci->rv;
/* MCS (for transport block 2)*/
dlsch_config_pdu_1_1->tb2_mcs = dci->mcs2.val;
// Basic sanity check for MCS value to check for a false or erroneous DCI
if (dlsch_config_pdu_1_1->tb2_mcs > 28) {
LOG_W(MAC, "MCS value % d out of bounds! Possibly due to false DCI. Ignoring DCI!!\n", dlsch_config_pdu_1_1->tb2_mcs);
return -1;
}
/* NDI (for transport block 2)*/
dlsch_config_pdu_1_1->tb2_ndi = dci->ndi2.val;
/* RV (for transport block 2)*/
dlsch_config_pdu_1_1->tb2_rv = dci->rv2.val;
/* HARQ_PROCESS_NUMBER */
dlsch_config_pdu_1_1->harq_process_nbr = dci->harq_pid;
/* DAI */
dlsch_config_pdu_1_1->dai = dci->dai[0].val;
/* TPC_PUCCH */
// according to TS 38.213 Table 7.2.1-1
if (dci->tpc == 0) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = -1;
if (dci->tpc == 1) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = 0;
if (dci->tpc == 2) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = 1;
if (dci->tpc == 3) dlsch_config_pdu_1_1->accumulated_delta_PUCCH = 3;
/* PUCCH_RESOURCE_IND */
dlsch_config_pdu_1_1->pucch_resource_id = dci->pucch_resource_indicator;
// Sanity check for pucch_resource_indicator value received to check for false DCI.
valid = 0;
pucch_res_set_cnt = mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.count;
for (int id = 0; id < pucch_res_set_cnt; id++) {
if (dlsch_config_pdu_1_1->pucch_resource_id < mac->ULbwp[0]->bwp_Dedicated->pucch_Config->choice.setup->resourceSetToAddModList->list.array[id]->resourceList.list.count) {
valid = 1;
break;
}
}
if (!valid) {
LOG_W(MAC, "pucch_resource_indicator value %d is out of bounds. Possibly due to false DCI. Ignoring DCI!\n", dlsch_config_pdu_1_1->pucch_resource_id);
return -1;
}
/* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */
// according to TS 38.213 Table 9.2.3-1
dlsch_config_pdu_1_1->pdsch_to_harq_feedback_time_ind = mac->ULbwp[bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0];
/* ANTENNA_PORTS */
uint8_t n_codewords = 1; // FIXME!!!
if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 1)){
// Table 7.3.1.2.2-1: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=1
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_1[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_1[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_1[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_1[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_1[dci->antenna_ports.val][4];
}
if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 1) &&
(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 2)){
// Table 7.3.1.2.2-2: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=2
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][4];
dlsch_config_pdu_1_1->n_front_load_symb = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][5];
}
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][4];
dlsch_config_pdu_1_1->dmrs_ports[4] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][5];
dlsch_config_pdu_1_1->dmrs_ports[5] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][6];
dlsch_config_pdu_1_1->dmrs_ports[6] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][7];
dlsch_config_pdu_1_1->dmrs_ports[7] = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][8];
dlsch_config_pdu_1_1->n_front_load_symb = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][9];
}
}
if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 2) &&
(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 1)){
// Table 7.3.1.2.2-3: Antenna port(s) (1000 + DMRS port), dmrs-Type=2, maxLength=1
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][4];
}
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][4];
dlsch_config_pdu_1_1->dmrs_ports[4] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][5];
dlsch_config_pdu_1_1->dmrs_ports[5] = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][6];
}
}
if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 2) &&
(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 2)){
// Table 7.3.1.2.2-4: Antenna port(s) (1000 + DMRS port), dmrs-Type=2, maxLength=2
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][4];
dlsch_config_pdu_1_1->n_front_load_symb = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][5];
}
if (n_codewords == 1) {
dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][0];
dlsch_config_pdu_1_1->dmrs_ports[0] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][1];
dlsch_config_pdu_1_1->dmrs_ports[1] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][2];
dlsch_config_pdu_1_1->dmrs_ports[2] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][3];
dlsch_config_pdu_1_1->dmrs_ports[3] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][4];
dlsch_config_pdu_1_1->dmrs_ports[4] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][5];
dlsch_config_pdu_1_1->dmrs_ports[5] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][6];
dlsch_config_pdu_1_1->dmrs_ports[6] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][7];
dlsch_config_pdu_1_1->dmrs_ports[7] = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][8];
dlsch_config_pdu_1_1->n_front_load_symb = table_7_3_2_3_3_4_twoCodeword[dci->antenna_ports.val][9];
}
}
/* TCI */
if (mac->dl_config_request.dl_config_list[0].dci_config_pdu.dci_config_rel15.coreset.tci_present_in_dci == 1){
// 0 bit if higher layer parameter tci-PresentInDCI is not enabled
// otherwise 3 bits as defined in Subclause 5.1.5 of [6, TS38.214]
dlsch_config_pdu_1_1->tci_state = dci->transmission_configuration_indication.val;
}
/* SRS_REQUEST */
// if SUL is supported in the cell, there is an additional bit in this field and the value of this bit represents table 7.1.1.1-1 TS 38.212 FIXME!!!
dlsch_config_pdu_1_1->srs_config.aperiodicSRS_ResourceTrigger = (dci->srs_request.val & 0x11); // as per Table 7.3.1.1.2-24 TS 38.212
/* CBGTI */
dlsch_config_pdu_1_1->cbgti = dci->cbgti.val;
/* CBGFI */
dlsch_config_pdu_1_1->codeBlockGroupFlushIndicator = dci->cbgfi.val;
/* DMRS_SEQ_INI */
//FIXME!!!
// dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15.N_RB_BWP = n_RB_DLBWP;
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH;
LOG_D(MAC,"(nr_ue_procedures.c) pdu_type=%d\n\n",dl_config->dl_config_list[dl_config->number_pdus].pdu_type);
dl_config->number_pdus = dl_config->number_pdus + 1;
/* TODO same calculation for MCS table as done in UL */
dlsch_config_pdu_1_1->mcs_table = (pdsch_config->mcs_Table) ? (*pdsch_config->mcs_Table + 1) : 0;
/*PTRS configuration */
if(mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) {
valid_ptrs_setup = set_dl_ptrs_values(mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup,
dlsch_config_pdu_1_1->number_rbs, dlsch_config_pdu_1_1->mcs, dlsch_config_pdu_1_1->mcs_table,
&dlsch_config_pdu_1_1->PTRSFreqDensity,&dlsch_config_pdu_1_1->PTRSTimeDensity,
&dlsch_config_pdu_1_1->PTRSPortIndex,&dlsch_config_pdu_1_1->nEpreRatioOfPDSCHToPTRS,
&dlsch_config_pdu_1_1->PTRSReOffset, dlsch_config_pdu_1_1->number_symbols);
if(valid_ptrs_setup==true) {
dlsch_config_pdu_1_1->pduBitmap |= 0x1;
}
}
break;
case NR_DL_DCI_FORMAT_2_0:
break;
case NR_DL_DCI_FORMAT_2_1:
break;
case NR_DL_DCI_FORMAT_2_2:
break;
case NR_DL_DCI_FORMAT_2_3:
break;
default:
break;
}
if(rnti == SI_RNTI){
// }else if(rnti == mac->ra_rnti){
}else if(rnti == P_RNTI){
}else{ // c-rnti
/// check if this is pdcch order
//dci->random_access_preamble_index;
//dci->ss_pbch_index;
//dci->prach_mask_index;
/// else normal DL-SCH grant
}
return 0;
}
int8_t nr_ue_get_SR(module_id_t module_idP, int CC_id, frame_t frameP, uint8_t eNB_id, uint16_t rnti, sub_frame_t subframe){
return 0;
}
void nr_ue_send_sdu(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment, int pdu_id){
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP);
for (i = 0; i < 32; i++) {
LOG_T(MAC, "%x.", sdu[i]);
}
LOG_T(MAC, "\n");
#endif
LOG_D(MAC, "In %s [%d.%d] Handling DLSCH PDU...\n", __FUNCTION__, dl_info->frame, dl_info->slot);
// Processing MAC PDU
// it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs
switch (dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type){
case FAPI_NR_RX_PDU_TYPE_DLSCH:
nr_ue_process_mac_pdu(dl_info, ul_time_alignment, pdu_id);
break;
case FAPI_NR_RX_PDU_TYPE_RAR:
nr_ue_process_rar(dl_info, ul_time_alignment, pdu_id);
break;
default:
break;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT);
}
// N_RB configuration according to 7.3.1.0 (DCI size alignment) of TS 38.212
int get_n_rb(NR_UE_MAC_INST_t *mac, int rnti_type){
int N_RB = 0, start_RB;
switch(rnti_type) {
case NR_RNTI_RA:
case NR_RNTI_TC:
case NR_RNTI_P:
case NR_RNTI_SI:
if (mac->DLbwp[0]->bwp_Common->pdcch_ConfigCommon->choice.setup->controlResourceSetZero) {
NR_BWP_Id_t bwp_id = mac->DL_BWP_Id;
uint8_t coreset_id = 0; // assuming controlResourceSetId is 0 for controlResourceSetZero
NR_ControlResourceSet_t *coreset = mac->coreset[bwp_id - 1][coreset_id];
get_coreset_rballoc(coreset->frequencyDomainResources.buf,&N_RB,&start_RB);
} else {
N_RB = NRRIV2BW(mac->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
}
break;
case NR_RNTI_C:
N_RB = NRRIV2BW(mac->DLbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
break;
}
return N_RB;
}
int nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
int dci_format,
uint8_t dci_size,
uint16_t rnti,
uint64_t *dci_pdu,
dci_pdu_rel15_t *dci_pdu_rel15) {
int rnti_type=-1;
RA_config_t *ra = &mac->ra;
if (rnti == ra->ra_rnti) rnti_type = NR_RNTI_RA;
else if (rnti == mac->crnti) rnti_type = NR_RNTI_C;
else if (rnti == ra->t_crnti) rnti_type = NR_RNTI_TC;
else if (rnti == 0xFFFE) rnti_type = NR_RNTI_P;
else if (rnti == 0xFFFF) rnti_type = NR_RNTI_SI;
AssertFatal(rnti_type!=-1,"no identified/handled rnti\n");
AssertFatal(mac->DLbwp[0] != NULL, "DLbwp[0] shouldn't be null here!\n");
AssertFatal(mac->ULbwp[0] != NULL, "ULbwp[0] shouldn't be null here!\n");
int N_RB = get_n_rb(mac, rnti_type);
int N_RB_UL = (mac->scg != NULL) ?
NRRIV2BW(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE) :
NRRIV2BW(mac->scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
int pos=0;
int fsize=0;
if (rnti_type == NR_RNTI_C) {
// First find out the DCI format from the first bit (UE performed blind decoding)
pos++;
dci_pdu_rel15->format_indicator = (*dci_pdu>>(dci_size-pos))&1;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"Format indicator %d (%d bits) N_RB_BWP %d => %d (0x%lx)\n",dci_pdu_rel15->format_indicator,1,N_RB,dci_size-pos,*dci_pdu);
#endif
if (dci_format == NR_UL_DCI_FORMAT_0_0 || dci_format == NR_DL_DCI_FORMAT_1_0) {
if (dci_pdu_rel15->format_indicator == 0)
dci_format = NR_UL_DCI_FORMAT_0_0;
else
dci_format = NR_DL_DCI_FORMAT_1_0;
}
else if (dci_format == NR_UL_DCI_FORMAT_0_1 || dci_format == NR_DL_DCI_FORMAT_1_1) {
// In case the sizes of formats 0_1 and 1_1 happen to be the same
if (dci_pdu_rel15->format_indicator == 0)
dci_format = NR_UL_DCI_FORMAT_0_1;
else
dci_format = NR_DL_DCI_FORMAT_1_1;
}
}
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC, "DCI format is %d\n", dci_format);
#endif
switch(dci_format) {
case NR_DL_DCI_FORMAT_1_0:
switch(rnti_type) {
case NR_RNTI_RA:
// Freq domain assignment
fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
pos=fsize;
dci_pdu_rel15->frequency_domain_assignment.val = *dci_pdu>>(dci_size-pos)&((1<<fsize)-1);
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"frequency-domain assignment %d (%d bits) N_RB_BWP %d=> %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment.val,fsize,N_RB,dci_size-pos,*dci_pdu);
#endif
// Time domain assignment
pos+=4;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu >> (dci_size-pos))&0xf;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"time-domain assignment %d (4 bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,dci_size-pos,*dci_pdu);
#endif
// VRB to PRB mapping
pos++;
dci_pdu_rel15->vrb_to_prb_mapping.val = (*dci_pdu>>(dci_size-pos))&0x1;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"vrb to prb mapping %d (1 bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping.val,dci_size-pos,*dci_pdu);
#endif
// MCS
pos+=5;
dci_pdu_rel15->mcs = (*dci_pdu>>(dci_size-pos))&0x1f;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"mcs %d (5 bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,dci_size-pos,*dci_pdu);
#endif
// TB scaling
pos+=2;
dci_pdu_rel15->tb_scaling = (*dci_pdu>>(dci_size-pos))&0x3;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"tb_scaling %d (2 bits)=> %d (0x%lx)\n",dci_pdu_rel15->tb_scaling,dci_size-pos,*dci_pdu);
#endif
break;
case NR_RNTI_C:
// Freq domain assignment (275rb >> fsize = 16)
fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
pos+=fsize;
dci_pdu_rel15->frequency_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<fsize)-1);
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"Freq domain assignment %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->frequency_domain_assignment.val,fsize,dci_size-pos,*dci_pdu);
#endif
uint16_t is_ra = 1;
for (int i=0; i<fsize; i++)
if (!((dci_pdu_rel15->frequency_domain_assignment.val>>i)&1)) {
is_ra = 0;
break;
}
if (is_ra) //fsize are all 1 38.212 p86
{
// ra_preamble_index 6 bits
pos+=6;
dci_pdu_rel15->ra_preamble_index = (*dci_pdu>>(dci_size-pos))&0x3f;
// UL/SUL indicator 1 bit
pos++;
dci_pdu_rel15->ul_sul_indicator.val = (*dci_pdu>>(dci_size-pos))&1;
// SS/PBCH index 6 bits
pos+=6;
dci_pdu_rel15->ss_pbch_index = (*dci_pdu>>(dci_size-pos))&0x3f;
// prach_mask_index 4 bits
pos+=4;
dci_pdu_rel15->prach_mask_index = (*dci_pdu>>(dci_size-pos))&0xf;
} //end if
else {
// Time domain assignment 4bit
pos+=4;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&0xf;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"Time domain assignment %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->time_domain_assignment.val,4,dci_size-pos,*dci_pdu);
#endif
// VRB to PRB mapping 1bit
pos++;
dci_pdu_rel15->vrb_to_prb_mapping.val = (*dci_pdu>>(dci_size-pos))&1;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"VRB to PRB %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->vrb_to_prb_mapping.val,1,dci_size-pos,*dci_pdu);
#endif
// MCS 5bit //bit over 32, so dci_pdu ++
pos+=5;
dci_pdu_rel15->mcs = (*dci_pdu>>(dci_size-pos))&0x1f;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"MCS %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->mcs,5,dci_size-pos,*dci_pdu);
#endif
// New data indicator 1bit
pos++;
dci_pdu_rel15->ndi = (*dci_pdu>>(dci_size-pos))&1;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"NDI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->ndi,1,dci_size-pos,*dci_pdu);
#endif
// Redundancy version 2bit
pos+=2;
dci_pdu_rel15->rv = (*dci_pdu>>(dci_size-pos))&0x3;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"RV %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->rv,2,dci_size-pos,*dci_pdu);
#endif
// HARQ process number 4bit
pos+=4;
dci_pdu_rel15->harq_pid = (*dci_pdu>>(dci_size-pos))&0xf;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"HARQ_PID %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->harq_pid,4,dci_size-pos,*dci_pdu);
#endif
// Downlink assignment index 2bit
pos+=2;
dci_pdu_rel15->dai[0].val = (*dci_pdu>>(dci_size-pos))&3;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"DAI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->dai[0].val,2,dci_size-pos,*dci_pdu);
#endif
// TPC command for scheduled PUCCH 2bit
pos+=2;
dci_pdu_rel15->tpc = (*dci_pdu>>(dci_size-pos))&3;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"TPC %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->tpc,2,dci_size-pos,*dci_pdu);
#endif
// PUCCH resource indicator 3bit
pos+=3;
dci_pdu_rel15->pucch_resource_indicator = (*dci_pdu>>(dci_size-pos))&0x7;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"PUCCH RI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pucch_resource_indicator,3,dci_size-pos,*dci_pdu);
#endif
// PDSCH-to-HARQ_feedback timing indicator 3bit
pos+=3;
dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val = (*dci_pdu>>(dci_size-pos))&0x7;
#ifdef DEBUG_EXTRACT_DCI
LOG_D(MAC,"PDSCH to HARQ TI %d (%d bits)=> %d (0x%lx)\n",dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val,3,dci_size-pos,*dci_pdu);
#endif
} //end else
break;
case NR_RNTI_P:
/*
// Short Messages Indicator  E2 bits
for (int i=0; i<2; i++)
dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages_indicator>>(1-i))&1)<<(dci_size-pos++);
// Short Messages  E8 bits
for (int i=0; i<8; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->short_messages>>(7-i))&1)<<(dci_size-pos++);
// Freq domain assignment 0-16 bit
fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
for (int i=0; i<fsize; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->frequency_domain_assignment>>(fsize-i-1))&1)<<(dci_size-pos++);
// Time domain assignment 4 bit
for (int i=0; i<4; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment>>(3-i))&1)<<(dci_size-pos++);
// VRB to PRB mapping 1 bit
*dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos++);
// MCS 5 bit
for (int i=0; i<5; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++);
// TB scaling 2 bit
for (int i=0; i<2; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->tb_scaling>>(1-i))&1)<<(dci_size-pos++);
*/
break;
case NR_RNTI_SI:
/*
// Freq domain assignment 0-16 bit
fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
for (int i=0; i<fsize; i++)
*dci_pdu |= ((dci_pdu_rel15->frequency_domain_assignment>>(fsize-i-1))&1)<<(dci_size-pos++);
// Time domain assignment 4 bit
for (int i=0; i<4; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->time_domain_assignment>>(3-i))&1)<<(dci_size-pos++);
// VRB to PRB mapping 1 bit
*dci_pdu |= ((uint64_t)dci_pdu_rel15->vrb_to_prb_mapping.val&1)<<(dci_size-pos++);
// MCS 5bit //bit over 32, so dci_pdu ++
for (int i=0; i<5; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->mcs>>(4-i))&1)<<(dci_size-pos++);
// Redundancy version 2bit
for (int i=0; i<2; i++)
*dci_pdu |= (((uint64_t)dci_pdu_rel15->rv>>(1-i))&1)<<(dci_size-pos++);
*/
break;
case NR_RNTI_TC:
// indicating a DL DCI format 1bit
pos++;
dci_pdu_rel15->format_indicator = (*dci_pdu>>(dci_size-pos))&1;
// Freq domain assignment 0-16 bit
fsize = (int)ceil( log2( (N_RB*(N_RB+1))>>1 ) );
pos+=fsize;
dci_pdu_rel15->frequency_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<fsize)-1);
// Time domain assignment 4 bit
pos+=4;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&0xf;
// VRB to PRB mapping 1 bit
dci_pdu_rel15->vrb_to_prb_mapping.val = (*dci_pdu>>(dci_size-pos))&1;
// MCS 5bit //bit over 32, so dci_pdu ++
pos+=5;
dci_pdu_rel15->mcs = (*dci_pdu>>(dci_size-pos))&0x1f;
// New data indicator 1bit
dci_pdu_rel15->ndi = (*dci_pdu>>(dci_size-pos))&1;
// Redundancy version 2bit
pos+=2;
dci_pdu_rel15->rv = (*dci_pdu>>(dci_size-pos))&3;
// HARQ process number 4bit
pos+=4;
dci_pdu_rel15->harq_pid = (*dci_pdu>>(dci_size-pos))&0xf;
// Downlink assignment index  E2 bits
pos+=2;
dci_pdu_rel15->dai[0].val = (*dci_pdu>>(dci_size-pos))&3;
// TPC command for scheduled PUCCH  E2 bits
pos+=2;
dci_pdu_rel15->tpc = (*dci_pdu>>(dci_size-pos))&3;
// PDSCH-to-HARQ_feedback timing indicator  E3 bits
pos+=3;
dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val = (*dci_pdu>>(dci_size-pos))&7;
break;
}
break;
case NR_UL_DCI_FORMAT_0_0:
switch(rnti_type)
{
case NR_RNTI_C:
fsize = (int)ceil( log2( (N_RB_UL*(N_RB_UL+1))>>1 ) );
pos+=fsize;
dci_pdu_rel15->frequency_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<fsize)-1);
// Time domain assignment 4bit
pos+=4;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&0xf;
// Frequency hopping flag  E1 bit
pos++;
dci_pdu_rel15->frequency_hopping_flag.val= (*dci_pdu>>(dci_size-pos))&1;
// MCS 5 bit
pos+=5;
dci_pdu_rel15->mcs= (*dci_pdu>>(dci_size-pos))&0x1f;
// New data indicator 1bit
pos++;
dci_pdu_rel15->ndi= (*dci_pdu>>(dci_size-pos))&1;
// Redundancy version 2bit
pos+=2;
dci_pdu_rel15->rv= (*dci_pdu>>(dci_size-pos))&3;
// HARQ process number 4bit
pos+=4;
dci_pdu_rel15->harq_pid = (*dci_pdu>>(dci_size-pos))&0xf;
// TPC command for scheduled PUSCH  E2 bits
pos+=2;
dci_pdu_rel15->tpc = (*dci_pdu>>(dci_size-pos))&3;
// UL/SUL indicator  E1 bit
/* commented for now (RK): need to get this from BWP descriptor
if (cfg->pucch_config.pucch_GroupHopping.value)
dci_pdu->= ((uint64_t)*dci_pdu>>(dci_size-pos)ul_sul_indicator&1)<<(dci_size-pos++);
*/
break;
case NR_RNTI_TC:
/*
// indicating a DL DCI format 1bit
dci_pdu->= (*dci_pdu>>(dci_size-pos)format_indicator&1)<<(dci_size-pos++);
// Freq domain assignment max 16 bit
fsize = (int)ceil( log2( (N_RB_UL*(N_RB_UL+1))>>1 ) );
for (int i=0; i<fsize; i++)
dci_pdu->= ((*dci_pdu>>(dci_size-pos)frequency_domain_assignment>>(fsize-i-1))&1)<<(dci_size-pos++);
// Time domain assignment 4bit
for (int i=0; i<4; i++)
dci_pdu->= (((uint64_t)*dci_pdu>>(dci_size-pos)time_domain_assignment>>(3-i))&1)<<(dci_size-pos++);
// Frequency hopping flag  E1 bit
dci_pdu->= ((uint64_t)*dci_pdu>>(dci_size-pos)frequency_hopping_flag&1)<<(dci_size-pos++);
// MCS 5 bit
for (int i=0; i<5; i++)
dci_pdu->= (((uint64_t)*dci_pdu>>(dci_size-pos)mcs>>(4-i))&1)<<(dci_size-pos++);
// New data indicator 1bit
dci_pdu->= ((uint64_t)*dci_pdu>>(dci_size-pos)ndi&1)<<(dci_size-pos++);
// Redundancy version 2bit
for (int i=0; i<2; i++)
dci_pdu->= (((uint64_t)*dci_pdu>>(dci_size-pos)rv>>(1-i))&1)<<(dci_size-pos++);
// HARQ process number 4bit
for (int i=0; i<4; i++)
*dci_pdu |= (((uint64_t)*dci_pdu>>(dci_size-pos)harq_pid>>(3-i))&1)<<(dci_size-pos++);
// TPC command for scheduled PUSCH  E2 bits
for (int i=0; i<2; i++)
dci_pdu->= (((uint64_t)*dci_pdu>>(dci_size-pos)tpc>>(1-i))&1)<<(dci_size-pos++);
*/
// UL/SUL indicator  E1 bit
/*
commented for now (RK): need to get this information from BWP descriptor
if (cfg->pucch_config.pucch_GroupHopping.value)
dci_pdu->= ((uint64_t)dci_pdu_rel15->ul_sul_indicator&1)<<(dci_size-pos++);
*/
break;
}
break;
case NR_DL_DCI_FORMAT_1_1:
switch(rnti_type)
{
case NR_RNTI_C:
// Carrier indicator
pos+=dci_pdu_rel15->carrier_indicator.nbits;
dci_pdu_rel15->carrier_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->carrier_indicator.nbits)-1);
// BWP Indicator
pos+=dci_pdu_rel15->bwp_indicator.nbits;
dci_pdu_rel15->bwp_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->bwp_indicator.nbits)-1);
config_bwp_ue(mac, &dci_pdu_rel15->bwp_indicator.val, &dci_format);
// Frequency domain resource assignment
pos+=dci_pdu_rel15->frequency_domain_assignment.nbits;
dci_pdu_rel15->frequency_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->frequency_domain_assignment.nbits)-1);
// Time domain resource assignment
pos+=dci_pdu_rel15->time_domain_assignment.nbits;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->time_domain_assignment.nbits)-1);
// VRB-to-PRB mapping
pos+=dci_pdu_rel15->vrb_to_prb_mapping.nbits;
dci_pdu_rel15->vrb_to_prb_mapping.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->vrb_to_prb_mapping.nbits)-1);
// PRB bundling size indicator
pos+=dci_pdu_rel15->prb_bundling_size_indicator.nbits;
dci_pdu_rel15->prb_bundling_size_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->prb_bundling_size_indicator.nbits)-1);
// Rate matching indicator
pos+=dci_pdu_rel15->rate_matching_indicator.nbits;
dci_pdu_rel15->rate_matching_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->rate_matching_indicator.nbits)-1);
// ZP CSI-RS trigger
pos+=dci_pdu_rel15->zp_csi_rs_trigger.nbits;
dci_pdu_rel15->zp_csi_rs_trigger.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->zp_csi_rs_trigger.nbits)-1);
//TB1
// MCS 5bit
pos+=5;
dci_pdu_rel15->mcs = (*dci_pdu>>(dci_size-pos))&0x1f;
// New data indicator 1bit
pos+=1;
dci_pdu_rel15->ndi = (*dci_pdu>>(dci_size-pos))&0x1;
// Redundancy version 2bit
pos+=2;
dci_pdu_rel15->rv = (*dci_pdu>>(dci_size-pos))&0x3;
//TB2
// MCS 5bit
pos+=dci_pdu_rel15->mcs2.nbits;
dci_pdu_rel15->mcs2.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->mcs2.nbits)-1);
// New data indicator 1bit
pos+=dci_pdu_rel15->ndi2.nbits;
dci_pdu_rel15->ndi2.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->ndi2.nbits)-1);
// Redundancy version 2bit
pos+=dci_pdu_rel15->rv2.nbits;
dci_pdu_rel15->rv2.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->rv2.nbits)-1);
// HARQ process number 4bit
pos+=4;
dci_pdu_rel15->harq_pid = (*dci_pdu>>(dci_size-pos))&0xf;
// Downlink assignment index
pos+=dci_pdu_rel15->dai[0].nbits;
dci_pdu_rel15->dai[0].val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->dai[0].nbits)-1);
// TPC command for scheduled PUCCH 2bit
pos+=2;
dci_pdu_rel15->tpc = (*dci_pdu>>(dci_size-pos))&0x3;
// PUCCH resource indicator 3bit
pos+=3;
dci_pdu_rel15->pucch_resource_indicator = (*dci_pdu>>(dci_size-pos))&0x3;
// PDSCH-to-HARQ_feedback timing indicator
pos+=dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits;
dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.nbits)-1);
// Antenna ports
pos+=dci_pdu_rel15->antenna_ports.nbits;
dci_pdu_rel15->antenna_ports.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->antenna_ports.nbits)-1);
// TCI
pos+=dci_pdu_rel15->transmission_configuration_indication.nbits;
dci_pdu_rel15->transmission_configuration_indication.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->transmission_configuration_indication.nbits)-1);
// SRS request
pos+=dci_pdu_rel15->srs_request.nbits;
dci_pdu_rel15->srs_request.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->srs_request.nbits)-1);
// CBG transmission information
pos+=dci_pdu_rel15->cbgti.nbits;
dci_pdu_rel15->cbgti.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->cbgti.nbits)-1);
// CBG flushing out information
pos+=dci_pdu_rel15->cbgfi.nbits;
dci_pdu_rel15->cbgfi.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->cbgfi.nbits)-1);
// DMRS sequence init
pos+=1;
dci_pdu_rel15->dmrs_sequence_initialization.val = (*dci_pdu>>(dci_size-pos))&0x1;
break;
}
break;
case NR_UL_DCI_FORMAT_0_1:
switch(rnti_type)
{
case NR_RNTI_C:
// Carrier indicator
pos+=dci_pdu_rel15->carrier_indicator.nbits;
dci_pdu_rel15->carrier_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->carrier_indicator.nbits)-1);
// UL/SUL Indicator
pos+=dci_pdu_rel15->ul_sul_indicator.nbits;
dci_pdu_rel15->ul_sul_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->ul_sul_indicator.nbits)-1);
// BWP Indicator
pos+=dci_pdu_rel15->bwp_indicator.nbits;
dci_pdu_rel15->bwp_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->bwp_indicator.nbits)-1);
config_bwp_ue(mac, &dci_pdu_rel15->bwp_indicator.val, &dci_format);
// Freq domain assignment max 16 bit
fsize = (int)ceil( log2( (N_RB_UL*(N_RB_UL+1))>>1 ) );
//pos+=dci_pdu_rel15->frequency_domain_assignment.nbits;
pos+=fsize;
//pos+=dci_pdu_rel15->frequency_domain_assignment.nbits;
dci_pdu_rel15->frequency_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&((1<<fsize)-1);
// Time domain assignment 4bit
//pos+=4;
pos+=dci_pdu_rel15->time_domain_assignment.nbits;
dci_pdu_rel15->time_domain_assignment.val = (*dci_pdu>>(dci_size-pos))&0x3;
// Not supported yet - skip for now
// Frequency hopping flag – 1 bit
//pos++;
//dci_pdu_rel15->frequency_hopping_flag.val= (*dci_pdu>>(dci_size-pos))&1;
// MCS 5 bit
pos+=5;
dci_pdu_rel15->mcs= (*dci_pdu>>(dci_size-pos))&0x1f;
// New data indicator 1bit
pos++;
dci_pdu_rel15->ndi= (*dci_pdu>>(dci_size-pos))&1;
// Redundancy version 2bit
pos+=2;
dci_pdu_rel15->rv= (*dci_pdu>>(dci_size-pos))&3;
// HARQ process number 4bit
pos+=4;
dci_pdu_rel15->harq_pid = (*dci_pdu>>(dci_size-pos))&0xf;
// 1st Downlink assignment index
pos+=dci_pdu_rel15->dai[0].nbits;
dci_pdu_rel15->dai[0].val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->dai[0].nbits)-1);
// 2nd Downlink assignment index
pos+=dci_pdu_rel15->dai[1].nbits;
dci_pdu_rel15->dai[1].val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->dai[1].nbits)-1);
// TPC command for scheduled PUSCH – 2 bits
pos+=2;
dci_pdu_rel15->tpc = (*dci_pdu>>(dci_size-pos))&3;
// SRS resource indicator
pos+=dci_pdu_rel15->srs_resource_indicator.nbits;
dci_pdu_rel15->srs_resource_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->srs_resource_indicator.nbits)-1);
// Precoding info and n. of layers
pos+=dci_pdu_rel15->precoding_information.nbits;
dci_pdu_rel15->precoding_information.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->precoding_information.nbits)-1);
// Antenna ports
pos+=dci_pdu_rel15->antenna_ports.nbits;
dci_pdu_rel15->antenna_ports.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->antenna_ports.nbits)-1);
// SRS request
pos+=dci_pdu_rel15->srs_request.nbits;
dci_pdu_rel15->srs_request.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->srs_request.nbits)-1);
// CSI request
pos+=dci_pdu_rel15->csi_request.nbits;
dci_pdu_rel15->csi_request.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->csi_request.nbits)-1);
// CBG transmission information
pos+=dci_pdu_rel15->cbgti.nbits;
dci_pdu_rel15->cbgti.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->cbgti.nbits)-1);
// PTRS DMRS association
pos+=dci_pdu_rel15->ptrs_dmrs_association.nbits;
dci_pdu_rel15->ptrs_dmrs_association.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->ptrs_dmrs_association.nbits)-1);
// Beta offset indicator
pos+=dci_pdu_rel15->beta_offset_indicator.nbits;
dci_pdu_rel15->beta_offset_indicator.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->beta_offset_indicator.nbits)-1);
// DMRS sequence initialization
pos+=dci_pdu_rel15->dmrs_sequence_initialization.nbits;
dci_pdu_rel15->dmrs_sequence_initialization.val = (*dci_pdu>>(dci_size-pos))&((1<<dci_pdu_rel15->dmrs_sequence_initialization.nbits)-1);
// UL-SCH indicator
pos+=1;
dci_pdu_rel15->ulsch_indicator = (*dci_pdu>>(dci_size-pos))&0x1;
// UL/SUL indicator – 1 bit
/* commented for now (RK): need to get this from BWP descriptor
if (cfg->pucch_config.pucch_GroupHopping.value)
dci_pdu->= ((uint64_t)*dci_pdu>>(dci_size-pos)ul_sul_indicator&1)<<(dci_size-pos++);
*/
break;
}
break;
}
return dci_format;
}
///////////////////////////////////
// brief: nr_ue_process_mac_pdu
// function: parsing DL PDU header
///////////////////////////////////
// Header for DLSCH:
// Except:
// - DL-SCH: fixed-size MAC CE(known by LCID)
// - DL-SCH: padding
//
// |0|1|2|3|4|5|6|7| bit-wise
// |R|F| LCID |
// | L |
// |0|1|2|3|4|5|6|7| bit-wise
// |R|F| LCID |
// | L |
// | L |
////////////////////////////////
// Header for DLSCH:
// - DLSCH: fixed-size MAC CE(known by LCID)
// - DLSCH: padding, for single/multiple 1-oct padding CE(s)
//
// |0|1|2|3|4|5|6|7| bit-wise
// |R|R| LCID |
// LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described
// in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits;
// L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders
// corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field;
// F: lenght of L is 0:8 or 1:16 bits wide
// R: Reserved bit, set to zero.
////////////////////////////////
void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment,
int pdu_id){
uint8_t rx_lcid;
uint16_t mac_ce_len;
uint16_t mac_subheader_len;
uint16_t mac_sdu_len;
module_id_t module_idP = dl_info->module_id;
frame_t frameP = dl_info->frame;
int slot = dl_info->slot;
uint8_t *pduP = (dl_info->rx_ind->rx_indication_body + pdu_id)->pdsch_pdu.pdu;
uint16_t pdu_len = (dl_info->rx_ind->rx_indication_body + pdu_id)->pdsch_pdu.pdu_length;
uint8_t gNB_index = dl_info->gNB_index;
uint8_t CC_id = dl_info->cc_id;
uint8_t done = 0;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
RA_config_t *ra = &mac->ra;
if (!pduP){
return;
}
LOG_D(MAC, "In %s [%d.%d]: processing PDU %d of %d total number of PDUs...\n", __FUNCTION__, frameP, slot, pdu_id, dl_info->rx_ind->number_pdus);
while (!done && pdu_len > 0){
mac_ce_len = 0x0000;
mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct
mac_sdu_len = 0x0000;
rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID;
//#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID, pdu_len);
//#endif
LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", rx_lcid, pdu_len);
switch(rx_lcid){
// MAC CE
case DL_SCH_LCID_CCCH:
// MSG4 RRC Connection Setup 38.331
// varialbe length
mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
}
break;
case DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH:
// 38.321 Ch6.1.3.14
// varialbe length
mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
}
break;
case DL_SCH_LCID_APERIODIC_CSI_TRI_STATE_SUBSEL:
// 38.321 Ch6.1.3.13
// varialbe length
mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
}
break;
case DL_SCH_LCID_SP_CSI_RS_CSI_IM_RES_SET_ACT:
// 38.321 Ch6.1.3.12
// varialbe length
mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
}
break;
case DL_SCH_LCID_SP_SRS_ACTIVATION:
// 38.321 Ch6.1.3.17
// varialbe length
mac_ce_len |= (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
mac_ce_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
}
break;
case DL_SCH_LCID_RECOMMENDED_BITRATE:
// 38.321 Ch6.1.3.20
mac_ce_len = 2;
break;
case DL_SCH_LCID_SP_ZP_CSI_RS_RES_SET_ACT:
// 38.321 Ch6.1.3.19
mac_ce_len = 2;
break;
case DL_SCH_LCID_PUCCH_SPATIAL_RELATION_ACT:
// 38.321 Ch6.1.3.18
mac_ce_len = 3;
break;
case DL_SCH_LCID_SP_CSI_REP_PUCCH_ACT:
// 38.321 Ch6.1.3.16
mac_ce_len = 2;
break;
case DL_SCH_LCID_TCI_STATE_IND_UE_SPEC_PDCCH:
// 38.321 Ch6.1.3.15
mac_ce_len = 2;
break;
case DL_SCH_LCID_DUPLICATION_ACT:
// 38.321 Ch6.1.3.11
mac_ce_len = 1;
break;
case DL_SCH_LCID_SCell_ACT_4_OCT:
// 38.321 Ch6.1.3.10
mac_ce_len = 4;
break;
case DL_SCH_LCID_SCell_ACT_1_OCT:
// 38.321 Ch6.1.3.10
mac_ce_len = 1;
break;
case DL_SCH_LCID_L_DRX:
// 38.321 Ch6.1.3.6
// fixed length but not yet specify.
mac_ce_len = 0;
break;
case DL_SCH_LCID_DRX:
// 38.321 Ch6.1.3.5
// fixed length but not yet specify.
mac_ce_len = 0;
break;
case DL_SCH_LCID_TA_COMMAND:
// 38.321 Ch6.1.3.4
mac_ce_len = 1;
/*uint8_t ta_command = ((NR_MAC_CE_TA *)pduP)[1].TA_COMMAND;
uint8_t tag_id = ((NR_MAC_CE_TA *)pduP)[1].TAGID;*/
ul_time_alignment->apply_ta = 1;
ul_time_alignment->ta_command = ((NR_MAC_CE_TA *)pduP)[1].TA_COMMAND;
ul_time_alignment->tag_id = ((NR_MAC_CE_TA *)pduP)[1].TAGID;
/*
#ifdef DEBUG_HEADER_PARSING
LOG_D(MAC, "[UE] CE %d : UE Timing Advance : %d\n", i, pduP[1]);
#endif
*/
LOG_D(MAC, "Received TA_COMMAND %u TAGID %u CC_id %d\n", ul_time_alignment->ta_command, ul_time_alignment->tag_id, CC_id);
break;
case DL_SCH_LCID_CON_RES_ID:
// Clause 5.1.5 and 6.1.3.3 of 3GPP TS 38.321 version 16.2.1 Release 16
// WIP todo: handle CCCH_pdu
mac_ce_len = 6;
LOG_I(MAC, "[UE %d][RAPROC] Frame %d : received contention resolution msg: %x.%x.%x.%x.%x.%x, Terminating RA procedure\n", module_idP, frameP, pduP[0], pduP[1], pduP[2], pduP[3], pduP[4], pduP[5]);
if (ra->RA_active == 1) {
nr_ra_succeeded(module_idP, frameP, slot);
}
break;
case DL_SCH_LCID_PADDING:
done = 1;
// end of MAC PDU, can ignore the rest.
break;
// MAC SDU
case DL_SCH_LCID_DCCH:
// check if LCID is valid at current time.
case DL_SCH_LCID_DCCH1:
// check if LCID is valid at current time.
default:
// check if LCID is valid at current time.
if(((NR_MAC_SUBHEADER_SHORT *)pduP)->F){
//mac_sdu_len |= (uint16_t)(((NR_MAC_SUBHEADER_LONG *)pduP)->L2)<<8;
mac_subheader_len = 3;
mac_sdu_len = ((uint16_t)(((NR_MAC_SUBHEADER_LONG *) pduP)->L1 & 0x7f) << 8)
| ((uint16_t)((NR_MAC_SUBHEADER_LONG *) pduP)->L2 & 0xff);
} else {
mac_sdu_len = (uint16_t)((NR_MAC_SUBHEADER_SHORT *)pduP)->L;
mac_subheader_len = 2;
}
LOG_D(MAC, "[UE %d] Frame %d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, gNB_index, mac_sdu_len);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP);
for (i = 0; i < 32; i++)
LOG_T(MAC, "%x.", (pduP + mac_subheader_len)[i]);
LOG_T(MAC, "\n");
#endif
if (IS_SOFTMODEM_NOS1){
if (rx_lcid < NB_RB_MAX && rx_lcid >= DL_SCH_LCID_DTCH) {
mac_rlc_data_ind(module_idP,
mac->crnti,
gNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
rx_lcid,
(char *) (pduP + mac_subheader_len),
mac_sdu_len,
1,
NULL);
} else {
LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (gNB %d)\n", module_idP, frameP, rx_lcid, gNB_index);
}
}
break;
}
pduP += ( mac_subheader_len + mac_ce_len + mac_sdu_len );
pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len );
if (pdu_len < 0)
LOG_E(MAC, "[MAC] nr_ue_process_mac_pdu, residual mac pdu length %d < 0!\n", pdu_len);
}
}
////////////////////////////////////////////////////////
/////* ULSCH MAC PDU generation (6.1.2 TS 38.321) */////
////////////////////////////////////////////////////////
uint16_t nr_generate_ulsch_pdu(uint8_t *sdus_payload,
uint8_t *pdu,
uint8_t num_sdus,
uint16_t *sdu_lengths,
uint8_t *sdu_lcids,
uint8_t power_headroom,
uint16_t crnti,
uint16_t truncated_bsr,
uint16_t short_bsr,
uint16_t long_bsr,
unsigned short post_padding,
uint16_t buflen) {
NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) pdu;
unsigned char last_size = 0, i, mac_header_control_elements[16], *ce_ptr, bsr = 0;
int mac_ce_size;
uint16_t offset = 0;
LOG_D(MAC, "[UE] Generating ULSCH PDU : num_sdus %d\n", num_sdus);
#ifdef DEBUG_HEADER_PARSING
for (i = 0; i < num_sdus; i++)
LOG_D(MAC, "[UE] MAC subPDU %d (lcid %d length %d bytes \n", i, sdu_lcids[i], sdu_lengths[i]);
#endif
// Generating UL MAC subPDUs including MAC SDU and subheader
for (i = 0; i < num_sdus; i++) {
LOG_D(MAC, "[UE] Generating UL MAC subPDUs for SDU with lenght %d ( num_sdus %d )\n", sdu_lengths[i], num_sdus);
if (sdu_lcids[i] != UL_SCH_LCID_CCCH){
if (sdu_lengths[i] < 128) {
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0;
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = sdu_lcids[i];
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = (unsigned char) sdu_lengths[i];
last_size = 2;
} else {
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->F = 1;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->LCID = sdu_lcids[i];
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L1 = ((unsigned short) sdu_lengths[i] >> 8) & 0x7f;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L2 = (unsigned short) sdu_lengths[i] & 0xff;
last_size = 3;
}
} else { // UL CCCH SDU
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = sdu_lcids[i];
}
mac_pdu_ptr += last_size;
// cycle through SDUs, compute each relevant and place ulsch_buffer in
memcpy((void *) mac_pdu_ptr, (void *) sdus_payload, sdu_lengths[i]);
sdus_payload += sdu_lengths[i];
mac_pdu_ptr += sdu_lengths[i];
}
// Generating UL MAC subPDUs including MAC CEs (MAC CE and subheader)
ce_ptr = &mac_header_control_elements[0];
if (power_headroom) {
// MAC CE fixed subheader
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = UL_SCH_LCID_SINGLE_ENTRY_PHR;
mac_pdu_ptr++;
// PHR MAC CE (1 octet)
((NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr)->PH = power_headroom;
((NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr)->R1 = 0;
((NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr)->PCMAX = 0; // todo
((NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr)->R2 = 0;
mac_ce_size = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE);
// Copying bytes for PHR MAC CEs to the mac pdu pointer
memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size);
ce_ptr += mac_ce_size;
mac_pdu_ptr += (unsigned char) mac_ce_size;
}
if (crnti) {
// MAC CE fixed subheader
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = CRNTI;
mac_pdu_ptr++;
// C-RNTI MAC CE (2 octets)
* (uint16_t *) ce_ptr = crnti;
mac_ce_size = sizeof(uint16_t);
// Copying bytes for CRNTI MAC CE to the mac pdu pointer
memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size);
ce_ptr += mac_ce_size;
mac_pdu_ptr += (unsigned char) mac_ce_size;
}
if (truncated_bsr) {
// MAC CE fixed subheader
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = UL_SCH_LCID_S_TRUNCATED_BSR;
mac_pdu_ptr++;
// Short truncated BSR MAC CE (1 octet)
((NR_BSR_SHORT_TRUNCATED *) ce_ptr)-> Buffer_size = truncated_bsr;
((NR_BSR_SHORT_TRUNCATED *) ce_ptr)-> LcgID = 0; // todo
mac_ce_size = sizeof(NR_BSR_SHORT_TRUNCATED);
bsr = 1 ;
} else if (short_bsr) {
// MAC CE fixed subheader
mac_pdu_ptr->R = 0;
mac_pdu_ptr->LCID = UL_SCH_LCID_S_BSR;
mac_pdu_ptr++;
// Short truncated BSR MAC CE (1 octet)
((NR_BSR_SHORT *) ce_ptr)->Buffer_size = short_bsr;
((NR_BSR_SHORT *) ce_ptr)->LcgID = 0; // todo
mac_ce_size = sizeof(NR_BSR_SHORT);
bsr = 1 ;
} else if (long_bsr) {
// MAC CE variable subheader
// todo ch 6.1.3.1. TS 38.321
// ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0;
// ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0;
// ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = UL_SCH_LCID_L_BSR;
// ((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = 0;
// last_size = 2;
// mac_pdu_ptr += last_size;
// Short truncated BSR MAC CE (1 octet)
// ((NR_BSR_LONG *) ce_ptr)->Buffer_size0 = short_bsr;
// ((NR_BSR_LONG *) ce_ptr)->LCGID0 = 0;
// mac_ce_size = sizeof(NR_BSR_LONG); // size is variable
}
if (bsr){
// Copying bytes for BSR MAC CE to the mac pdu pointer
memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size);
ce_ptr += mac_ce_size;
mac_pdu_ptr += (unsigned char) mac_ce_size;
}
// compute offset before adding padding (if necessary)
offset = ((unsigned char *) mac_pdu_ptr - pdu);
uint16_t padding_bytes = 0;
if(buflen > 0) // If the buflen is provided
padding_bytes = buflen - offset;
// Compute final offset for padding
if (post_padding > 0 || padding_bytes>0) {
((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->LCID = UL_SCH_LCID_PADDING;
mac_pdu_ptr++;
} else {
// no MAC subPDU with padding
}
// compute final offset
offset = ((unsigned char *) mac_pdu_ptr - pdu);
//printf("Offset %d \n", ((unsigned char *) mac_pdu_ptr - pdu));
return offset;
}
uint8_t
nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
sub_frame_t subframe, uint8_t eNB_index,
uint8_t *ulsch_buffer, uint16_t buflen, uint8_t *access_mode) {
uint8_t total_rlc_pdu_header_len = 0;
int16_t buflen_remain = 0;
uint8_t lcid = 0;
uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint16_t payload_offset = 0, num_sdus = 0;
uint8_t ulsch_sdus[MAX_ULSCH_PAYLOAD_BYTES];
uint16_t sdu_length_total = 0;
//unsigned short post_padding = 0;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
rlc_buffer_occupancy_t lcid_buffer_occupancy_old =
0, lcid_buffer_occupancy_new = 0;
LOG_D(MAC,
"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n",
module_idP, frameP, subframe, buflen);
AssertFatal(CC_id == 0,
"Transmission on secondary CCs is not supported yet\n");
// Check for DCCH first
// TO DO: Multiplex in the order defined by the logical channel prioritization
for (lcid = UL_SCH_LCID_SRB1;
lcid < NR_MAX_NUM_LCID; lcid++) {
lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, mac->crnti, eNB_index, frameP, subframe, ENB_FLAG_NO, lcid);
lcid_buffer_occupancy_new = lcid_buffer_occupancy_old;
if(lcid_buffer_occupancy_new){
buflen_remain =
buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE);
LOG_D(MAC,
"[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to "
"send (Transport Block size %d SDU Length Total %d , mac header len %d, buflen_remain %d )\n", //BSR byte before Tx=%d
module_idP, frameP, lcid, lcid_buffer_occupancy_new,
buflen, sdu_length_total,
total_rlc_pdu_header_len, buflen_remain); // ,nr_ue_mac_inst->scheduling_info.BSR_bytes[nr_ue_mac_inst->scheduling_info.LCGID[lcid]]
while(buflen_remain > 0 && lcid_buffer_occupancy_new){
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
mac->crnti,
eNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
lcid,
buflen_remain,
(char *)&ulsch_sdus[sdu_length_total],0,
0);
AssertFatal(buflen_remain >= sdu_lengths[num_sdus],
"LCID=%d RLC has segmented %d bytes but MAC has max=%d\n",
lcid, sdu_lengths[num_sdus], buflen_remain);
if (sdu_lengths[num_sdus]) {
sdu_length_total += sdu_lengths[num_sdus];
sdu_lcids[num_sdus] = lcid;
total_rlc_pdu_header_len += MAX_RLC_SDU_SUBHEADER_SIZE; //rlc_pdu_header_len_last;
//Update number of SDU
num_sdus++;
}
/* Get updated BO after multiplexing this PDU */
lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP,
mac->crnti,
eNB_index,
frameP,
subframe,
ENB_FLAG_NO,
lcid);
buflen_remain =
buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE);
}
}
}
// Generate ULSCH PDU
if (num_sdus>0) {
payload_offset = nr_generate_ulsch_pdu(ulsch_sdus,
ulsch_buffer, // mac header
num_sdus, // num sdus
sdu_lengths, // sdu length
sdu_lcids, // sdu lcid
0, // power_headroom
mac->crnti, // crnti
0, // truncated_bsr
0, // short_bsr
0, // long_bsr
0, // post_padding
buflen); // TBS in bytes
}
else
return 0;
// Padding: fill remainder of ULSCH with 0
if (buflen - payload_offset > 0){
for (int j = payload_offset; j < buflen; j++)
ulsch_buffer[j] = 0;
}
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_I(MAC, "Printing UL MAC payload UE side, payload_offset: %d \n", payload_offset);
for (int i = 0; i < buflen ; i++) {
//harq_process_ul_ue->a[i] = (unsigned char) rand();
//printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
printf("%02x ",(unsigned char)ulsch_buffer[i]);
}
printf("\n");
#endif
return 1;
}