Files
openairinterface5g/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
T
Melissa Elkadi 9322701ce4 Need a break if we queue a ul_tti_req based on PDU state
If we dont have this break we are trying to queue
the UL_TTI_REQ we just queued
2022-02-09 13:32:09 -08:00

1584 lines
62 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* \file NR_IF_Module.c
* \brief functions for NR UE FAPI-like interface
* \author R. Knopp, K.H. HSU
* \date 2018
* \version 0.1
* \company Eurecom / NTUST
* \email: knopp@eurecom.fr, kai-hsiang.hsu@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs_nr_UE.h"
#include "NR_IF_Module.h"
#include "NR_MAC_UE/mac_proto.h"
#include "assertions.h"
#include "NR_MAC_UE/mac_extern.h"
#include "SCHED_NR_UE/fapi_nr_ue_l1.h"
#include "executables/softmodem-common.h"
#include "openair2/RRC/NR_UE/rrc_proto.h"
#include "openair2/RRC/NR_UE/rrc_vars.h"
#include "openair2/GNB_APP/L1_nr_paramdef.h"
#include "openair2/GNB_APP/gnb_paramdef.h"
#include "targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
#include <stdio.h>
#define MAX_IF_MODULES 100
UL_IND_t *UL_INFO = NULL;
static eth_params_t stub_eth_params;
static nr_ue_if_module_t *nr_ue_if_module_inst[MAX_IF_MODULES];
static int ue_tx_sock_descriptor = -1;
static int ue_rx_sock_descriptor = -1;
static int g_harq_pid;
sem_t sfn_slot_semaphore;
queue_t nr_sfn_slot_queue;
queue_t nr_chan_param_queue;
queue_t nr_dl_tti_req_queue;
queue_t nr_tx_req_queue;
queue_t nr_ul_dci_req_queue;
queue_t nr_ul_tti_req_queue;
static slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT];
static int get_mcs_from_sinr(float sinr);
static int get_cqi_from_mcs(void);
static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index);
static bool did_drop_transport_block(int slot, uint16_t rnti);
static float get_bler_val(uint8_t mcs, int sinr);
static bool should_drop_transport_block(int slot, uint16_t rnti);
static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request);
static inline bool is_channel_modeling(void);
void nrue_init_standalone_socket(int tx_port, int rx_port)
{
{
struct sockaddr_in server_address;
int addr_len = sizeof(server_address);
memset(&server_address, 0, addr_len);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(tx_port);
int sd = socket(server_address.sin_family, SOCK_DGRAM, 0);
if (sd < 0)
{
LOG_E(MAC, "Socket creation error standalone PNF\n");
return;
}
if (inet_pton(server_address.sin_family, stub_eth_params.remote_addr, &server_address.sin_addr) <= 0)
{
LOG_E(MAC, "Invalid standalone PNF Address\n");
close(sd);
return;
}
// Using connect to use send() instead of sendto()
if (connect(sd, (struct sockaddr *)&server_address, addr_len) < 0)
{
LOG_E(MAC, "Connection to standalone PNF failed: %s\n", strerror(errno));
close(sd);
return;
}
assert(ue_tx_sock_descriptor == -1);
ue_tx_sock_descriptor = sd;
LOG_D(NR_RRC, "Successfully set up tx_socket in %s.\n", __FUNCTION__);
}
{
struct sockaddr_in server_address;
int addr_len = sizeof(server_address);
memset(&server_address, 0, addr_len);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(rx_port);
int sd = socket(server_address.sin_family, SOCK_DGRAM, 0);
if (sd < 0)
{
LOG_E(MAC, "Socket creation error standalone PNF\n");
return;
}
if (bind(sd, (struct sockaddr *)&server_address, addr_len) < 0)
{
LOG_E(MAC, "Connection to standalone PNF failed: %s\n", strerror(errno));
close(sd);
return;
}
assert(ue_rx_sock_descriptor == -1);
ue_rx_sock_descriptor = sd;
LOG_D(NR_RRC, "Successfully set up rx_socket in %s.\n", __FUNCTION__);
}
LOG_I(NR_RRC, "NRUE standalone socket info: tx_port %d rx_port %d on %s.\n",
tx_port, rx_port, stub_eth_params.remote_addr);
}
void send_nsa_standalone_msg(NR_UL_IND_t *UL_INFO, uint16_t msg_id)
{
switch(msg_id)
{
case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION:
{
char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
LOG_D(NR_MAC, "RACH header id :%d", UL_INFO->rach_ind.header.message_id);
int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->rach_ind, buffer, sizeof(buffer), NULL);
if (encoded_size <= 0)
{
LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size);
return;
}
LOG_I(NR_MAC, "NR_RACH_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size,
UL_INFO->rach_ind.sfn, UL_INFO->rach_ind.slot, UL_INFO->rach_ind.number_of_pdus);
if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0)
{
LOG_E(NR_MAC, "Send Proxy NR_UE failed\n");
return;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION:
{
char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
LOG_D(NR_MAC, "RX header id :%d", UL_INFO->rx_ind.header.message_id);
int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->rx_ind, buffer, sizeof(buffer), NULL);
if (encoded_size <= 0)
{
LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size);
return;
}
LOG_I(NR_MAC, "NR_RX_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size,
UL_INFO->rx_ind.sfn, UL_INFO->rx_ind.slot, UL_INFO->rx_ind.number_of_pdus);
if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0)
{
LOG_E(NR_MAC, "Send Proxy NR_UE failed\n");
return;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION:
{
char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
LOG_D(NR_MAC, "CRC header id :%d", UL_INFO->crc_ind.header.message_id);
int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->crc_ind, buffer, sizeof(buffer), NULL);
if (encoded_size <= 0)
{
LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size);
return;
}
LOG_I(NR_MAC, "NR_CRC_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size,
UL_INFO->crc_ind.sfn, UL_INFO->crc_ind.slot, UL_INFO->crc_ind.number_crcs);
if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0)
{
LOG_E(NR_MAC, "Send Proxy NR_UE failed\n");
return;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION:
{
char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
LOG_I(NR_MAC, "UCI header id :%d", UL_INFO->uci_ind.header.message_id);
int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->uci_ind, buffer, sizeof(buffer), NULL);
if (encoded_size <= 0)
{
LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size);
return;
}
LOG_I(NR_MAC, "NR_UCI_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size,
UL_INFO->uci_ind.sfn, UL_INFO->uci_ind.slot, UL_INFO->uci_ind.num_ucis);
if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0)
{
LOG_E(NR_MAC, "Send Proxy NR_UE failed\n");
return;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION:
break;
default:
break;
}
}
bool sfn_slot_matcher(void *wanted, void *candidate)
{
nfapi_p7_message_header_t *msg = candidate;
int sfn_sf = *(int*)wanted;
switch (msg->message_id)
{
case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION:
{
nfapi_nr_rach_indication_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
}
case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION:
{
nfapi_nr_rx_data_indication_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
}
case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION:
{
nfapi_nr_crc_indication_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
}
case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION:
{
nfapi_nr_uci_indication_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
}
case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST:
{
nfapi_nr_dl_tti_request_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
}
case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST:
{
nfapi_nr_tx_data_request_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
}
case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST:
{
nfapi_nr_ul_dci_request_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
}
case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST:
{
nfapi_nr_ul_tti_request_t *ind = candidate;
return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
}
default:
LOG_E(NR_MAC, "sfn_slot_match bad ID: %d\n", msg->message_id);
}
return false;
}
static void fill_dl_info_with_pdcch(fapi_nr_dci_indication_t *dci, nfapi_nr_dl_dci_pdu_t *rx_dci, int idx)
{
int num_bytes = (rx_dci->PayloadSizeBits + 7) / 8;
LOG_I(NR_PHY, "[%d, %d] PDCCH DCI (Payload) for rnti %x with PayloadSizeBits %d, num_bytes %d\n",
dci->SFN, dci->slot, rx_dci->RNTI, rx_dci->PayloadSizeBits, num_bytes);
for (int k = 0; k < num_bytes; k++)
{
LOG_I(NR_MAC, "PDCCH DCI PDU payload[%d] = %d\n", k, rx_dci->Payload[k]);
dci->dci_list[idx].payloadBits[k] = rx_dci->Payload[k];
}
dci->dci_list[idx].payloadSize = rx_dci->PayloadSizeBits;
dci->dci_list[idx].rnti = rx_dci->RNTI;
dci->number_of_dcis = idx + 1;
}
static void fill_mib_in_rx_ind(nfapi_nr_dl_tti_request_pdu_t *pdu_list, fapi_nr_rx_indication_t *rx_ind, int pdu_idx, int pdu_type)
{
AssertFatal(pdu_idx < sizeof(rx_ind->rx_indication_body) / sizeof(rx_ind->rx_indication_body[0]),
"pdu_index (%d) is greater than rx_indication_body size!\n", pdu_idx);
AssertFatal(pdu_idx == rx_ind->number_pdus, "Invalid pdu_idx %d!\n", pdu_idx);
LOG_D(NR_MAC, "Recevied an SSB and are filling rx_ind with the MIB!\n");
nfapi_nr_dl_tti_ssb_pdu_rel15_t *ssb_pdu = &pdu_list->ssb_pdu.ssb_pdu_rel15;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.cell_id = ssb_pdu->PhysCellId;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu = MALLOC(3 * sizeof(*rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu));
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[0] = (ssb_pdu->bchPayload) & 0xff;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[1] = (ssb_pdu->bchPayload >> 8) & 0xff;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[2] = (ssb_pdu->bchPayload >> 16) & 0xff;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.rsrp_dBm = ssb_pdu->ssbRsrp;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_index = ssb_pdu->SsbBlockIndex;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_length = pdu_list->PDUSize;
rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_start_subcarrier = ssb_pdu->SsbSubcarrierOffset;
rx_ind->rx_indication_body[pdu_idx].pdu_type = pdu_type;
rx_ind->number_pdus = pdu_idx + 1;
}
static bool is_my_dci(NR_UE_MAC_INST_t *mac, nfapi_nr_dl_dci_pdu_t *received_pdu)
{
/* For multiple UEs, we need to be able to filter the rx'd messages by
the RNTI. The filtering is different between NSA mode and SA mode.
NSA mode has a two step CFRA procedure and SA has a 4 step procedure.
We only need to check if the rx'd RNTI doesnt match the CRNTI if the RAR
has been processed already, in NSA mode.
In SA, depending on the RA state, we can have a SIB (0xffff), RAR (0x10b),
Msg3 (TC_RNTI) or an actual DCI message (CRNTI). When we get Msg3, the
MAC instance of the UE still has a CRNTI = 0. We should only check if the
CRNTI doesnt match the received RNTI in SA mode if Msg3 has been processed
already. Only once the RA procedure succeeds is the CRNTI value updated
to the TC_RNTI. */
if (get_softmodem_params()->nsa)
{
if (received_pdu->RNTI != mac->crnti &&
(received_pdu->RNTI != mac->ra.ra_rnti || mac->ra.RA_RAPID_found))
return false;
}
if (get_softmodem_params()->sa)
{
if (received_pdu->RNTI != mac->crnti && mac->ra.ra_state == RA_SUCCEEDED)
return false;
if (received_pdu->RNTI != mac->ra.t_crnti && mac->ra.ra_state == WAIT_CONTENTION_RESOLUTION)
return false;
if (received_pdu->RNTI != 0x10b && mac->ra.ra_state == WAIT_RAR)
return false;
if (received_pdu->RNTI != 0xFFFF && mac->ra.ra_state <= GENERATE_PREAMBLE)
return false;
}
return true;
}
static void copy_dl_tti_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_dl_tti_request_t *dl_tti_request)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id);
mac->nr_ue_emul_l1.expected_sib = false;
memset(mac->nr_ue_emul_l1.index_has_sib, 0, sizeof(mac->nr_ue_emul_l1.index_has_sib));
mac->nr_ue_emul_l1.expected_rar = false;
memset(mac->nr_ue_emul_l1.index_has_rar, 0, sizeof(mac->nr_ue_emul_l1.index_has_rar));
mac->nr_ue_emul_l1.expected_dci = false;
memset(mac->nr_ue_emul_l1.index_has_dci, 0, sizeof(mac->nr_ue_emul_l1.index_has_dci));
int pdu_idx = 0;
int num_pdus = dl_tti_request->dl_tti_request_body.nPDUs;
AssertFatal(num_pdus >= 0, "Invalid dl_tti_request number of PDUS\n");
for (int i = 0; i < num_pdus; i++)
{
nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i];
if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE)
{
LOG_I(NR_PHY, "[%d, %d] PDSCH PDU for rnti %x\n",
dl_tti_request->SFN, dl_tti_request->Slot, pdu_list->pdsch_pdu.pdsch_pdu_rel15.rnti);
}
if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE)
{
LOG_I(NR_PHY, "[%d, %d] PDCCH DCI PDU (Format for incoming PDSCH PDU)\n",
dl_tti_request->SFN, dl_tti_request->Slot);
uint16_t num_dcis = pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci;
if (num_dcis > 0)
{
if (!dl_info->dci_ind)
{
dl_info->dci_ind = CALLOC(1, sizeof(fapi_nr_dci_indication_t));
}
dl_info->dci_ind->SFN = dl_tti_request->SFN;
dl_info->dci_ind->slot = dl_tti_request->Slot;
AssertFatal(num_dcis <= sizeof(dl_info->dci_ind->dci_list) / sizeof(dl_info->dci_ind->dci_list[0]),
"The number of DCIs is greater than dci_list");
for (int j = 0; j < num_dcis; j++)
{
nfapi_nr_dl_dci_pdu_t *dci_pdu_list = &pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu[j];
if (!is_my_dci(mac, dci_pdu_list))
{
continue;
}
fill_dl_info_with_pdcch(dl_info->dci_ind, dci_pdu_list, pdu_idx);
if (dci_pdu_list->RNTI == 0xffff)
{
mac->nr_ue_emul_l1.expected_sib = true;
mac->nr_ue_emul_l1.index_has_sib[j] = true;
LOG_D(NR_MAC, "Setting index_has_sib[%d] = true\n", j);
}
else if (dci_pdu_list->RNTI == mac->ra.ra_rnti)
{
mac->nr_ue_emul_l1.expected_rar = true;
mac->nr_ue_emul_l1.index_has_rar[j] = true;
LOG_D(NR_MAC, "Setting index_has_rar[%d] = true\n", j);
}
else
{
mac->nr_ue_emul_l1.expected_dci = true;
mac->nr_ue_emul_l1.index_has_dci[j] = true;
LOG_D(NR_MAC, "Setting index_has_dci[%d] = true\n", j);
}
pdu_idx++;
}
}
}
if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE)
{
/* If we get a MIB, we want to handle it right away and then come back.
The MIB and SIB come in the same dl_tti_req but the MIB should be
processed first and then the DCI and payload of the SIB1 can be
processed. The MIB should be handled first and then the rx_ind
will be freed after handling. This is why the PDU index will
always be zero for the RX_IND becasue we should not have more than
one MIB. */
if (!dl_info->rx_ind)
{
dl_info->rx_ind = CALLOC(1, sizeof(*dl_info->rx_ind));
}
fapi_nr_rx_indication_t *rx_ind = dl_info->rx_ind;
rx_ind->sfn = dl_tti_request->SFN;
rx_ind->slot = dl_tti_request->Slot;
fill_mib_in_rx_ind(pdu_list, rx_ind, 0, FAPI_NR_RX_PDU_TYPE_SSB);
NR_UL_TIME_ALIGNMENT_t ul_time_alignment;
memset(&ul_time_alignment, 0, sizeof(ul_time_alignment));
nr_ue_dl_indication(&mac->dl_info, &ul_time_alignment);
}
}
dl_info->slot = dl_tti_request->Slot;
dl_info->frame = dl_tti_request->SFN;
}
static void fill_rx_ind(nfapi_nr_pdu_t *pdu_list, fapi_nr_rx_indication_t *rx_ind, int pdu_idx, int pdu_type)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
AssertFatal(pdu_list->num_TLV < sizeof(pdu_list->TLVs) / sizeof(pdu_list->TLVs[0]), "Num TLVs exceeds TLV array size");
int length = 0;
for (int j = 0; j < pdu_list->num_TLV; j++)
{
length += pdu_list->TLVs[j].length;
}
LOG_I(NR_PHY, "Elkadi %s: num_tlv %d and length %d, pdu index %d\n",
__FUNCTION__, pdu_list->num_TLV, length, pdu_idx);
uint8_t *pdu = malloc(length);
AssertFatal(pdu != NULL, "%s: Out of memory in malloc", __FUNCTION__);
rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.pdu = pdu;
for (int j = 0; j < pdu_list->num_TLV; j++)
{
const uint32_t *ptr;
if (pdu_list->TLVs[j].tag)
ptr = pdu_list->TLVs[j].value.ptr;
else
ptr = pdu_list->TLVs[j].value.direct;
memcpy(pdu, ptr, pdu_list->TLVs[j].length);
pdu += pdu_list->TLVs[j].length;
}
bool ack_nack = true;
if (mac->ra.ra_state >= RA_SUCCEEDED && should_drop_transport_block(rx_ind->slot, mac->crnti))
{
ack_nack = false;
}
rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.ack_nack = ack_nack;
rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.pdu_length = length;
rx_ind->rx_indication_body[pdu_idx].pdu_type = pdu_type;
}
static void copy_tx_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_tx_data_request_t *tx_data_request)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id);
int num_pdus = tx_data_request->Number_of_PDUs;
AssertFatal(num_pdus >= 0, "Invalid tx_data_request number of PDUS\n");
if (!dl_info->rx_ind)
{
dl_info->rx_ind = CALLOC(num_pdus, sizeof(fapi_nr_rx_indication_t));
}
AssertFatal(dl_info->rx_ind != NULL, "%s: Out of memory in calloc", __FUNCTION__);
fapi_nr_rx_indication_t *rx_ind = dl_info->rx_ind;
rx_ind->sfn = tx_data_request->SFN;
rx_ind->slot = tx_data_request->Slot;
int pdu_idx = 0;
for (int i = 0; i < num_pdus; i++)
{
nfapi_nr_pdu_t *pdu_list = &tx_data_request->pdu_list[i];
if (mac->nr_ue_emul_l1.index_has_sib[i])
{
AssertFatal(!get_softmodem_params()->nsa,
"Should not be processing SIB in NSA mode, something bad happened\n");
fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_SIB);
pdu_idx++;
}
else if (mac->nr_ue_emul_l1.index_has_rar[i])
{
fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_RAR);
pdu_idx++;
}
else if (mac->nr_ue_emul_l1.index_has_dci[i])
{
fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_DLSCH);
pdu_idx++;
}
else
{
LOG_D(NR_MAC, "mac->nr_ue_emul_l1.index_has_dci[%d] = 0, so this index contained a DCI for a different UE\n", i);
}
}
dl_info->slot = tx_data_request->Slot;
dl_info->frame = tx_data_request->SFN;
dl_info->rx_ind->number_pdus = pdu_idx;
}
void free_uci_inds(nfapi_nr_uci_indication_t *uci_ind)
{
for (int k = 0; k < uci_ind->num_ucis; k++)
{
if (uci_ind->uci_list[k].pdu_type == NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE)
{
nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu_0_1 = &uci_ind->uci_list[k].pucch_pdu_format_0_1;
free(pdu_0_1->sr);
pdu_0_1->sr = NULL;
if (pdu_0_1->harq)
{
free(pdu_0_1->harq->harq_list);
pdu_0_1->harq->harq_list = NULL;
}
free(pdu_0_1->harq);
pdu_0_1->harq = NULL;
}
if (uci_ind->uci_list[k].pdu_type == NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE)
{
nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4 = &uci_ind->uci_list[k].pucch_pdu_format_2_3_4;
free(pdu_2_3_4->sr.sr_payload);
pdu_2_3_4->sr.sr_payload = NULL;
free(pdu_2_3_4->harq.harq_payload);
pdu_2_3_4->harq.harq_payload = NULL;
}
}
free(uci_ind->uci_list);
uci_ind->uci_list = NULL;
free(uci_ind);
uci_ind = NULL;
}
static void copy_ul_dci_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_ul_dci_request_t *ul_dci_req)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id);
int pdu_idx = 0;
int num_pdus = ul_dci_req->numPdus;
AssertFatal(num_pdus >= 0, "Invalid ul_dci_request number of PDUS\n");
for (int i = 0; i < num_pdus; i++)
{
nfapi_nr_ul_dci_request_pdus_t *pdu_list = &ul_dci_req->ul_dci_pdu_list[i];
AssertFatal(pdu_list->PDUType == 0, "ul_dci_req pdu type != PUCCH");
LOG_I(NR_PHY, "[%d %d] PUCCH PDU in ul_dci for rnti %x and numDLDCI = %d\n",
ul_dci_req->SFN, ul_dci_req->Slot, pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu->RNTI,
pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci);
uint16_t num_dci = pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci;
if (num_dci > 0)
{
if (!dl_info->dci_ind)
{
dl_info->dci_ind = CALLOC(1, sizeof(fapi_nr_dci_indication_t));
}
AssertFatal(dl_info->dci_ind != NULL, "%s: Out of memory in calloc", __FUNCTION__);
dl_info->dci_ind->SFN = ul_dci_req->SFN;
dl_info->dci_ind->slot = ul_dci_req->Slot;
AssertFatal(num_dci < sizeof(dl_info->dci_ind->dci_list) / sizeof(dl_info->dci_ind->dci_list[0]), "The number of DCIs is greater than dci_list");
for (int j = 0; j < num_dci; j++)
{
nfapi_nr_dl_dci_pdu_t *dci_pdu_list = &pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu[j];
if (dci_pdu_list->RNTI != mac->crnti)
{
LOG_D(NR_MAC, "dci_pdu_list->RNTI (%x) != mac->crnti (%x)\n", dci_pdu_list->RNTI, mac->crnti);
continue;
}
fill_dl_info_with_pdcch(dl_info->dci_ind, dci_pdu_list, pdu_idx);
pdu_idx++;
}
}
}
dl_info->frame = ul_dci_req->SFN;
dl_info->slot = ul_dci_req->Slot;
}
static bool send_crc_ind_and_rx_ind(int sfn_slot)
{
bool sent_crc_rx = true;
LOG_I(NR_MAC, "Melissa, This is the num items in crc %d and rx %d\n", nr_crc_ind_queue.num_items, nr_rx_ind_queue.num_items);
nfapi_nr_rx_data_indication_t *rx_ind = unqueue_matching(&nr_rx_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
nfapi_nr_crc_indication_t *crc_ind = unqueue_matching(&nr_crc_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
if (crc_ind && crc_ind->number_crcs > 0)
{
NR_UL_IND_t UL_INFO = {
.crc_ind = *crc_ind,
};
send_nsa_standalone_msg(&UL_INFO, crc_ind->header.message_id);
free(crc_ind->crc_list);
free(crc_ind);
}
if (rx_ind && rx_ind->number_of_pdus > 0)
{
NR_UL_IND_t UL_INFO = {
.rx_ind = *rx_ind,
};
send_nsa_standalone_msg(&UL_INFO, rx_ind->header.message_id);
free(rx_ind->pdu_list);
free(rx_ind);
}
else
{
sent_crc_rx = false;
}
return sent_crc_rx;
}
static void copy_ul_tti_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_ul_tti_request_t *ul_tti_req)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id);
int num_pdus = ul_tti_req->n_pdus;
int sfn_slot = NFAPI_SFNSLOT2HEX(ul_tti_req->SFN, ul_tti_req->Slot);
AssertFatal(num_pdus >= 0, "Invalid ul_tti_request number of PDUS\n");
AssertFatal(num_pdus <= sizeof(ul_tti_req->pdus_list) / sizeof(ul_tti_req->pdus_list[0]),
"Too many pdus %d in ul_tti_req\n", num_pdus);
if (!send_crc_ind_and_rx_ind(sfn_slot))
{
LOG_E(NR_MAC, "CRC_RX ind not sent\n");
if (!put_queue(&nr_ul_tti_req_queue, ul_tti_req))
{
LOG_E(NR_PHY, "put_queue failed for ul_tti_req.\n");
free(ul_tti_req);
ul_tti_req = NULL;
}
return;
}
free(ul_tti_req);
}
static void fill_dci_from_dl_config(nr_downlink_indication_t*dl_ind, fapi_nr_dl_config_request_t *dl_config)
{
if (!dl_ind->dci_ind)
{
return;
}
AssertFatal(dl_config->number_pdus < sizeof(dl_config->dl_config_list) / sizeof(dl_config->dl_config_list[0]),
"Too many dl_config pdus %d", dl_config->number_pdus);
for (int i = 0; i < dl_config->number_pdus; i++)
{
LOG_I(PHY, "In %s: filling DCI with a total of %d total DL PDUs (dl_config %p) \n",
__FUNCTION__, dl_config->number_pdus, dl_config);
fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15_dci = &dl_config->dl_config_list[i].dci_config_pdu.dci_config_rel15;
int num_dci_options = rel15_dci->num_dci_options;
if (num_dci_options <= 0)
{
LOG_I(NR_MAC, "num_dci_opts = %d for pdu[%d] in dl_config_list\n", rel15_dci->num_dci_options, i);
}
AssertFatal(num_dci_options <= sizeof(rel15_dci->dci_length_options) / sizeof(rel15_dci->dci_length_options[0]),
"num_dci_options %d > dci_length_options array\n", num_dci_options);
AssertFatal(num_dci_options <= sizeof(rel15_dci->dci_format_options) / sizeof(rel15_dci->dci_format_options[0]),
"num_dci_options %d > dci_format_options array\n", num_dci_options);
for (int j = 0; j < num_dci_options; j++)
{
int num_dcis = dl_ind->dci_ind->number_of_dcis;
AssertFatal(num_dcis <= sizeof(dl_ind->dci_ind->dci_list) / sizeof(dl_ind->dci_ind->dci_list[0]),
"dl_config->number_pdus %d > dci_ind->dci_list array\n", num_dcis);
for (int k = 0; k < num_dcis; k++)
{
LOG_D(NR_PHY, "Received len %d, length options[%d] %d, format assigned %d, format options[%d] %d\n",
dl_ind->dci_ind->dci_list[k].payloadSize, j, rel15_dci->dci_length_options[j],
dl_ind->dci_ind->dci_list[k].dci_format, j, rel15_dci->dci_format_options[j]);
if (rel15_dci->dci_length_options[j] == dl_ind->dci_ind->dci_list[k].payloadSize)
{
dl_ind->dci_ind->dci_list[k].dci_format = rel15_dci->dci_format_options[j];
LOG_I(NR_PHY, "format assigned dl_ind->dci_ind->dci_list[k].dci_format %d\n",
dl_ind->dci_ind->dci_list[k].dci_format);
int CCEind = rel15_dci->CCE[j];
int L = rel15_dci->L[j];
dl_ind->dci_ind->dci_list[k].n_CCE = CCEind;
dl_ind->dci_ind->dci_list[k].N_CCE = L;
}
}
}
}
}
void check_and_process_dci(nfapi_nr_dl_tti_request_t *dl_tti_request,
nfapi_nr_tx_data_request_t *tx_data_request,
nfapi_nr_ul_dci_request_t *ul_dci_request,
nfapi_nr_ul_tti_request_t *ul_tti_request)
{
frame_t frame = 0;
int slot = 0;
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
if (pthread_mutex_lock(&mac->mutex_dl_info)) abort();
if (dl_tti_request)
{
frame = dl_tti_request->SFN;
slot = dl_tti_request->Slot;
LOG_I(NR_PHY, "[%d, %d] dl_tti_request\n", frame, slot);
copy_dl_tti_req_to_dl_info(&mac->dl_info, dl_tti_request);
}
/* This checks if the previously recevied DCI matches our current RNTI
value. The assumption is that if the DCI matches our RNTI, then the
incoming tx_data_request is also destined for the current UE. If the
RAR hasn't been processed yet, we do not want to be filtering the
tx_data_requests. */
if (tx_data_request && (mac->nr_ue_emul_l1.expected_sib ||
mac->nr_ue_emul_l1.expected_rar ||
mac->nr_ue_emul_l1.expected_dci))
{
frame = tx_data_request->SFN;
slot = tx_data_request->Slot;
LOG_I(NR_PHY, "[%d, %d] PDSCH in tx_request\n", frame, slot);
copy_tx_data_req_to_dl_info(&mac->dl_info, tx_data_request);
}
else if (ul_dci_request)
{
frame = ul_dci_request->SFN;
slot = ul_dci_request->Slot;
LOG_I(NR_PHY, "[%d, %d] ul_dci_request\n", frame, slot);
copy_ul_dci_data_req_to_dl_info(&mac->dl_info, ul_dci_request);
}
else if (ul_tti_request)
{
frame = ul_tti_request->SFN;
slot = ul_tti_request->Slot;
LOG_I(NR_PHY, "[%d, %d] ul_tti_request\n", frame, slot);
copy_ul_tti_data_req_to_dl_info(&mac->dl_info, ul_tti_request);
}
else
{
if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort();
LOG_D(NR_MAC, "All indications were NULL in %s\n", __FUNCTION__);
return;
}
NR_UL_TIME_ALIGNMENT_t ul_time_alignment;
memset(&ul_time_alignment, 0, sizeof(ul_time_alignment));
fill_dci_from_dl_config(&mac->dl_info, &mac->dl_config_request);
nr_ue_dl_indication(&mac->dl_info, &ul_time_alignment);
if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort();
// If we filled dl_info AFTER we got the slot indication, we want to check if we should fill tx_req:
nr_uplink_indication_t ul_info;
memset(&ul_info, 0, sizeof(ul_info));
int slots_per_frame = 20; //30 kHZ subcarrier spacing
int slot_ahead = 2; // TODO: Make this dynamic
ul_info.frame_rx = frame;
ul_info.slot_rx = slot;
ul_info.slot_tx = (slot + slot_ahead) % slots_per_frame;
ul_info.frame_tx = (ul_info.slot_rx + slot_ahead >= slots_per_frame) ? ul_info.frame_rx + 1 : ul_info.frame_rx;
ul_info.ue_sched_mode = SCHED_ALL;
if (mac->scc || mac->scc_SIB)
{
if (is_nr_UL_slot(mac->scc ?
mac->scc->tdd_UL_DL_ConfigurationCommon :
mac->scc_SIB->tdd_UL_DL_ConfigurationCommon,
ul_info.slot_tx,
mac->frame_type)) {
LOG_I(NR_MAC, "Slot %d. calling nr_ue_ul_ind() from %s\n", ul_info.slot_tx, __FUNCTION__);
nr_ue_ul_indication(&ul_info);
}
}
}
void save_nr_measurement_info(nfapi_nr_dl_tti_request_t *dl_tti_request)
{
int num_pdus = dl_tti_request->dl_tti_request_body.nPDUs;
char buffer[MAX_MESSAGE_SIZE];
if (num_pdus <= 0)
{
LOG_E(NR_PHY, "%s: dl_tti_request number of PDUS <= 0\n", __FUNCTION__);
abort();
}
LOG_D(NR_PHY, "%s: dl_tti_request number of PDUS: %d\n", __FUNCTION__, num_pdus);
for (int i = 0; i < num_pdus; i++)
{
nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i];
if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE)
{
LOG_D(NR_PHY, "Cell_id: %d, the ssb_block_idx %d, sc_offset: %d and payload %d\n",
pdu_list->ssb_pdu.ssb_pdu_rel15.PhysCellId,
pdu_list->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex,
pdu_list->ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset,
pdu_list->ssb_pdu.ssb_pdu_rel15.bchPayload);
pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp = 60;
LOG_D(NR_RRC, "Setting pdulist[%d].ssbRsrp to %d\n", i, pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp);
}
}
size_t pack_len = nfapi_nr_p7_message_pack((void *)dl_tti_request,
buffer,
sizeof(buffer),
NULL);
if (pack_len < 0)
{
LOG_E(NR_PHY, "%s: Error packing nr p7 message.\n", __FUNCTION__);
}
nsa_sendmsg_to_lte_ue(buffer, pack_len, NR_UE_RRC_MEASUREMENT);
LOG_A(NR_RRC, "Populated NR_UE_RRC_MEASUREMENT information and sent to LTE UE\n");
}
static void enqueue_nr_nfapi_msg(void *buffer, ssize_t len, nfapi_p7_message_header_t header)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
switch (header.message_id)
{
case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST:
{
nfapi_nr_dl_tti_request_t *dl_tti_request = MALLOC(sizeof(*dl_tti_request));
if (nfapi_nr_p7_message_unpack(buffer, len, dl_tti_request,
sizeof(*dl_tti_request), NULL) < 0)
{
LOG_E(NR_PHY, "Message dl_tti_request failed to unpack\n");
break;
}
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST message in sfn/slot %d %d. \n",
dl_tti_request->SFN, dl_tti_request->Slot);
if (is_channel_modeling())
save_pdsch_pdu_for_crnti(dl_tti_request);
if (!put_queue(&nr_dl_tti_req_queue, dl_tti_request))
{
LOG_E(NR_PHY, "put_queue failed for dl_tti_request.\n");
free(dl_tti_request);
dl_tti_request = NULL;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST:
{
nfapi_nr_tx_data_request_t *tx_data_request = MALLOC(sizeof(*tx_data_request));
if (nfapi_nr_p7_message_unpack(buffer, len, tx_data_request,
sizeof(*tx_data_request), NULL) < 0)
{
LOG_E(NR_PHY, "Message tx_data_request failed to unpack\n");
break;
}
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST message in SFN/slot %d %d. \n",
tx_data_request->SFN, tx_data_request->Slot);
if (!put_queue(&nr_tx_req_queue, tx_data_request))
{
LOG_E(NR_PHY, "put_queue failed for tx_request.\n");
free(tx_data_request);
tx_data_request = NULL;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST:
{
nfapi_nr_ul_dci_request_t *ul_dci_request = MALLOC(sizeof(*ul_dci_request));
if (nfapi_nr_p7_message_unpack(buffer, len, ul_dci_request,
sizeof(*ul_dci_request), NULL) < 0)
{
LOG_E(NR_PHY, "Message ul_dci_request failed to unpack\n");
break;
}
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST message in SFN/slot %d %d. \n",
ul_dci_request->SFN, ul_dci_request->Slot);
if (!put_queue(&nr_ul_dci_req_queue, ul_dci_request))
{
LOG_E(NR_PHY, "put_queue failed for ul_dci_request.\n");
free(ul_dci_request);
ul_dci_request = NULL;
}
break;
}
case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST:
{
nfapi_nr_ul_tti_request_t *ul_tti_request = MALLOC(sizeof(*ul_tti_request));
if (nfapi_nr_p7_message_unpack(buffer, len, ul_tti_request,
sizeof(*ul_tti_request), NULL) < 0)
{
LOG_E(NR_PHY, "Message ul_tti_request failed to unpack\n");
break;
}
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST message in SFN/slot %d %d.\n",
ul_tti_request->SFN, ul_tti_request->Slot);
for (int i = 0; i < ul_tti_request->n_pdus; i++) {
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST pdu_type %d, ra_state %d.\n",
ul_tti_request->pdus_list[i].pdu_type, mac->ra.ra_state);
if (ul_tti_request->pdus_list[i].pdu_type == 1 &&
mac->ra.ra_state >= RA_SUCCEEDED) {
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST that were queueing with rnti %x!\n",
ul_tti_request->pdus_list[i].pucch_pdu.rnti);
if (!put_queue(&nr_ul_tti_req_queue, ul_tti_request))
{
LOG_I(NR_PHY, "put_queue failed for ul_tti_request, calling put_queue_replace.\n");
nfapi_nr_ul_tti_request_t *evicted_ul_tti_req = put_queue_replace(&nr_ul_tti_req_queue, ul_tti_request);
free(evicted_ul_tti_req);
}
break;
}
else if (mac->ra.ra_state < RA_SUCCEEDED) {
LOG_I(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST before RA_SUCEEDED that were queueing with rnti %x!\n",
ul_tti_request->pdus_list[i].pucch_pdu.rnti);
if (!put_queue(&nr_ul_tti_req_queue, ul_tti_request))
{
LOG_I(NR_PHY, "put_queue failed for ul_tti_request, calling put_queue_replace.\n");
nfapi_nr_ul_tti_request_t *evicted_ul_tti_req = put_queue_replace(&nr_ul_tti_req_queue, ul_tti_request);
free(evicted_ul_tti_req);
}
break;
}
}
break;
}
default:
LOG_E(NR_PHY, "Invalid nFAPI message. Header ID %d\n",
header.message_id);
break;
}
return;
}
static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request)
{
int count_sent = 0;
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
int number_of_pdu = dl_tti_request->dl_tti_request_body.nPDUs;
if (number_of_pdu <= 0)
{
LOG_E(NR_MAC, "%s: dl_tti_request pdu size <= 0\n", __FUNCTION__);
abort();
}
for (int i = 0; i < number_of_pdu; i++)
{
const nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i];
if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE)
{
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = &pdu_list->pdsch_pdu.pdsch_pdu_rel15;
if (pdsch_pdu->rnti == mac->crnti && mac->ra.ra_state == RA_SUCCEEDED)
{
read_channel_param(pdsch_pdu, dl_tti_request->Slot, count_sent);
count_sent++;
LOG_D(NR_MAC, "pdsch_pdu->rnti %x mac->crnti %x mac->ra.ra_state %d count_sent %d\n",
pdsch_pdu->rnti, mac->crnti, mac->ra.ra_state, count_sent);
}
}
}
}
void *nrue_standalone_pnf_task(void *context)
{
struct sockaddr_in server_address;
socklen_t addr_len = sizeof(server_address);
int sd = ue_rx_sock_descriptor;
assert(sd > 0);
char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE];
LOG_I(NR_RRC, "Successfully started %s.\n", __FUNCTION__);
while (true)
{
ssize_t len = recvfrom(sd, buffer, sizeof(buffer), MSG_TRUNC, (struct sockaddr *)&server_address, &addr_len);
if (len == -1)
{
LOG_E(NR_PHY, "reading from standalone pnf sctp socket failed \n");
continue;
}
if (len > sizeof(buffer))
{
LOG_E(NR_PHY, "%s(%d). Message truncated. %zd\n", __FUNCTION__, __LINE__, len);
continue;
}
if (len == sizeof(uint16_t))
{
uint16_t *sfn_slot = CALLOC(1, sizeof(*sfn_slot));
memcpy(sfn_slot, buffer, sizeof(*sfn_slot));
LOG_I(NR_PHY, "Received from proxy sfn %d slot %d\n",
NFAPI_SFNSLOT2SFN(*sfn_slot), NFAPI_SFNSLOT2SLOT(*sfn_slot));
if (!put_queue(&nr_sfn_slot_queue, sfn_slot))
{
LOG_E(NR_PHY, "put_queue failed for sfn slot.\n");
}
if (sem_post(&sfn_slot_semaphore) != 0)
{
LOG_E(NR_PHY, "sem_post() error\n");
abort();
}
}
else if (len == sizeof(nr_phy_channel_params_t))
{
nr_phy_channel_params_t *ch_info = CALLOC(1, sizeof(*ch_info));
memcpy(ch_info, buffer, sizeof(*ch_info));
slot_rnti_mcs[NFAPI_SFNSLOT2SLOT(ch_info->sfn_slot)].sinr = ch_info->sinr;
LOG_D(NR_PHY, "Received_SINR = %f, sfn:slot %d:%d\n",
ch_info->sinr, NFAPI_SFNSLOT2SFN(ch_info->sfn_slot), NFAPI_SFNSLOT2SLOT(ch_info->sfn_slot));
if (!put_queue(&nr_chan_param_queue, ch_info))
{
LOG_E(NR_PHY, "put_queue failed for sfn slot.\n");
}
if (sem_post(&sfn_slot_semaphore) != 0)
{
LOG_E(MAC, "sem_post() error\n");
abort();
}
}
else
{
nfapi_p7_message_header_t header;
if (nfapi_p7_message_header_unpack(buffer, len, &header, sizeof(header), NULL) < 0)
{
LOG_E(NR_PHY, "Header unpack failed for nrue_standalone pnf\n");
continue;
}
enqueue_nr_nfapi_msg(buffer, len, header);
}
} //while(true)
}
// L2 Abstraction Layer
int handle_bcch_bch(module_id_t module_id, int cc_id,
unsigned int gNB_index, uint8_t *pduP,
unsigned int additional_bits,
uint32_t ssb_index, uint32_t ssb_length,
uint16_t ssb_start_subcarrier, uint16_t cell_id){
return nr_ue_decode_mib(module_id,
cc_id,
gNB_index,
additional_bits,
ssb_length, // Lssb = 64 is not support
ssb_index,
pduP,
ssb_start_subcarrier,
cell_id);
}
// L2 Abstraction Layer
int handle_bcch_dlsch(module_id_t module_id, int cc_id, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, uint32_t pdu_len){
return nr_ue_decode_BCCH_DL_SCH(module_id, cc_id, gNB_index, ack_nack, pduP, pdu_len);
}
// L2 Abstraction Layer
int handle_dci(module_id_t module_id, int cc_id, unsigned int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci){
return nr_ue_process_dci_indication_pdu(module_id, cc_id, gNB_index, frame, slot, dci);
}
// L2 Abstraction Layer
// Note: sdu should always be processed because data and timing advance updates are transmitted by the UE
int8_t handle_dlsch(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment, int pdu_id){
dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid = g_harq_pid;
update_harq_status(dl_info->module_id,
dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid,
dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack);
if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack)
nr_ue_send_sdu(dl_info, ul_time_alignment, pdu_id);
return 0;
}
void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nack) {
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_pid];
if (current_harq->active) {
current_harq->ack = ack_nack;
current_harq->ack_received = true;
LOG_D(PHY,"Updating harq_status for harq_id %d,ack/nak %d\n",harq_pid,current_harq->ack);
}
else {
//shouldn't get here
LOG_E(MAC, "Trying to process acknack for an inactive harq process (%d)\n", harq_pid);
}
}
int nr_ue_ul_indication(nr_uplink_indication_t *ul_info){
NR_UE_L2_STATE_t ret;
module_id_t module_id = ul_info->module_id;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
if (ul_info->ue_sched_mode == ONLY_PUSCH) {
ret = nr_ue_scheduler(NULL, ul_info);
return 0;
}
if (ul_info->ue_sched_mode == SCHED_ALL) {
ret = nr_ue_scheduler(NULL, ul_info);
}
else
LOG_D(NR_MAC, "In %s():%d not calling scheduler. sched mode = %d and mac->ra.ra_state = %d\n",
__FUNCTION__, __LINE__, ul_info->ue_sched_mode, mac->ra.ra_state);
NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon = mac->scc != NULL ? mac->scc->tdd_UL_DL_ConfigurationCommon : mac->scc_SIB->tdd_UL_DL_ConfigurationCommon;
if (is_nr_UL_slot(tdd_UL_DL_ConfigurationCommon, ul_info->slot_tx, mac->frame_type) && !get_softmodem_params()->phy_test)
nr_ue_prach_scheduler(module_id, ul_info->frame_tx, ul_info->slot_tx, ul_info->thread_id);
LOG_I(NR_MAC, "In %s():%d calling nr_ue_pucch_scheduler in %d.%d\n",
__FUNCTION__, __LINE__, ul_info->frame_tx, ul_info->slot_tx);
if (is_nr_UL_slot(tdd_UL_DL_ConfigurationCommon, ul_info->slot_tx, mac->frame_type) &&
!get_softmodem_params()->emulate_l1)
nr_ue_pucch_scheduler(module_id, ul_info->frame_tx, ul_info->slot_tx, ul_info->thread_id);
switch(ret){
case UE_CONNECTION_OK:
break;
case UE_CONNECTION_LOST:
break;
case UE_PHY_RESYNCH:
break;
case UE_PHY_HO_PRACH:
break;
default:
break;
}
return 0;
}
int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment){
uint32_t ret_mask = 0x0;
module_id_t module_id = dl_info->module_id;
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
fapi_nr_dl_config_request_t *dl_config = &mac->dl_config_request;
if ((!dl_info->dci_ind && !dl_info->rx_ind)) {
// UL indication to schedule DCI reception
nr_ue_scheduler(dl_info, NULL);
} else {
// UL indication after reception of DCI or DL PDU
if (dl_info && dl_info->dci_ind && dl_info->dci_ind->number_of_dcis) {
LOG_D(MAC,"[L2][IF MODULE][DL INDICATION][DCI_IND]\n");
for (int i = 0; i < dl_info->dci_ind->number_of_dcis; i++) {
fapi_nr_dci_indication_pdu_t *dci_index = dl_info->dci_ind->dci_list+i;
LOG_I(MAC,">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d, format %d, harq_pid %d\n",
i,
dl_info->dci_ind->number_of_dcis,
dci_index->dci_format,
mac->def_dci_pdu_rel15[dci_index->dci_format].harq_pid);
nr_scheduled_response_t scheduled_response;
int8_t ret = handle_dci(dl_info->module_id,
dl_info->cc_id,
dl_info->gNB_index,
dl_info->frame,
dl_info->slot,
dci_index);
/* The check below filters out UL_DCIs (format 7) which are being processed as DL_DCIs. */
if (dci_index->dci_format == 7 && mac->ra.ra_state == RA_SUCCEEDED) {
LOG_I(NR_MAC, "We are filtering a UL_DCI to prevent it from being treated like a DL_DCI\n");
break;
}
dci_pdu_rel15_t *def_dci_pdu_rel15 = &mac->def_dci_pdu_rel15[dci_index->dci_format];
g_harq_pid = def_dci_pdu_rel15->harq_pid;
LOG_D(NR_MAC, "Setting harq_pid = %d and dci_index = %d (based on format)\n", g_harq_pid, dci_index->dci_format);
ret_mask |= (ret << FAPI_NR_DCI_IND);
if (ret >= 0) {
AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is NULL!\n" );
AssertFatal( nr_ue_if_module_inst[module_id]->scheduled_response != NULL, "scheduled_response is NULL!\n" );
fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, dl_info->module_id, dl_info->cc_id, dl_info->frame, dl_info->slot, dl_info->thread_id);
nr_ue_if_module_inst[module_id]->scheduled_response(&scheduled_response);
}
//memset(def_dci_pdu_rel15, 0, sizeof(*def_dci_pdu_rel15));
}
free(dl_info->dci_ind);
dl_info->dci_ind = NULL;
}
if (dl_info->rx_ind != NULL) {
for (int i=0; i<dl_info->rx_ind->number_pdus; ++i) {
LOG_D(MAC, "In %s sending DL indication to MAC. 1 PDU type %d of %d total number of PDUs \n",
__FUNCTION__,
dl_info->rx_ind->rx_indication_body[i].pdu_type,
dl_info->rx_ind->number_pdus);
switch(dl_info->rx_ind->rx_indication_body[i].pdu_type){
case FAPI_NR_RX_PDU_TYPE_SSB:
mac->ssb_rsrp_dBm = (dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.rsrp_dBm;
ret_mask |= (handle_bcch_bch(dl_info->module_id, dl_info->cc_id, dl_info->gNB_index,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.pdu,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.additional_bits,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_index,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_length,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.ssb_start_subcarrier,
(dl_info->rx_ind->rx_indication_body+i)->ssb_pdu.cell_id)) << FAPI_NR_RX_PDU_TYPE_SSB;
break;
case FAPI_NR_RX_PDU_TYPE_SIB:
ret_mask |= (handle_bcch_dlsch(dl_info->module_id,
dl_info->cc_id, dl_info->gNB_index,
(dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.ack_nack,
(dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.pdu,
(dl_info->rx_ind->rx_indication_body+i)->pdsch_pdu.pdu_length)) << FAPI_NR_RX_PDU_TYPE_SIB;
break;
case FAPI_NR_RX_PDU_TYPE_DLSCH:
ret_mask |= (handle_dlsch(dl_info, ul_time_alignment, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH;
break;
case FAPI_NR_RX_PDU_TYPE_RAR:
ret_mask |= (handle_dlsch(dl_info, ul_time_alignment, i)) << FAPI_NR_RX_PDU_TYPE_RAR;
break;
default:
break;
}
}
free(dl_info->rx_ind);
dl_info->rx_ind = NULL;
}
//clean up nr_downlink_indication_t *dl_info
free(dl_info->dci_ind);
dl_info->dci_ind = NULL;
free(dl_info->rx_ind);
dl_info->rx_ind = NULL;
}
return 0;
}
nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id){
if (nr_ue_if_module_inst[module_id] == NULL) {
nr_ue_if_module_inst[module_id] = (nr_ue_if_module_t *)malloc(sizeof(nr_ue_if_module_t));
memset((void*)nr_ue_if_module_inst[module_id],0,sizeof(nr_ue_if_module_t));
nr_ue_if_module_inst[module_id]->cc_mask=0;
nr_ue_if_module_inst[module_id]->current_frame = 0;
nr_ue_if_module_inst[module_id]->current_slot = 0;
nr_ue_if_module_inst[module_id]->phy_config_request = nr_ue_phy_config_request;
if (get_softmodem_params()->emulate_l1)
nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response_stub;
else
nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response;
nr_ue_if_module_inst[module_id]->dl_indication = nr_ue_dl_indication;
nr_ue_if_module_inst[module_id]->ul_indication = nr_ue_ul_indication;
}
return nr_ue_if_module_inst[module_id];
}
int nr_ue_if_module_kill(uint32_t module_id) {
if (nr_ue_if_module_inst[module_id] != NULL){
free(nr_ue_if_module_inst[module_id]);
}
return 0;
}
int nr_ue_dcireq(nr_dcireq_t *dcireq) {
fapi_nr_dl_config_request_t *dl_config = &dcireq->dl_config_req;
NR_UE_MAC_INST_t *UE_mac = get_mac_inst(0);
dl_config->sfn = UE_mac->dl_config_request.sfn;
dl_config->slot = UE_mac->dl_config_request.slot;
LOG_D(PHY, "Entering UE DCI configuration frame %d slot %d \n", dcireq->frame, dcireq->slot);
ue_dci_configuration(UE_mac, dl_config, dcireq->frame, dcireq->slot);
return 0;
}
void RCconfig_nr_ue_L1(void) {
int j;
paramdef_t L1_Params[] = L1PARAMS_DESC;
paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0};
config_getlist(&L1_ParamList, L1_Params, sizeof(L1_Params) / sizeof(paramdef_t), NULL);
if (L1_ParamList.numelt > 0) {
for (j = 0; j < L1_ParamList.numelt; j++) {
if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) {
stub_eth_params.local_if_name = strdup(
*(L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr));
stub_eth_params.my_addr = strdup(
*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr));
stub_eth_params.remote_addr = strdup(
*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr));
stub_eth_params.my_portc =
*(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr);
stub_eth_params.remote_portc =
*(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr);
stub_eth_params.my_portd =
*(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr);
stub_eth_params.remote_portd =
*(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr);
stub_eth_params.transp_preference = ETH_UDP_MODE;
}
}
}
}
static int get_mcs_from_sinr(float sinr)
{
if (sinr < (nr_bler_data[0].bler_table[0][0]))
{
LOG_I(NR_MAC, "The SINR found is smaller than first MCS table\n");
return 0;
}
if (sinr > (nr_bler_data[NR_NUM_MCS-1].bler_table[nr_bler_data[NR_NUM_MCS-1].length - 1][0]))
{
LOG_I(NR_MAC, "The SINR found is larger than last MCS table\n");
return NR_NUM_MCS-1;
}
for (int n = NR_NUM_MCS-1; n >= 0; n--)
{
CHECK_INDEX(nr_bler_data, n);
float largest_sinr = (nr_bler_data[n].bler_table[nr_bler_data[n].length - 1][0]);
float smallest_sinr = (nr_bler_data[n].bler_table[0][0]);
if (sinr < largest_sinr && sinr > smallest_sinr)
{
LOG_I(NR_MAC, "The SINR found in MCS %d table\n", n);
return n;
}
}
LOG_E(NR_MAC, "Unable to get an MCS value.\n");
abort();
}
static int get_cqi_from_mcs(void)
{
static const int mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15};
assert(NUM_ELEMENTS(mcs_to_cqi) == NR_NUM_MCS);
int slot = 0;
while (slot < NUM_NFAPI_SLOT)
{
if (slot_rnti_mcs[slot].latest)
{
int num_pdus = slot_rnti_mcs[slot].num_pdus;
if (num_pdus <= 0)
{
LOG_E(NR_MAC, "%s: slot_rnti_mcs[%d].num_pdus = 0\n", __FUNCTION__, slot);
abort();
}
CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus);
int mcs = get_mcs_from_sinr(slot_rnti_mcs[slot].sinr);
CHECK_INDEX(mcs_to_cqi, mcs);
int cqi = mcs_to_cqi[mcs];
LOG_I(NR_MAC, "SINR: %f -> MCS: %d -> CQI: %d\n", slot_rnti_mcs[slot].sinr, mcs, cqi);
return cqi;
}
slot++;
}
LOG_E(NR_MAC, "Unable to get CQI value because no MCS found\n");
abort();
}
static void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int slot, int index)
{
if (pdu == NULL)
{
LOG_E(NR_MAC,"PDU NULL\n");
abort();
}
/* This function is executed for every pdsch pdu type in a dl_tti_request. We save
the assocaited MCS and RNTI value for each. The 'index' passed in is a count of
how many times we have called this function for a particular dl_tti_request. It
allows us to save MCS/RNTI data in correct indicies when multiple pdsch pdu's are received.*/
for (int i = 0; i < NUM_NFAPI_SLOT; i++)
{
slot_rnti_mcs[i].latest = false;
}
CHECK_INDEX(slot_rnti_mcs[slot].rnti, index);
CHECK_INDEX(slot_rnti_mcs[slot].mcs, index);
CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, index);
slot_rnti_mcs[slot].rnti[index] = pdu->rnti;
slot_rnti_mcs[slot].mcs[index] = pdu->mcsIndex[0];
slot_rnti_mcs[slot].rvIndex[index] = pdu->rvIndex[0];
slot_rnti_mcs[slot].drop_flag[index] = false;
slot_rnti_mcs[slot].num_pdus = index+1; //index starts at 0 so we incrament to get num of pdus
slot_rnti_mcs[slot].latest = true;
LOG_I(NR_MAC, "Adding MCS %d and RNTI %x for slot_rnti_mcs[%d]\n", slot_rnti_mcs[slot].mcs[index], slot_rnti_mcs[slot].rnti[index], slot);
return;
}
static bool did_drop_transport_block(int slot, uint16_t rnti)
{
int num_pdus = slot_rnti_mcs[slot].num_pdus;
if (num_pdus <= 0)
{
LOG_E(MAC, "Problem, the PDU size is <= 0. We dropped this packet\n");
return true;
}
CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus);
CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus);
for (int n = 0; n < num_pdus; n++)
{
if (slot_rnti_mcs[slot].rnti[n] == rnti && slot_rnti_mcs[slot].drop_flag[n])
{
return true;
}
}
return false;
}
static float get_bler_val(uint8_t mcs, int sinr)
{
// 4th col = dropped packets, 5th col = total packets
float bler_val = 0.0;
CHECK_INDEX(nr_bler_data, mcs);
LOG_I(NR_MAC, "sinr %d min %d max %d\n", sinr,
(int)(nr_bler_data[mcs].bler_table[0][0] * 10),
(int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10)
);
if (sinr < (int)(nr_bler_data[mcs].bler_table[0][0] * 10))
{
LOG_I(NR_MAC, "MCS %d table. SINR is smaller than lowest SINR, bler_val is set based on lowest SINR in table\n", mcs);
bler_val = nr_bler_data[mcs].bler_table[0][4] / nr_bler_data[mcs].bler_table[0][5];
return bler_val;
}
if (sinr > (int)(nr_bler_data[mcs].bler_table[nr_bler_data[mcs].length - 1][0] * 10))
{
LOG_I(NR_MAC, "MCS %d table. SINR is greater than largest SINR. bler_val is set based on largest SINR in table\n", mcs);
bler_val = nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][4] / nr_bler_data[mcs].bler_table[(nr_bler_data[mcs].length - 1)][5];
return bler_val;
}
// Loop through bler table to find sinr_index
for (int i = 0; i < nr_bler_data[mcs].length; i++)
{
int temp_sinr = (int)(nr_bler_data[mcs].bler_table[i][0] * 10);
if (temp_sinr == sinr)
{
bler_val = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
return bler_val;
}
// Linear interpolation when SINR is between indices
if (temp_sinr > sinr)
{
float bler_val1 = nr_bler_data[mcs].bler_table[i - 1][4] / nr_bler_data[mcs].bler_table[i - 1][5];
float bler_val2 = nr_bler_data[mcs].bler_table[i][4] / nr_bler_data[mcs].bler_table[i][5];
LOG_I(NR_MAC, "sinr %d min %f max %f\n", sinr, bler_val1, bler_val2);
return ((bler_val1 + bler_val2) / 2);
}
}
LOG_E(NR_MAC, "NO SINR INDEX FOUND!\n");
abort();
}
static inline bool is_channel_modeling(void)
{
/* TODO: For now we enable channel modeling based on the node_number.
Replace with a command line option to enable/disable channel modeling.
The LTE UE will crash when channel modeling is conducted for NSA
mode. It does not crash for LTE mode. We have not implemented channel
modeling for NSA mode yet. For now, we ensure only do do chanel modeling
in LTE mode. */
return get_softmodem_params()->node_number == 0 && !get_softmodem_params()->nsa;
}
static bool should_drop_transport_block(int slot, uint16_t rnti)
{
if (!is_channel_modeling())
{
return false;
}
/* We want to avoid dropping setup messages because this would be pathological.
This assumes were in standalone_pnf mode where
UE_rrc_inst[0] is module_id = 0 and Info[0] is eNB_index = 0. */
NR_UE_STATE_t state = NR_UE_rrc_inst[0].Info[0].State;
if (state < NR_RRC_CONNECTED)
{
LOG_I(NR_MAC, "Not dropping because state: %d", state);
return false;
}
/* Get block error rate (bler_val) from table based on every saved
MCS and SINR to be used as the cutoff rate for dropping packets.
Generate random uniform vairable to compare against bler_val. */
int num_pdus = slot_rnti_mcs[slot].num_pdus;
assert(slot < 20 && slot >= 0);
LOG_I(NR_MAC, "rnti: %x num_pdus %d state %d slot %u sinr %f\n",
rnti, num_pdus, state, slot, slot_rnti_mcs[slot].sinr);
assert(num_pdus > 0);
CHECK_INDEX(slot_rnti_mcs[slot].rnti, num_pdus);
CHECK_INDEX(slot_rnti_mcs[slot].mcs, num_pdus);
CHECK_INDEX(slot_rnti_mcs[slot].drop_flag, num_pdus);
int n = 0;
uint8_t mcs = 99;
for (n = 0; n < num_pdus; n++)
{
if (slot_rnti_mcs[slot].rnti[n] == rnti)
{
mcs = slot_rnti_mcs[slot].mcs[n];
}
if (mcs != 99)
{
/* Use MCS to get the bler value. Since there can be multiple MCS
values for a particular slot, we verify that all PDUs are not
flagged for drop before returning. If even one is flagged for drop
we return immediately because we drop the entire packet. */
LOG_I(NR_MAC, "rnti: %x mcs %u slot %u sinr %f\n",
slot_rnti_mcs[slot].rnti[n], mcs, slot, slot_rnti_mcs[slot].sinr);
float bler_val;
if (slot_rnti_mcs[slot].rvIndex[n] != 0)
bler_val = 0;
else
bler_val = get_bler_val(mcs, ((int)(slot_rnti_mcs[slot].sinr * 10)));
double drop_cutoff = ((double) rand() / (RAND_MAX));
assert(drop_cutoff <= 1);
LOG_I(NR_MAC, "SINR = %f, Bler_val = %f, MCS = %"PRIu8"\n", slot_rnti_mcs[slot].sinr, bler_val, slot_rnti_mcs[slot].mcs[n]);
if (drop_cutoff <= bler_val)
{
slot_rnti_mcs[slot].drop_flag[n] = true;
LOG_D(NR_MAC, "We are dropping this packet. Bler_val = %f, MCS = %"PRIu8", slot = %d\n", bler_val, slot_rnti_mcs[slot].mcs[n], slot);
return slot_rnti_mcs[slot].drop_flag[n];
}
}
}
if (mcs == 99)
{
LOG_E(NR_MAC, "NO MCS Found for rnti %x. slot_rnti_mcs[%d].mcs[%d] \n", rnti, slot, n);
abort();
}
return false;
}