607 lines
24 KiB
C
607 lines
24 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_ulsch_ue.c
|
|
* \brief Top-level routines for transmission of the PUSCH TS 38.211 v 15.4.0
|
|
* \author Khalid Ahmed
|
|
* \date 2019
|
|
* \version 0.1
|
|
* \company Fraunhofer IIS
|
|
* \email: khalid.ahmed@iis.fraunhofer.de
|
|
* \note
|
|
* \warning
|
|
*/
|
|
#include <stdint.h>
|
|
#include "PHY/NR_REFSIG/dmrs_nr.h"
|
|
#include "PHY/NR_REFSIG/ptrs_nr.h"
|
|
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
|
|
#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
|
|
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
|
#include "PHY/MODULATION/nr_modulation.h"
|
|
#include "PHY/MODULATION/modulation_common.h"
|
|
#include "common/utils/assertions.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
#include "common/utils/LOG/vcd_signal_dumper.h"
|
|
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
|
#include "PHY/NR_TRANSPORT/nr_sch_dmrs.h"
|
|
#include "PHY/defs_nr_common.h"
|
|
#include "PHY/TOOLS/tools_defs.h"
|
|
#include "executables/nr-softmodem.h"
|
|
#include "executables/softmodem-common.h"
|
|
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
|
|
#include <openair2/UTIL/OPT/opt.h>
|
|
|
|
//#define DEBUG_PUSCH_MAPPING
|
|
//#define DEBUG_MAC_PDU
|
|
//#define DEBUG_DFT_IDFT
|
|
|
|
//extern int32_t uplink_counter;
|
|
|
|
void nr_pusch_codeword_scrambling_uci(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, uint32_t* out)
|
|
{
|
|
uint32_t *seq = gold_cache((n_RNTI << 15) + Nid, (size + 31) / 32);
|
|
for (int i=0; i<size; i++) {
|
|
int idx = i / 32;
|
|
int b_idx = i % 32;
|
|
if (in[i]==NR_PUSCH_x)
|
|
out[idx] ^= 1 << b_idx;
|
|
else if (in[i]==NR_PUSCH_y){
|
|
if (b_idx)
|
|
out[idx] ^= (out[idx] & (1 << (b_idx - 1))) << 1;
|
|
else{
|
|
uint32_t temp_out = out[idx - 1];
|
|
out[idx] ^= temp_out >> 31;
|
|
}
|
|
}
|
|
else
|
|
out[idx] ^= (((in[i]) & 1) ^ ((seq[idx] >> b_idx) & 1)) << b_idx;
|
|
//printf("i %d b_idx %d in %d s 0x%08x out 0x%08x\n", i, b_idx, in[i], s, *out);
|
|
}
|
|
}
|
|
|
|
void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, bool uci_on_pusch, uint32_t* out)
|
|
{
|
|
if (uci_on_pusch)
|
|
nr_pusch_codeword_scrambling_uci(in, size, Nid, n_RNTI, out);
|
|
else
|
|
nr_codeword_scrambling(in, size, 0, Nid, n_RNTI, out);
|
|
}
|
|
|
|
void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
|
const unsigned char harq_pid,
|
|
const uint32_t frame,
|
|
const uint8_t slot,
|
|
const int gNB_id,
|
|
nr_phy_data_tx_t *phy_data,
|
|
c16_t **txdataF)
|
|
{
|
|
LOG_D(PHY,"nr_ue_ulsch_procedures hard_id %d %d.%d\n",harq_pid,frame,slot);
|
|
|
|
int Wf[2], Wt[2];
|
|
int l_prime[2], delta;
|
|
uint8_t nb_dmrs_re_per_rb;
|
|
int i;
|
|
int sample_offsetF, N_RE_prime;
|
|
|
|
NR_DL_FRAME_PARMS *frame_parms = &UE->frame_parms;
|
|
|
|
int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig
|
|
uint16_t number_dmrs_symbols = 0;
|
|
|
|
NR_UE_ULSCH_t *ulsch_ue = &phy_data->ulsch;
|
|
NR_UL_UE_HARQ_t *harq_process_ul_ue = &UE->ul_harq_processes[harq_pid];
|
|
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch_ue->pusch_pdu;
|
|
|
|
uint32_t tb_size = pusch_pdu->pusch_data.tb_size;
|
|
AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 &&
|
|
pusch_pdu->pusch_uci.csi_part1_bit_length == 0 &&
|
|
pusch_pdu->pusch_uci.csi_part2_bit_length == 0,
|
|
"UCI on PUSCH not supported at PHY\n");
|
|
|
|
int start_symbol = pusch_pdu->start_symbol_index;
|
|
uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos;
|
|
uint8_t number_of_symbols = pusch_pdu->nr_of_symbols;
|
|
uint8_t dmrs_type = pusch_pdu->dmrs_config_type;
|
|
uint16_t start_rb = pusch_pdu->rb_start;
|
|
uint16_t nb_rb = pusch_pdu->rb_size;
|
|
uint8_t Nl = pusch_pdu->nrOfLayers;
|
|
uint8_t mod_order = pusch_pdu->qam_mod_order;
|
|
uint16_t rnti = pusch_pdu->rnti;
|
|
uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data;
|
|
uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb+pusch_pdu->bwp_start)*NR_NB_SC_PER_RB;
|
|
|
|
if (start_sc >= frame_parms->ofdm_symbol_size)
|
|
start_sc -= frame_parms->ofdm_symbol_size;
|
|
|
|
ulsch_ue->Nid_cell = frame_parms->Nid_cell;
|
|
|
|
for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) {
|
|
if((ul_dmrs_symb_pos >> i) & 0x01)
|
|
number_dmrs_symbols += 1;
|
|
}
|
|
|
|
nb_dmrs_re_per_rb = ((dmrs_type == pusch_dmrs_type1) ? 6:4)*cdm_grps_no_data;
|
|
|
|
LOG_D(PHY,"ulsch TX %x : start_rb %d nb_rb %d mod_order %d Nl %d Tpmi %d bwp_start %d start_sc %d start_symbol %d num_symbols %d cdmgrpsnodata %d num_dmrs %d dmrs_re_per_rb %d\n",
|
|
rnti,start_rb,nb_rb,mod_order,Nl,pusch_pdu->Tpmi,pusch_pdu->bwp_start,start_sc,start_symbol,number_of_symbols,cdm_grps_no_data,number_dmrs_symbols,nb_dmrs_re_per_rb);
|
|
// TbD num_of_mod_symbols is set but never used
|
|
N_RE_prime = NR_NB_SC_PER_RB*number_of_symbols - nb_dmrs_re_per_rb*number_dmrs_symbols - N_PRB_oh;
|
|
harq_process_ul_ue->num_of_mod_symbols = N_RE_prime*nb_rb;
|
|
|
|
/////////////////////////PTRS parameters' initialization/////////////////////////
|
|
///////////
|
|
|
|
uint8_t L_ptrs, K_ptrs = 0;
|
|
uint32_t unav_res = 0;
|
|
if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
|
K_ptrs = pusch_pdu->pusch_ptrs.ptrs_freq_density;
|
|
L_ptrs = 1 << pusch_pdu->pusch_ptrs.ptrs_time_density;
|
|
|
|
ulsch_ue->ptrs_symbols = 0;
|
|
|
|
set_ptrs_symb_idx(&ulsch_ue->ptrs_symbols,
|
|
number_of_symbols,
|
|
start_symbol,
|
|
L_ptrs,
|
|
ul_dmrs_symb_pos);
|
|
int n_ptrs = (nb_rb + K_ptrs - 1) / K_ptrs;
|
|
int ptrsSymbPerSlot = get_ptrs_symbols_in_slot(ulsch_ue->ptrs_symbols,
|
|
start_symbol,
|
|
number_of_symbols);
|
|
unav_res = n_ptrs * ptrsSymbPerSlot;
|
|
}
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////ULSCH coding/////////////////////////
|
|
///////////
|
|
|
|
unsigned int G = nr_get_G(nb_rb,
|
|
number_of_symbols,
|
|
nb_dmrs_re_per_rb,
|
|
number_dmrs_symbols,
|
|
unav_res,
|
|
mod_order,
|
|
Nl);
|
|
|
|
trace_NRpdu(DIRECTION_UPLINK, harq_process_ul_ue->payload_AB, tb_size, WS_C_RNTI, rnti, frame, slot, 0, 0);
|
|
|
|
if (nr_ulsch_encoding(UE, ulsch_ue, frame_parms, harq_pid, tb_size, G) == -1)
|
|
return;
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////ULSCH scrambling/////////////////////////
|
|
///////////
|
|
|
|
uint32_t available_bits = G;
|
|
// +1 because size can be not modulo 4
|
|
uint32_t scrambled_output[available_bits / (8 * sizeof(uint32_t)) + 1];
|
|
memset(scrambled_output, 0, sizeof(scrambled_output));
|
|
|
|
nr_pusch_codeword_scrambling(harq_process_ul_ue->f,
|
|
available_bits,
|
|
pusch_pdu->data_scrambling_id,
|
|
rnti,
|
|
false,
|
|
scrambled_output);
|
|
|
|
/////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////ULSCH modulation/////////////////////////
|
|
///////////
|
|
|
|
int max_num_re = Nl*number_of_symbols*nb_rb*NR_NB_SC_PER_RB;
|
|
c16_t d_mod[max_num_re] __attribute__((aligned(16)));
|
|
|
|
nr_modulation(scrambled_output, // assume one codeword for the moment
|
|
available_bits,
|
|
mod_order,
|
|
(int16_t *)d_mod);
|
|
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////DMRS Modulation/////////////////////////
|
|
///////////
|
|
|
|
uint16_t n_dmrs = (pusch_pdu->bwp_start + start_rb + nb_rb)*((dmrs_type == pusch_dmrs_type1) ? 6:4);
|
|
c16_t mod_dmrs[n_dmrs] __attribute((aligned(16)));
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////ULSCH layer mapping/////////////////////////
|
|
///////////
|
|
const int sz = available_bits / mod_order;
|
|
c16_t tx_layers[Nl][sz];
|
|
memset(tx_layers, 0, sizeof(tx_layers));
|
|
|
|
nr_ue_layer_mapping(d_mod, Nl, available_bits / mod_order, sz, tx_layers);
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////// ULSCH transform precoding ////////////////////////
|
|
///////////
|
|
|
|
l_prime[0] = 0; // single symbol ap 0
|
|
|
|
uint8_t u = 0, v = 0;
|
|
c16_t *dmrs_seq = NULL;
|
|
/// Transform-coded "y"-sequences (for definition see 38-211 V15.3.0 2018-09, subsection 6.3.1.4)
|
|
c16_t y[max_num_re] __attribute__((aligned(16)));
|
|
memset(y, 0, sizeof(y));
|
|
|
|
if (pusch_pdu->transform_precoding == transformPrecoder_enabled) {
|
|
|
|
uint32_t nb_re_pusch=nb_rb * NR_NB_SC_PER_RB;
|
|
uint32_t y_offset = 0;
|
|
uint16_t num_dmrs_res_per_symbol = nb_rb*(NR_NB_SC_PER_RB/2);
|
|
|
|
// Calculate index to dmrs seq array based on number of DMRS Subcarriers on this symbol
|
|
int index = get_index_for_dmrs_lowpapr_seq(num_dmrs_res_per_symbol);
|
|
u = pusch_pdu->dfts_ofdm.low_papr_group_number;
|
|
v = pusch_pdu->dfts_ofdm.low_papr_sequence_number;
|
|
dmrs_seq = dmrs_lowpaprtype1_ul_ref_sig[u][v][index];
|
|
|
|
AssertFatal(index >= 0, "Num RBs not configured according to 3GPP 38.211 section 6.3.1.4. For PUSCH with transform precoding, num RBs cannot be multiple of any other primenumber other than 2,3,5\n");
|
|
AssertFatal(dmrs_seq != NULL, "DMRS low PAPR seq not found, check if DMRS sequences are generated");
|
|
|
|
LOG_D(PHY,"Transform Precoding params. u: %d, v: %d, index for dmrsseq: %d\n", u, v, index);
|
|
|
|
for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) {
|
|
|
|
if((ul_dmrs_symb_pos >> l) & 0x01)
|
|
/* In the symbol with DMRS no data would be transmitted CDM groups is 2*/
|
|
continue;
|
|
|
|
nr_dft(&y[y_offset], &tx_layers[0][y_offset], nb_re_pusch);
|
|
|
|
y_offset = y_offset + nb_re_pusch;
|
|
|
|
LOG_D(PHY,"Transform precoding being done on data- symbol: %d, nb_re_pusch: %d, y_offset: %d\n", l, nb_re_pusch, y_offset);
|
|
|
|
#ifdef DEBUG_PUSCH_MAPPING
|
|
printf("NR_ULSCH_UE: y_offset %u\t nb_re_pusch %u \t Symbol %d \t nb_rb %d \n",
|
|
y_offset, nb_re_pusch, l, nb_rb);
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG_DFT_IDFT
|
|
int32_t debug_symbols[MAX_NUM_NR_RE] __attribute__ ((aligned(16)));
|
|
int offset = 0;
|
|
printf("NR_ULSCH_UE: available_bits: %u, mod_order: %d", available_bits,mod_order);
|
|
|
|
for (int ll = 0; ll < (available_bits/mod_order); ll++) {
|
|
debug_symbols[ll] = ulsch_ue->y[ll];
|
|
}
|
|
|
|
printf("NR_ULSCH_UE: numSym: %d, num_dmrs_sym: %d", number_of_symbols,number_dmrs_symbols);
|
|
for (int ll = 0; ll < (number_of_symbols-number_dmrs_symbols); ll++) {
|
|
nr_idft(&debug_symbols[offset], nb_re_pusch);
|
|
offset = offset + nb_re_pusch;
|
|
}
|
|
LOG_M("preDFT_all_symbols.m","UE_preDFT", tx_layers[0],number_of_symbols*nb_re_pusch,1,1);
|
|
LOG_M("postDFT_all_symbols.m","UE_postDFT", y,number_of_symbols*nb_re_pusch,1,1);
|
|
LOG_M("DEBUG_IDFT_SYMBOLS.m","UE_Debug_IDFT", debug_symbols,number_of_symbols*nb_re_pusch,1,1);
|
|
LOG_M("UE_DMRS_SEQ.m","UE_DMRS_SEQ", dmrs_seq,nb_re_pusch,1,1);
|
|
#endif
|
|
|
|
}
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/////////////////////////ULSCH RE mapping/////////////////////////
|
|
///////////
|
|
|
|
const int encoded_length = frame_parms->N_RB_UL * 14 * NR_NB_SC_PER_RB * mod_order * Nl;
|
|
c16_t tx_precoding[Nl][encoded_length];
|
|
memset(tx_precoding, 0, sizeof(tx_precoding));
|
|
|
|
for (int nl=0; nl < Nl; nl++) {
|
|
uint8_t k_prime = 0;
|
|
uint16_t m = 0;
|
|
|
|
#ifdef DEBUG_PUSCH_MAPPING
|
|
printf("NR_ULSCH_UE: Value of CELL ID %d /t, u %d \n", frame_parms->Nid_cell, u);
|
|
#endif
|
|
|
|
int dmrs_port = get_dmrs_port(nl,pusch_pdu->dmrs_ports);
|
|
// DMRS params for this dmrs port
|
|
get_Wt(Wt, dmrs_port, dmrs_type);
|
|
get_Wf(Wf, dmrs_port, dmrs_type);
|
|
delta = get_delta(dmrs_port, dmrs_type);
|
|
|
|
for (int l=start_symbol; l<start_symbol+number_of_symbols; l++) {
|
|
|
|
uint16_t k = start_sc;
|
|
uint16_t n = 0;
|
|
uint8_t is_dmrs_sym = 0;
|
|
uint8_t is_ptrs_sym = 0;
|
|
uint16_t dmrs_idx = 0, ptrs_idx = 0;
|
|
|
|
c16_t mod_ptrs[nb_rb] __attribute((aligned(16))); // assume maximum number of PTRS per pusch allocation
|
|
|
|
if ((ul_dmrs_symb_pos >> l) & 0x01) {
|
|
is_dmrs_sym = 1;
|
|
|
|
if (pusch_pdu->transform_precoding == transformPrecoder_disabled){
|
|
|
|
if (dmrs_type == pusch_dmrs_type1)
|
|
dmrs_idx = (pusch_pdu->bwp_start + start_rb)*6;
|
|
else
|
|
dmrs_idx = (pusch_pdu->bwp_start + start_rb)*4;
|
|
|
|
// TODO: performance improvement, we can skip the modulation of DMRS symbols outside the bandwidth part
|
|
// Perform this on gold sequence, not required when SC FDMA operation is done,
|
|
LOG_D(PHY,"DMRS in symbol %d\n",l);
|
|
const uint32_t *gold = nr_gold_pusch(frame_parms->N_RB_UL,
|
|
frame_parms->symbols_per_slot,
|
|
pusch_pdu->ul_dmrs_scrambling_id,
|
|
pusch_pdu->scid,
|
|
slot,
|
|
l);
|
|
nr_modulation(gold,
|
|
n_dmrs * 2,
|
|
DMRS_MOD_ORDER,
|
|
(int16_t *)mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
|
|
} else {
|
|
dmrs_idx = 0;
|
|
}
|
|
} else if (pusch_pdu->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
|
|
|
|
AssertFatal(pusch_pdu->transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n");
|
|
|
|
if(is_ptrs_symbol(l, ulsch_ue->ptrs_symbols)) {
|
|
is_ptrs_sym = 1;
|
|
const uint32_t *gold = nr_gold_pusch(frame_parms->N_RB_UL,
|
|
frame_parms->symbols_per_slot,
|
|
pusch_pdu->ul_dmrs_scrambling_id,
|
|
pusch_pdu->scid,
|
|
slot,
|
|
l);
|
|
nr_modulation(gold, nb_rb, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
|
|
}
|
|
}
|
|
|
|
for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++) {
|
|
uint8_t is_dmrs = 0;
|
|
uint8_t is_ptrs = 0;
|
|
|
|
sample_offsetF = l*frame_parms->ofdm_symbol_size + k;
|
|
|
|
if (is_dmrs_sym) {
|
|
if (k == ((start_sc+get_dmrs_freq_idx_ul(n, k_prime, delta, dmrs_type))%frame_parms->ofdm_symbol_size))
|
|
is_dmrs = 1;
|
|
} else if (is_ptrs_sym) {
|
|
is_ptrs = is_ptrs_subcarrier(k,
|
|
rnti,
|
|
K_ptrs,
|
|
nb_rb,
|
|
pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset,
|
|
start_sc,
|
|
frame_parms->ofdm_symbol_size);
|
|
}
|
|
|
|
if (is_dmrs == 1) {
|
|
// if transform precoding is enabled
|
|
const int tmp = Wt[l_prime[0]] * Wf[k_prime] * AMP;
|
|
if (pusch_pdu->transform_precoding == transformPrecoder_enabled)
|
|
tx_precoding[nl][sample_offsetF] = c16mulRealShift(dmrs_seq[dmrs_idx], tmp, 15);
|
|
else
|
|
tx_precoding[nl][sample_offsetF] = c16mulRealShift(mod_dmrs[dmrs_idx], tmp, 15);
|
|
|
|
#ifdef DEBUG_PUSCH_MAPPING
|
|
printf("DMRS: Layer: %d\t, dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t dmrs: %d %d\n",
|
|
nl,
|
|
dmrs_idx,
|
|
l,
|
|
k,
|
|
k_prime,
|
|
n,
|
|
tx_precoding[nl][sample_offsetF].r,
|
|
tx_precoding[nl][sample_offsetF].i);
|
|
#endif
|
|
|
|
dmrs_idx++;
|
|
k_prime++;
|
|
k_prime &= 1;
|
|
n += (k_prime) ? 0 : 1;
|
|
|
|
} else if (is_ptrs == 1) {
|
|
uint16_t beta_ptrs = 1; // temp value until power control is implemented
|
|
tx_precoding[nl][sample_offsetF] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * AMP, 15);
|
|
ptrs_idx++;
|
|
} else if (!is_dmrs_sym
|
|
|| allowed_xlsch_re_in_dmrs_symbol(k, start_sc, frame_parms->ofdm_symbol_size, cdm_grps_no_data, dmrs_type)) {
|
|
if (pusch_pdu->transform_precoding == transformPrecoder_disabled)
|
|
tx_precoding[nl][sample_offsetF] = tx_layers[nl][m];
|
|
else
|
|
tx_precoding[nl][sample_offsetF] = y[m];
|
|
|
|
#ifdef DEBUG_PUSCH_MAPPING
|
|
printf("DATA: layer %d\t m %d\t l %d \t k %d \t tx_precoding: %d %d\n",
|
|
nl,
|
|
m,
|
|
l,
|
|
k,
|
|
tx_precoding[nl][sample_offsetF].r,
|
|
tx_precoding[nl][sample_offsetF].i);
|
|
#endif
|
|
|
|
m++;
|
|
|
|
} else {
|
|
tx_precoding[nl][sample_offsetF] = (c16_t){0};
|
|
}
|
|
|
|
if (++k >= frame_parms->ofdm_symbol_size)
|
|
k -= frame_parms->ofdm_symbol_size;
|
|
} // for (i=0; i< nb_rb*NR_NB_SC_PER_RB; i++)
|
|
} // for (l=start_symbol; l<start_symbol+number_of_symbols; l++)
|
|
} // for (nl=0; nl < Nl; nl++)
|
|
|
|
/////////////////////////ULSCH precoding/////////////////////////
|
|
///////////
|
|
/// Layer Precoding and Antenna port mapping
|
|
// tx_layers 0-3 are mapped on antenna ports
|
|
// The precoding info is supported by nfapi such as num_prgs, prg_size, prgs_list and pm_idx
|
|
// The same precoding matrix is applied on prg_size RBs, Thus
|
|
// pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1
|
|
// The Precoding matrix:
|
|
for (int ap = 0; ap < frame_parms->nb_antennas_tx; ap++) {
|
|
for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) {
|
|
uint16_t k = start_sc;
|
|
|
|
for (int rb = 0; rb < nb_rb; rb++) {
|
|
// get pmi info
|
|
uint8_t pmi = pusch_pdu->Tpmi;
|
|
|
|
if (pmi == 0) { // unitary Precoding
|
|
if (k + NR_NB_SC_PER_RB <= frame_parms->ofdm_symbol_size) { // RB does not cross DC
|
|
if (ap < pusch_pdu->nrOfLayers)
|
|
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k],
|
|
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size + k],
|
|
NR_NB_SC_PER_RB * sizeof(c16_t));
|
|
else
|
|
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k], 0, NR_NB_SC_PER_RB * sizeof(int32_t));
|
|
} else { // RB does cross DC
|
|
int neg_length = frame_parms->ofdm_symbol_size - k;
|
|
int pos_length = NR_NB_SC_PER_RB - neg_length;
|
|
if (ap < pusch_pdu->nrOfLayers) {
|
|
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k],
|
|
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size + k],
|
|
neg_length * sizeof(c16_t));
|
|
memcpy(&txdataF[ap][l * frame_parms->ofdm_symbol_size],
|
|
&tx_precoding[ap][l * frame_parms->ofdm_symbol_size],
|
|
pos_length * sizeof(int32_t));
|
|
} else {
|
|
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size + k], 0, neg_length * sizeof(int32_t));
|
|
memset(&txdataF[ap][l * frame_parms->ofdm_symbol_size], 0, pos_length * sizeof(int32_t));
|
|
}
|
|
}
|
|
k += NR_NB_SC_PER_RB;
|
|
if (k >= frame_parms->ofdm_symbol_size) {
|
|
k -= frame_parms->ofdm_symbol_size;
|
|
}
|
|
} else {
|
|
// get the precoding matrix weights:
|
|
const char *W_prec;
|
|
switch (frame_parms->nb_antennas_tx) {
|
|
case 1: // 1 antenna port
|
|
W_prec = nr_W_1l_2p[pmi][ap];
|
|
break;
|
|
case 2: // 2 antenna ports
|
|
if (pusch_pdu->nrOfLayers == 1) // 1 layer
|
|
W_prec = nr_W_1l_2p[pmi][ap];
|
|
else // 2 layers
|
|
W_prec = nr_W_2l_2p[pmi][ap];
|
|
break;
|
|
case 4: // 4 antenna ports
|
|
if (pusch_pdu->nrOfLayers == 1) // 1 layer
|
|
W_prec = nr_W_1l_4p[pmi][ap];
|
|
else if (pusch_pdu->nrOfLayers == 2) // 2 layers
|
|
W_prec = nr_W_2l_4p[pmi][ap];
|
|
else if (pusch_pdu->nrOfLayers == 3) // 3 layers
|
|
W_prec = nr_W_3l_4p[pmi][ap];
|
|
else // 4 layers
|
|
W_prec = nr_W_4l_4p[pmi][ap];
|
|
break;
|
|
default:
|
|
LOG_D(PHY, "Precoding 1,2, or 4 antenna ports are currently supported\n");
|
|
W_prec = nr_W_1l_2p[pmi][ap];
|
|
break;
|
|
}
|
|
|
|
for (int i = 0; i < NR_NB_SC_PER_RB; i++) {
|
|
int32_t re_offset = l * frame_parms->ofdm_symbol_size + k;
|
|
txdataF[ap][re_offset] = nr_layer_precoder(encoded_length, tx_precoding, W_prec, pusch_pdu->nrOfLayers, re_offset);
|
|
if (++k >= frame_parms->ofdm_symbol_size) {
|
|
k -= frame_parms->ofdm_symbol_size;
|
|
}
|
|
}
|
|
}
|
|
} // RB loop
|
|
} // symbol loop
|
|
} // port loop
|
|
|
|
NR_UL_UE_HARQ_t *harq_process_ulsch = NULL;
|
|
harq_process_ulsch = &UE->ul_harq_processes[harq_pid];
|
|
harq_process_ulsch->ULstatus = SCH_IDLE;
|
|
///////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
|
|
const uint8_t slot,
|
|
const NR_DL_FRAME_PARMS *frame_parms,
|
|
const uint8_t n_antenna_ports,
|
|
c16_t **txdataF,
|
|
uint32_t linktype)
|
|
{
|
|
const int tx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
|
|
|
int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL;
|
|
|
|
c16_t **txdata = UE->common_vars.txData;
|
|
for(int ap = 0; ap < n_antenna_ports; ap++) {
|
|
apply_nr_rotation_TX(frame_parms,
|
|
txdataF[ap],
|
|
frame_parms->symbol_rotation[linktype],
|
|
slot,
|
|
N_RB,
|
|
0,
|
|
NR_NUMBER_OF_SYMBOLS_PER_SLOT);
|
|
}
|
|
|
|
for (int ap = 0; ap < n_antenna_ports; ap++) {
|
|
if (frame_parms->Ncp == 1) { // extended cyclic prefix
|
|
PHY_ofdm_mod((int *)txdataF[ap],
|
|
(int *)&txdata[ap][tx_offset],
|
|
frame_parms->ofdm_symbol_size,
|
|
12,
|
|
frame_parms->nb_prefix_samples,
|
|
CYCLIC_PREFIX);
|
|
} else { // normal cyclic prefix
|
|
nr_normal_prefix_mod(txdataF[ap],
|
|
&txdata[ap][tx_offset],
|
|
14,
|
|
frame_parms,
|
|
slot);
|
|
}
|
|
}
|
|
|
|
///////////
|
|
////////////////////////////////////////////////////
|
|
return 0;
|
|
}
|