Fixes to UE ULSCH PDU generation
- included MAC CE sub-PDUs size in the computation of RLC data to transmit this fixes the error with residual mac pdu appearing at gNB side when transmitting higher amount of data - got rid of the nr_generate_ulsch_pdu and moved the relevant UL-SCH MAC PDU generation procedure within the nr_ue_get_sdu and nr_ue_get_rach - reduced memcpy calls and unnecessary memory allocations - fetching RLC data and SDU size from the mac_rlc_data_req, removed the call to mac_rlc_get_buffer_occupancy_ind - introduced a new function to generate the MAC CEs sub-PDUs - removed unnecessary function input parameters - minor fixes and cleanup - enhanced logging
This commit is contained in:
@@ -390,6 +390,16 @@ typedef struct {
|
||||
|
||||
} NR_UE_MAC_INST_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint8_t power_headroom;
|
||||
uint16_t crnti;
|
||||
uint16_t truncated_bsr;
|
||||
uint16_t short_bsr;
|
||||
uint16_t long_bsr;
|
||||
|
||||
} NR_UE_MAC_CE_t;
|
||||
|
||||
typedef enum seach_space_mask_e {
|
||||
type0_pdcch = 0x1,
|
||||
type0a_pdcch = 0x2,
|
||||
|
||||
@@ -156,18 +156,8 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
|
||||
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment,
|
||||
int pdu_id);
|
||||
|
||||
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);
|
||||
int nr_write_ce_ulsch_pdu(unsigned char *mac_ce,
|
||||
NR_UE_MAC_CE_t *nr_ue_mac_ce);
|
||||
|
||||
void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15);
|
||||
|
||||
@@ -188,10 +178,12 @@ int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac,
|
||||
uint8_t time_domain_ind,
|
||||
bool use_default);
|
||||
|
||||
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 nr_ue_get_sdu(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframe,
|
||||
uint8_t gNB_index,
|
||||
uint8_t *ulsch_buffer,
|
||||
uint16_t buflen);
|
||||
|
||||
int set_tdd_config_nr_ue(fapi_nr_config_request_t *cfg, int mu,
|
||||
int nrofDownlinkSlots, int nrofDownlinkSymbols,
|
||||
|
||||
@@ -474,23 +474,19 @@ void nr_Msg3_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// This function handles:
|
||||
// - Random Access Preamble Initialization (5.1.1 TS 38.321)
|
||||
// - Random Access Response reception (5.1.4 TS 38.321)
|
||||
/// In the current implementation, RA is 4-step contention free only
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// todo TS 38.321:
|
||||
// - BWP operation (subclause 5.15 TS 38.321)
|
||||
// - beam failure recovery
|
||||
// - handle initialization by handover
|
||||
// - handle DL assignment on PDCCH for RA-RNTI
|
||||
// - transmission on DCCH using PRACH (during handover, or sending SR for example)
|
||||
// - take into account MAC CEs in size_sdu (currently hardcoded size to 1 MAC subPDU and 1 padding subheader)
|
||||
// - fix rrc data req logic
|
||||
// - retrieve TBS
|
||||
// - add mac_rrc_nr_data_req_ue, etc ...
|
||||
// - Msg3 Retransmissions to be scheduled by DCI 0_0
|
||||
/**
|
||||
* Function: handles Random Access Preamble Initialization (5.1.1 TS 38.321)
|
||||
* handles Random Access Response reception (5.1.4 TS 38.321)
|
||||
* Note: In the current implementation, RA is 4-step contention free only
|
||||
*
|
||||
* @prach_resources pointer to PRACH resources
|
||||
* @prach_pdu pointer to FAPI UL PRACH PDU
|
||||
* @mod_id module ID
|
||||
* @CC_id CC ID
|
||||
* @frame current UL TX frame
|
||||
* @gNB_id gNB ID
|
||||
* @nr_slot_tx current UL TX slot
|
||||
*/
|
||||
uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
|
||||
fapi_nr_ul_config_prach_pdu *prach_pdu,
|
||||
module_id_t mod_id,
|
||||
@@ -501,11 +497,10 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
|
||||
RA_config_t *ra = &mac->ra;
|
||||
uint8_t mac_sdus[MAX_NR_ULSCH_PAYLOAD_BYTES];
|
||||
uint8_t lcid = UL_SCH_LCID_CCCH;
|
||||
uint8_t *payload;
|
||||
uint16_t size_sdu = 0;
|
||||
unsigned short post_padding;
|
||||
uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_SHORT);
|
||||
int8_t size_sdu = 0;
|
||||
|
||||
NR_RACH_ConfigCommon_t *setup;
|
||||
if (mac->scc) setup = mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
|
||||
else setup = mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup;
|
||||
@@ -513,11 +508,6 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
|
||||
NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
|
||||
NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated;
|
||||
|
||||
uint8_t sdu_lcids[NB_RB_MAX] = {0};
|
||||
uint16_t sdu_lengths[NB_RB_MAX] = {0};
|
||||
int num_sdus = 0;
|
||||
int offset = 0;
|
||||
|
||||
// Delay init RA procedure to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
|
||||
if (!prach_resources->init_msg1) {
|
||||
if ( (mac->common_configuration_complete>0 || get_softmodem_params()->do_ra==1) && ((MAX_FRAME_NUMBER+frame-prach_resources->sync_frame)%MAX_FRAME_NUMBER)>150 ){
|
||||
@@ -528,22 +518,26 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,"frame %d prach_resources->init_msg1 %d, ra->ra_state %d, ra->RA_active %d\n",
|
||||
frame,prach_resources->init_msg1,ra->ra_state,ra->RA_active);
|
||||
LOG_D(NR_MAC, "In %s: [UE %d][%d.%d]: init_msg1 %d, ra_state %d, RA_active %d\n",
|
||||
__FUNCTION__,
|
||||
mod_id,
|
||||
frame,
|
||||
nr_slot_tx,
|
||||
prach_resources->init_msg1,
|
||||
ra->ra_state,
|
||||
ra->RA_active);
|
||||
|
||||
if (prach_resources->init_msg1 && ra->ra_state != RA_SUCCEEDED) {
|
||||
|
||||
if (ra->RA_active == 0) {
|
||||
/* RA not active - checking if RRC is ready to initiate the RA procedure */
|
||||
|
||||
LOG_D(NR_MAC, "RA not active. Checking for data to transmit from upper layers...\n");
|
||||
LOG_D(NR_MAC, "In %s: RA not active. Checking for data to transmit from upper layers...\n", __FUNCTION__);
|
||||
|
||||
uint8_t TBS_max = 8 + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
|
||||
payload = (uint8_t*) mac->CCCH_pdu.payload;
|
||||
|
||||
num_sdus = 1;
|
||||
post_padding = 1;
|
||||
sdu_lcids[0] = lcid;
|
||||
uint8_t TBS_max = 8 + 2 * sh_size;
|
||||
uint8_t *pdu = (uint8_t*) mac->CCCH_pdu.payload;
|
||||
NR_MAC_SUBHEADER_SHORT *header = (NR_MAC_SUBHEADER_SHORT *) pdu;
|
||||
pdu += sh_size;
|
||||
|
||||
// initialisation by RRC
|
||||
|
||||
@@ -553,57 +547,56 @@ uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
|
||||
}
|
||||
|
||||
// CCCH PDU
|
||||
size_sdu = (uint16_t) nr_mac_rrc_data_req_ue(mod_id, CC_id, gNB_id, frame, CCCH, mac_sdus);
|
||||
size_sdu = nr_mac_rrc_data_req_ue(mod_id, CC_id, gNB_id, frame, CCCH, pdu);
|
||||
|
||||
sdu_lengths[0] = size_sdu;
|
||||
|
||||
LOG_D(NR_MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n", mod_id, frame, size_sdu);
|
||||
LOG_D(NR_MAC, "In %s: [UE %d][%d.%d]: Requested RRCConnectionRequest, got %d bytes for LCID 0x%02x \n", __FUNCTION__, mod_id, frame, nr_slot_tx, size_sdu, lcid);
|
||||
|
||||
if (size_sdu > 0) {
|
||||
|
||||
// UE Contention Resolution Identity
|
||||
// Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to determine whether or not the
|
||||
// Random Access Procedure has been successful after reception of Msg4
|
||||
memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6);
|
||||
memcpy(ra->cont_res_id, pdu, sizeof(uint8_t) * 6);
|
||||
|
||||
LOG_D(NR_MAC, "[UE %d][%d.%d]: starting initialisation Random Access Procedure...\n", mod_id, frame, nr_slot_tx);
|
||||
pdu += size_sdu;
|
||||
|
||||
ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
|
||||
LOG_D(NR_MAC, "In %s: [UE %d][%d.%d]: starting initialisation Random Access Procedure...\n", __FUNCTION__, mod_id, frame, nr_slot_tx);
|
||||
|
||||
ra->Msg3_size = size_sdu + sh_size;
|
||||
|
||||
AssertFatal(TBS_max > ra->Msg3_size, "In %s: allocated resources are not enough for Msg3!\n", __FUNCTION__);
|
||||
|
||||
init_RA(mod_id, prach_resources, setup, rach_ConfigGeneric, rach_ConfigDedicated);
|
||||
prach_resources->Msg3 = payload;
|
||||
prach_resources->Msg3 = (uint8_t*) mac->CCCH_pdu.payload;
|
||||
nr_get_RA_window(mac);
|
||||
|
||||
// Fill in preamble and PRACH resources
|
||||
if (ra->generate_nr_prach == GENERATE_PREAMBLE) {
|
||||
nr_get_prach_resources(mod_id, CC_id, gNB_id, prach_resources, prach_pdu, rach_ConfigDedicated);
|
||||
}
|
||||
offset = nr_generate_ulsch_pdu((uint8_t *) mac_sdus, // sdus buffer
|
||||
(uint8_t *) payload, // UL MAC pdu pointer
|
||||
num_sdus, // num sdus
|
||||
sdu_lengths, // sdu length
|
||||
sdu_lcids, // sdu lcid
|
||||
0, // power headroom
|
||||
0, // crnti
|
||||
0, // truncated bsr
|
||||
0, // short bsr
|
||||
0, // long_bsr
|
||||
post_padding,
|
||||
0);
|
||||
|
||||
AssertFatal(TBS_max > offset, "Frequency resources are not enough for Msg3!\n");
|
||||
header->R = 0;
|
||||
header->F = 0;
|
||||
header->LCID = lcid;
|
||||
header->L = (unsigned char) size_sdu;
|
||||
|
||||
// Padding: fill remainder with 0
|
||||
if (post_padding > 0){
|
||||
for (int j = 0; j < (TBS_max - offset); j++)
|
||||
payload[offset + j] = 0;
|
||||
if (TBS_max - ra->Msg3_size > 0) {
|
||||
LOG_D(NR_MAC, "In %s: remaining %d bytes, filling with padding\n", __FUNCTION__, TBS_max - ra->Msg3_size);
|
||||
((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING;
|
||||
pdu += sizeof(NR_MAC_SUBHEADER_FIXED);
|
||||
for (int j = 0; j < TBS_max - ra->Msg3_size - sizeof(NR_MAC_SUBHEADER_FIXED); j++) {
|
||||
pdu[j] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pdu -= sh_size;
|
||||
}
|
||||
|
||||
LOG_D(MAC,"size_sdu = %i\n", size_sdu);
|
||||
LOG_D(MAC,"offset = %i\n", offset);
|
||||
LOG_D(NR_MAC, "In %s: dumping UL Msg3 MAC PDU with length %d: \n", __FUNCTION__, TBS_max);
|
||||
for(int k = 0; k < TBS_max; k++) {
|
||||
LOG_D(MAC,"(%i): %i\n", k, prach_resources->Msg3[k]);
|
||||
LOG_D(NR_MAC,"(%i): %i\n", k, prach_resources->Msg3[k]);
|
||||
}
|
||||
|
||||
// Msg3 was initialized with TBS_max bytes because the RA_Msg3_size will only be known after
|
||||
|
||||
@@ -1137,14 +1137,6 @@ void nr_ue_send_sdu(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_t *u
|
||||
|
||||
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
|
||||
@@ -2149,145 +2141,116 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/////* ULSCH MAC PDU generation (6.1.2 TS 38.321) */////
|
||||
////////////////////////////////////////////////////////
|
||||
// about: generating MAC CEs (MAC CE and subheader) for the ULSCH PDU
|
||||
// returns: number of written bytes
|
||||
/**
|
||||
* Function: generating MAC CEs (MAC CE and subheader) for the ULSCH PDU
|
||||
* @mac_ce pointer to the MAC sub-PDUs including the MAC CEs
|
||||
* @nr_ue_mac_ce pointer to the MAC CEs to be transmitted
|
||||
*/
|
||||
int nr_write_ce_ulsch_pdu(unsigned char *mac_ce,
|
||||
NR_UE_MAC_CE_t *nr_ue_mac_ce) {
|
||||
|
||||
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) {
|
||||
int mac_ce_len = 0;
|
||||
uint8_t mac_ce_size = 0;
|
||||
|
||||
NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) pdu;
|
||||
if (nr_ue_mac_ce->power_headroom) {
|
||||
|
||||
LOG_D(MAC, "[UE] Generating ULSCH PDU : num_sdus %d\n", num_sdus);
|
||||
LOG_D(NR_MAC, "In %s: generating PHR MAC CE with command %d\n", __FUNCTION__, nr_ue_mac_ce->power_headroom);
|
||||
|
||||
#ifdef DEBUG_HEADER_PARSING
|
||||
|
||||
for (int 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 (int 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];
|
||||
mac_pdu_ptr += sizeof(NR_MAC_SUBHEADER_SHORT);
|
||||
} 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;
|
||||
mac_pdu_ptr += sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
}
|
||||
} else { // UL CCCH SDU
|
||||
mac_pdu_ptr->R = 0;
|
||||
mac_pdu_ptr->LCID = sdu_lcids[i];
|
||||
mac_pdu_ptr ++;
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
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++;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_SINGLE_ENTRY_PHR;
|
||||
mac_ce++;
|
||||
|
||||
// PHR MAC CE (1 octet)
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_pdu_ptr)->PH = power_headroom;
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_pdu_ptr)->R1 = 0;
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_pdu_ptr)->PCMAX = 0; // todo
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_pdu_ptr)->R2 = 0;
|
||||
mac_pdu_ptr += sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE);
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PH = nr_ue_mac_ce->power_headroom;
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R1 = 0;
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->PCMAX = 0; // todo
|
||||
((NR_SINGLE_ENTRY_PHR_MAC_CE *) mac_ce)->R2 = 0;
|
||||
|
||||
// update pointer and length
|
||||
mac_ce_size = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE);
|
||||
mac_ce += mac_ce_size;
|
||||
mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED);
|
||||
|
||||
}
|
||||
|
||||
if (crnti) {
|
||||
if (nr_ue_mac_ce->crnti) {
|
||||
|
||||
LOG_D(NR_MAC, "In %s: generating C-RNTI MAC CE with C-RNTI %x\n", __FUNCTION__, nr_ue_mac_ce->crnti);
|
||||
|
||||
// MAC CE fixed subheader
|
||||
mac_pdu_ptr->R = 0;
|
||||
mac_pdu_ptr->LCID = UL_SCH_LCID_C_RNTI;
|
||||
mac_pdu_ptr++;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_C_RNTI;
|
||||
mac_ce++;
|
||||
|
||||
// C-RNTI MAC CE (2 octets)
|
||||
* (uint16_t *) mac_pdu_ptr = crnti;
|
||||
mac_pdu_ptr += sizeof(uint16_t);
|
||||
*(uint16_t *) mac_ce = nr_ue_mac_ce->crnti;
|
||||
|
||||
// update pointer and length
|
||||
mac_ce_size = sizeof(uint16_t);
|
||||
mac_ce += mac_ce_size;
|
||||
mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED);
|
||||
|
||||
}
|
||||
|
||||
if (truncated_bsr) {
|
||||
if (nr_ue_mac_ce->truncated_bsr) {
|
||||
|
||||
LOG_D(NR_MAC, "In %s: generating Truncated BSR MAC CE with command %x\n", __FUNCTION__, nr_ue_mac_ce->truncated_bsr);
|
||||
|
||||
// MAC CE fixed subheader
|
||||
mac_pdu_ptr->R = 0;
|
||||
mac_pdu_ptr->LCID = UL_SCH_LCID_S_TRUNCATED_BSR;
|
||||
mac_pdu_ptr++;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_S_TRUNCATED_BSR;
|
||||
mac_ce++;
|
||||
|
||||
// Short truncated BSR MAC CE (1 octet)
|
||||
((NR_BSR_SHORT_TRUNCATED *) mac_pdu_ptr)-> Buffer_size = truncated_bsr;
|
||||
((NR_BSR_SHORT_TRUNCATED *) mac_pdu_ptr)-> LcgID = 0; // todo
|
||||
mac_pdu_ptr+= sizeof(NR_BSR_SHORT_TRUNCATED);
|
||||
} else if (short_bsr) {
|
||||
((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> Buffer_size = nr_ue_mac_ce->truncated_bsr;
|
||||
((NR_BSR_SHORT_TRUNCATED *) mac_ce)-> LcgID = 0;
|
||||
|
||||
// update pointer and length
|
||||
mac_ce_size = sizeof(NR_BSR_SHORT_TRUNCATED);
|
||||
mac_ce += mac_ce_size;
|
||||
mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED);
|
||||
|
||||
} else if (nr_ue_mac_ce->short_bsr) {
|
||||
|
||||
LOG_D(NR_MAC, "In %s: generating Truncated short BSR MAC CE with command %x\n", __FUNCTION__, nr_ue_mac_ce->short_bsr);
|
||||
|
||||
// MAC CE fixed subheader
|
||||
mac_pdu_ptr->R = 0;
|
||||
mac_pdu_ptr->LCID = UL_SCH_LCID_S_BSR;
|
||||
mac_pdu_ptr++;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) mac_ce)->LCID = UL_SCH_LCID_S_BSR;
|
||||
mac_ce++;
|
||||
|
||||
// Short truncated BSR MAC CE (1 octet)
|
||||
((NR_BSR_SHORT *) mac_pdu_ptr)->Buffer_size = short_bsr;
|
||||
((NR_BSR_SHORT *) mac_pdu_ptr)->LcgID = 0; // todo
|
||||
mac_pdu_ptr+= sizeof(NR_BSR_SHORT);
|
||||
} else if (long_bsr) {
|
||||
((NR_BSR_SHORT *) mac_ce)->Buffer_size = nr_ue_mac_ce->short_bsr;
|
||||
((NR_BSR_SHORT *) mac_ce)->LcgID = 0;
|
||||
|
||||
// update pointer and length
|
||||
mac_ce_size = sizeof(NR_BSR_SHORT);
|
||||
mac_ce += mac_ce_size;
|
||||
mac_ce_len += mac_ce_size + sizeof(NR_MAC_SUBHEADER_FIXED);
|
||||
|
||||
} else if (nr_ue_mac_ce->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;
|
||||
// sh_size = 2;
|
||||
|
||||
// Short truncated BSR MAC CE (1 octet)
|
||||
// ((NR_BSR_LONG *) ce_ptr)->Buffer_size0 = short_bsr;
|
||||
// ((NR_BSR_LONG *) ce_ptr)->LCGID0 = 0;
|
||||
// ((NR_BSR_LONG *) mac_ce)->Buffer_size0 = short_bsr;
|
||||
// ((NR_BSR_LONG *) mac_ce)->LCGID0 = 0;
|
||||
// mac_ce_size = sizeof(NR_BSR_LONG); // size is variable
|
||||
}
|
||||
// compute offset before adding padding (if necessary)
|
||||
int padding_bytes = 0;
|
||||
|
||||
if(buflen > 0) // If the buflen is provided
|
||||
padding_bytes = buflen + pdu - (unsigned char *) mac_pdu_ptr;
|
||||
return mac_ce_len;
|
||||
|
||||
AssertFatal(padding_bytes>=0,"");
|
||||
|
||||
// Compute final offset for padding
|
||||
if (post_padding || 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++;
|
||||
}
|
||||
return (uint8_t *)mac_pdu_ptr-pdu;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
// Random Access Response PDU //
|
||||
// TS 38.213 ch 8.2 //
|
||||
|
||||
@@ -989,7 +989,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
|
||||
frame_t frame_tx = ul_info->frame_tx;
|
||||
slot_t slot_tx = ul_info->slot_tx;
|
||||
module_id_t mod_id = ul_info->module_id;
|
||||
uint8_t access_mode = SCHEDULED_ACCESS;
|
||||
uint32_t gNB_index = ul_info->gNB_index;
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
|
||||
RA_config_t *ra = &mac->ra;
|
||||
@@ -1036,19 +1036,18 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
|
||||
|
||||
// Getting IP traffic to be transmitted
|
||||
data_existing = nr_ue_get_sdu(mod_id,
|
||||
cc_id,
|
||||
frame_tx,
|
||||
slot_tx,
|
||||
0,
|
||||
gNB_index,
|
||||
ulsch_input_buffer,
|
||||
TBS_bytes,
|
||||
&access_mode);
|
||||
TBS_bytes);
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,"Flipping NDI for harq_id %d\n",ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator);
|
||||
mac->UL_ndi[ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id] = ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator;
|
||||
mac->first_ul_tx[ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id] = 0;
|
||||
|
||||
// TBR use the proper function !
|
||||
//Random traffic to be transmitted if there is no IP traffic available for this Tx opportunity
|
||||
if (!data_existing) {
|
||||
//Use zeros for the header bytes in noS1 mode, in order to make sure that the LCID is not valid
|
||||
@@ -1965,114 +1964,174 @@ void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t s
|
||||
} // if is_nr_UL_slot
|
||||
}
|
||||
|
||||
#define MAX_LCID 8 //Fixme: also defined in LCID table
|
||||
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;
|
||||
#define MAX_LCID 8 // NR_MAX_NUM_LCID shall be used but the mac_rlc_data_req function can fetch data for max 8 LCID
|
||||
|
||||
/**
|
||||
* Function: to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer
|
||||
to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321)
|
||||
the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG
|
||||
* @module_idP Module ID
|
||||
* @frameP current UL frame
|
||||
* @subframe current UL slot
|
||||
* @gNB_index gNB index
|
||||
* @ulsch_buffer Pointer to ULSCH PDU
|
||||
* @buflen TBS
|
||||
*/
|
||||
uint8_t nr_ue_get_sdu(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t subframe,
|
||||
uint8_t gNB_index,
|
||||
uint8_t *ulsch_buffer,
|
||||
uint16_t buflen) {
|
||||
|
||||
int16_t buflen_remain = 0;
|
||||
uint8_t lcid = 0;
|
||||
uint16_t sdu_lengths[MAX_LCID] = { 0 };
|
||||
uint8_t sdu_lcids[MAX_LCID] = { 0 };
|
||||
uint16_t payload_offset = 0, num_sdus = 0;
|
||||
uint8_t ulsch_sdus[MAX_ULSCH_PAYLOAD_BYTES];
|
||||
uint16_t num_sdus = 0;
|
||||
uint16_t sdu_length_total = 0;
|
||||
//unsigned short post_padding = 0;
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
|
||||
uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
|
||||
rlc_buffer_occupancy_t lcid_buffer_occupancy_new = 0;
|
||||
LOG_D(NR_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");
|
||||
// Pointer used to build the MAC PDU by placing the RLC SDUs in the ULSCH buffer
|
||||
uint8_t *pdu = ulsch_buffer;
|
||||
|
||||
// Preparing the MAC CEs sub-PDUs and get the total size
|
||||
unsigned char mac_header_control_elements[16] = {0};
|
||||
NR_UE_MAC_CE_t nr_ue_mac_ce = {.crnti = mac->crnti};
|
||||
int tot_mac_ce_len = nr_write_ce_ulsch_pdu(&mac_header_control_elements[0], &nr_ue_mac_ce);
|
||||
uint8_t total_mac_pdu_header_len = tot_mac_ce_len;
|
||||
|
||||
LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", __FUNCTION__, module_idP, frameP, subframe, buflen);
|
||||
|
||||
// Check for DCCH first
|
||||
// TO DO: Multiplex in the order defined by the logical channel prioritization
|
||||
for (lcid = UL_SCH_LCID_SRB1;
|
||||
lcid < MAX_LCID; lcid++) {
|
||||
lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP, mac->crnti, eNB_index, frameP, subframe, ENB_FLAG_NO, lcid);
|
||||
|
||||
if(lcid_buffer_occupancy_new) {
|
||||
buflen_remain =
|
||||
buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE);
|
||||
LOG_D(NR_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]]
|
||||
buflen_remain = buflen - (total_mac_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE);
|
||||
|
||||
while(buflen_remain > 0 && lcid_buffer_occupancy_new){
|
||||
LOG_D(NR_MAC, "In %s: [UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header len %d bytes, buflen_remain %d bytes)\n",
|
||||
__FUNCTION__,
|
||||
module_idP,
|
||||
frameP,
|
||||
subframe,
|
||||
lcid,
|
||||
buflen,
|
||||
sdu_length_total,
|
||||
tot_mac_ce_len,
|
||||
buflen_remain);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
|
||||
mac->crnti,
|
||||
eNB_index,
|
||||
frameP,
|
||||
ENB_FLAG_NO,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
buflen_remain-MAX_RLC_SDU_SUBHEADER_SIZE,
|
||||
//Fixme: Laurent I removed MAX_RLC_SDU_SUBHEADER_SIZE because else we get out the buffer silently
|
||||
// the interface with nr_generate_ulsch_pdu() looks over complex and not CPU optimized
|
||||
(char *)&ulsch_sdus[sdu_length_total],0,
|
||||
0);
|
||||
while (buflen_remain > 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);
|
||||
// Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU
|
||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) pdu;
|
||||
|
||||
if (sdu_lengths[num_sdus]) {
|
||||
sdu_length_total += sdu_lengths[num_sdus];
|
||||
sdu_lcids[num_sdus] = lcid;
|
||||
pdu += sh_size;
|
||||
|
||||
total_rlc_pdu_header_len += MAX_RLC_SDU_SUBHEADER_SIZE; //rlc_pdu_header_len_last;
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
|
||||
mac->crnti,
|
||||
gNB_index,
|
||||
frameP,
|
||||
ENB_FLAG_NO,
|
||||
MBMS_FLAG_NO,
|
||||
lcid,
|
||||
buflen_remain,
|
||||
(char *)pdu,
|
||||
0,
|
||||
0);
|
||||
|
||||
//Update number of SDU
|
||||
num_sdus++;
|
||||
}
|
||||
AssertFatal(buflen_remain >= sdu_lengths[num_sdus], "In %s: LCID = 0x%02x RLC has segmented %d bytes but MAC has max %d remaining bytes\n",
|
||||
__FUNCTION__,
|
||||
lcid,
|
||||
sdu_lengths[num_sdus],
|
||||
buflen_remain);
|
||||
|
||||
/* 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);
|
||||
if (sdu_lengths[num_sdus]) {
|
||||
|
||||
LOG_D(MAC, "In %s: Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID 0x%02x (buflen (TBS) %d bytes)\n", __FUNCTION__,
|
||||
num_sdus + 1,
|
||||
sdu_lengths[num_sdus],
|
||||
lcid,
|
||||
buflen);
|
||||
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = lcid;
|
||||
header->L1 = ((unsigned short) sdu_lengths[num_sdus] >> 8) & 0x7f;
|
||||
header->L2 = (unsigned short) sdu_lengths[num_sdus] & 0xff;
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
LOG_I(NR_MAC, "In %s: dumping MAC sub-header with length %d: \n", __FUNCTION__, sh_size);
|
||||
log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n");
|
||||
LOG_I(NR_MAC, "In %s: dumping MAC SDU with length %d \n", __FUNCTION__, sdu_lengths[num_sdus]);
|
||||
log_dump(NR_MAC, pdu, sdu_lengths[num_sdus], LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
pdu += sdu_lengths[num_sdus];
|
||||
sdu_length_total += sdu_lengths[num_sdus];
|
||||
total_mac_pdu_header_len += sh_size;
|
||||
|
||||
num_sdus++;
|
||||
|
||||
} else {
|
||||
pdu -= sh_size;
|
||||
LOG_D(MAC, "In %s: no data to transmit for RB with LCID 0x%02x\n", __FUNCTION__, lcid);
|
||||
break;
|
||||
}
|
||||
|
||||
buflen_remain = buflen - (total_mac_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;
|
||||
if (num_sdus > 0) {
|
||||
|
||||
if (tot_mac_ce_len > 0) {
|
||||
|
||||
LOG_D(NR_MAC, "In %s copying %d bytes of MAC CEs to the UL PDU \n", __FUNCTION__, tot_mac_ce_len);
|
||||
memcpy((void *) pdu, (void *) mac_header_control_elements, tot_mac_ce_len);
|
||||
buflen_remain = buflen - (total_mac_pdu_header_len + sdu_length_total);
|
||||
pdu += (unsigned char) tot_mac_ce_len;
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
LOG_I(NR_MAC, "In %s: dumping MAC CE with length tot_mac_ce_len %d: \n", __FUNCTION__, tot_mac_ce_len);
|
||||
log_dump(NR_MAC, mac_header_control_elements, tot_mac_ce_len, LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Compute final offset for padding and fill remainder of ULSCH with 0
|
||||
if (buflen_remain > 0) {
|
||||
|
||||
((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0;
|
||||
((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING;
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
LOG_I(NR_MAC, "In %s: padding MAC sub-header with length %ld bytes \n", __FUNCTION__, sizeof(NR_MAC_SUBHEADER_FIXED));
|
||||
log_dump(NR_MAC, pdu, sizeof(NR_MAC_SUBHEADER_FIXED), LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
pdu++;
|
||||
buflen_remain--;
|
||||
|
||||
for (int j = 0; j < buflen_remain; j++) {
|
||||
pdu[j] = 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
LOG_I(NR_MAC, "In %s: MAC padding sub-PDU with length %d bytes \n", __FUNCTION__, buflen_remain);
|
||||
log_dump(NR_MAC, pdu, buflen_remain, LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
LOG_I(NR_MAC, "In %s: dumping MAC PDU with length %d: \n", __FUNCTION__, buflen);
|
||||
log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Padding: fill remainder of ULSCH with 0
|
||||
if (buflen - payload_offset > 0){
|
||||
for (int j = payload_offset; j < buflen; j++)
|
||||
ulsch_buffer[j] = 0;
|
||||
}
|
||||
return num_sdus > 0 ? 1 : 0;
|
||||
|
||||
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
|
||||
LOG_I(NR_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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user