mirror of https://github.com/PentHertz/srsLTE.git
Initial NR PDSCH encode/decode
This commit is contained in:
parent
666ba7d590
commit
fb64c2a460
|
@ -59,6 +59,7 @@ extern "C" {
|
|||
#define SRSLTE_MAX_LAYERS 4
|
||||
#define SRSLTE_MAX_CODEWORDS 2
|
||||
#define SRSLTE_MAX_TB SRSLTE_MAX_CODEWORDS
|
||||
#define SRSLTE_MAX_QM 8
|
||||
|
||||
#define SRSLTE_MAX_CODEBLOCKS 32
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ extern "C" {
|
|||
*/
|
||||
#define SRSLTE_SLOT_LEN_RE_NR(nof_prb) (nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR)
|
||||
|
||||
#define SRSLTE_SLOT_MAX_LEN_RE_NR (SRSLTE_SLOT_LEN_RE_NR(SRSLTE_MAX_PRB_NR))
|
||||
#define SRSLTE_SLOT_MAX_NOF_BITS_NR (SRSLTE_SLOT_MAX_LEN_RE_NR * SRSLTE_MAX_QM)
|
||||
#define SRSLTE_MAX_LAYERS_NR 8
|
||||
|
||||
/**
|
||||
* @brief Defines the maximum numerology supported. Defined by TS 38.211 v15.8.0 Table 4.3.2-1.
|
||||
*/
|
||||
|
@ -249,15 +253,6 @@ typedef struct SRSLTE_API {
|
|||
uint32_t n_cce;
|
||||
} srslte_pdcch_cfg_nr_t;
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
uint32_t max_mimo_layers; ///< @brief DL: Indicates the maximum number of MIMO layers to be used for PDSCH in all BWPs
|
||||
///< of this serving cell. (see TS 38.212 [17], clause 5.4.2.1). UL: Indicates the maximum
|
||||
///< MIMO layer to be used for PUSCH in all BWPs of the normal UL of this serving cell (see
|
||||
///< TS 38.212 [17], clause 5.4.2.1)
|
||||
srslte_xoverhead_t xoverhead; ///< Accounts for overhead from CSI-RS, CORESET, etc. If the field is absent, the UE
|
||||
///< applies value xOh0 (see TS 38.214 [19], clause 5.1.3.2).
|
||||
} srslte_serving_cell_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Calculates the bandwidth of a given CORESET in physical resource blocks (PRB) . This function uses the
|
||||
* frequency domain resources bit-map for counting the number of PRB.
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define SRSLTE_PDSCH_CFG_NR_H
|
||||
|
||||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/fec/softbuffer.h"
|
||||
#include "srslte/phy/phch/sch_cfg_nr.h"
|
||||
|
||||
/**
|
||||
* @brief PDSCH DMRS type
|
||||
|
@ -136,6 +136,8 @@ typedef struct SRSLTE_API {
|
|||
/// Transport block
|
||||
uint32_t tb_scaling_field;
|
||||
/// ....
|
||||
|
||||
srslte_sch_tb_t tb[SRSLTE_MAX_TB];
|
||||
} srslte_pdsch_grant_nr_t;
|
||||
|
||||
/**
|
||||
|
@ -149,11 +151,8 @@ typedef struct SRSLTE_API {
|
|||
|
||||
srslte_pdsch_dmrs_cfg_t dmrs_cfg_typeA;
|
||||
srslte_pdsch_dmrs_cfg_t dmrs_cfg_typeB;
|
||||
srslte_mcs_table_t mcs_table;
|
||||
|
||||
/// Parameters provided by PDSCH-ServingCellConfig
|
||||
srslte_serving_cell_cfg_t serving_cell_cfg;
|
||||
|
||||
srslte_sch_cfg_t sch_cfg; ///< Common shared channel parameters
|
||||
} srslte_pdsch_cfg_nr_t;
|
||||
|
||||
#endif // SRSLTE_PDSCH_CFG_NR_H
|
||||
|
|
|
@ -34,14 +34,22 @@
|
|||
#include "srslte/phy/ch_estimation/dmrs_pdsch.h"
|
||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||
#include "srslte/phy/phch/regs.h"
|
||||
#include "srslte/phy/phch/sch.h"
|
||||
#include "srslte/phy/phch/sch_nr.h"
|
||||
#include "srslte/phy/scrambling/scrambling.h"
|
||||
|
||||
/**
|
||||
* @brief PDSCH NR object
|
||||
*/
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_carrier_nr_t carrier;
|
||||
uint32_t max_prb; ///< Maximum number of allocated prb
|
||||
uint32_t max_layers; ///< Maximum number of allocated layers
|
||||
uint32_t max_cw; ///< Maximum number of allocated code words
|
||||
srslte_carrier_nr_t carrier; ///< NR carrier configuration
|
||||
srslte_sch_nr_t sch; ///< SCH Encoder/Decoder Object
|
||||
uint8_t* b[SRSLTE_MAX_CODEWORDS]; ///< SCH Encoded and scrambled data
|
||||
cf_t* d[SRSLTE_MAX_CODEWORDS]; ///< PDSCH modulated bits
|
||||
cf_t* x[SRSLTE_MAX_LAYERS_NR]; ///< PDSCH modulated bits
|
||||
srslte_modem_table_t modem_tables[SRSLTE_MOD_NITEMS]; ///< Modulator tables
|
||||
} srslte_pdsch_nr_t;
|
||||
|
||||
/**
|
||||
|
@ -50,39 +58,30 @@ typedef struct SRSLTE_API {
|
|||
typedef struct {
|
||||
uint8_t* payload;
|
||||
bool crc;
|
||||
float avg_iterations_block;
|
||||
float evm;
|
||||
} srslte_pdsch_res_nr_t;
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_init_ue(srslte_pdsch_nr_t* q);
|
||||
SRSLTE_API int srslte_pdsch_nr_init_tx(srslte_pdsch_nr_t* q);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_init_enb(srslte_pdsch_nr_t* q);
|
||||
SRSLTE_API int srslte_pdsch_nr_init_rx(srslte_pdsch_nr_t* q);
|
||||
|
||||
SRSLTE_API void srslte_pdsch_nr_free(srslte_pdsch_nr_t* q);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_set_carrier(srslte_pdsch_nr_t* q, srslte_cell_t cell);
|
||||
SRSLTE_API int
|
||||
srslte_pdsch_nr_set_carrier(srslte_pdsch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_sch_cfg_t* sch_cfg);
|
||||
|
||||
/* These functions do not modify the state and run in real-time */
|
||||
SRSLTE_API int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q,
|
||||
uint32_t slot_idx,
|
||||
srslte_pdsch_cfg_nr_t* cfg,
|
||||
uint8_t* data[SRSLTE_MAX_CODEWORDS],
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS]);
|
||||
SRSLTE_API int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint8_t* data[SRSLTE_MAX_TB],
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS]);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q,
|
||||
uint32_t slot_idx,
|
||||
srslte_pdsch_cfg_nr_t* cfg,
|
||||
srslte_chest_dl_res_t* channel,
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS],
|
||||
srslte_pdsch_res_nr_t data[SRSLTE_MAX_CODEWORDS]);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_select_pmi(srslte_pdsch_nr_t* q,
|
||||
srslte_chest_dl_res_t* channel,
|
||||
uint32_t nof_layers,
|
||||
uint32_t* best_pmi,
|
||||
float sinr[SRSLTE_MAX_CODEBOOKS]);
|
||||
|
||||
SRSLTE_API int srslte_pdsch_nr_compute_cn(srslte_pdsch_nr_t* q, srslte_chest_dl_res_t* channel, float* cn);
|
||||
SRSLTE_API int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
srslte_chest_dl_res_t* channel,
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS],
|
||||
srslte_pdsch_res_nr_t data[SRSLTE_MAX_TB]);
|
||||
|
||||
SRSLTE_API uint32_t srslte_pdsch_nr_grant_rx_info(srslte_pdsch_grant_nr_t* grant,
|
||||
srslte_pdsch_res_nr_t res[SRSLTE_MAX_CODEWORDS],
|
||||
|
|
|
@ -37,29 +37,14 @@
|
|||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||
|
||||
/**************************************************
|
||||
* Common structures used for Resource Allocation
|
||||
**************************************************/
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_mod_t mod;
|
||||
uint32_t N_L; ///< the number of transmission layers that the transport block is mapped onto
|
||||
int tbs; ///< Payload size, TS 38.212 refers to it as A
|
||||
double R; ///< Target LDPC rate
|
||||
int rv;
|
||||
uint32_t nof_bits; ///< Number of available bits to send, known as G
|
||||
uint32_t cw_idx;
|
||||
bool enabled;
|
||||
|
||||
// this is for debugging and metrics purposes
|
||||
uint32_t mcs_idx;
|
||||
|
||||
/// Soft-buffers pointers
|
||||
union {
|
||||
srslte_softbuffer_tx_t* tx;
|
||||
srslte_softbuffer_rx_t* rx;
|
||||
} softbuffer;
|
||||
} srslte_ra_tb_nr_t;
|
||||
/**
|
||||
* @brief Determines the number of resource elements available for a given PDSCH transmission
|
||||
* @param pdsch_cfg PDSCH configuration provided by higher layers
|
||||
* @param grant The given PDSCH transmission grant
|
||||
* @return The number of resource elements if the provided configuration is valid, otherwise SRSLTE_ERROR code
|
||||
*/
|
||||
SRSLTE_API int srslte_ra_dl_nr_slot_nof_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant);
|
||||
|
||||
/**
|
||||
* @brief Calculates shared channel TBS
|
||||
|
@ -75,5 +60,5 @@ SRSLTE_API uint32_t srslte_ra_nr_tbs(uint32_t N_re, double S, double R, uint32_t
|
|||
SRSLTE_API int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t mcs_idx,
|
||||
srslte_ra_tb_nr_t* tb);
|
||||
srslte_sch_tb_t* tb);
|
||||
#endif // SRSLTE_RA_NR_H
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_SCH_CFG_NR_H
|
||||
#define SRSLTE_SCH_CFG_NR_H
|
||||
|
||||
#include "srslte/phy/fec/softbuffer.h"
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_mcs_table_t mcs_table; ///< @brief Indicates the MCS table the UE shall use for PDSCH and/or PUSCH without
|
||||
///< transform precoding
|
||||
uint32_t max_mimo_layers; ///< @brief DL: Indicates the maximum number of MIMO layers to be used for PDSCH in all BWPs
|
||||
///< of this serving cell. (see TS 38.212 [17], clause 5.4.2.1). UL: Indicates the maximum
|
||||
///< MIMO layer to be used for PUSCH in all BWPs of the normal UL of this serving cell (see
|
||||
///< TS 38.212 [17], clause 5.4.2.1)
|
||||
srslte_xoverhead_t xoverhead; ///< Accounts for overhead from CSI-RS, CORESET, etc. If the field is absent, the UE
|
||||
///< applies value xOh0 (see TS 38.214 [19], clause 5.1.3.2).
|
||||
} srslte_sch_cfg_t;
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_mod_t mod;
|
||||
uint32_t N_L; ///< the number of transmission layers that the transport block is mapped onto
|
||||
int tbs; ///< Payload size, TS 38.212 refers to it as A
|
||||
double R; ///< Target LDPC rate
|
||||
int rv;
|
||||
uint32_t nof_bits; ///< Number of available bits to send, known as G
|
||||
uint32_t cw_idx;
|
||||
bool enabled;
|
||||
|
||||
/// Soft-buffers pointers
|
||||
union {
|
||||
srslte_softbuffer_tx_t* tx;
|
||||
srslte_softbuffer_rx_t* rx;
|
||||
} softbuffer;
|
||||
} srslte_sch_tb_t;
|
||||
|
||||
#endif // SRSLTE_SCH_CFG_NR_H
|
|
@ -37,11 +37,9 @@
|
|||
#include "srslte/phy/fec/ldpc/ldpc_encoder.h"
|
||||
#include "srslte/phy/fec/ldpc/ldpc_rm.h"
|
||||
#include "srslte/phy/phch/pdsch_cfg_nr.h"
|
||||
#include "srslte/phy/phch/ra_nr.h"
|
||||
|
||||
#define SRSLTE_SCH_NR_MAX_NOF_CB_LDPC \
|
||||
((SRSLTE_MAX_PRB_NR * SRSLTE_NRE * 8 * SRSLTE_NSYMB_PER_SLOT_NR + (SRSLTE_LDPC_BG2_MAX_LEN_CB - 1)) / \
|
||||
SRSLTE_LDPC_BG2_MAX_LEN_CB)
|
||||
((SRSLTE_SLOT_MAX_NOF_BITS_NR + (SRSLTE_LDPC_BG2_MAX_LEN_CB - 1)) / SRSLTE_LDPC_BG2_MAX_LEN_CB)
|
||||
|
||||
typedef struct SRSLTE_API {
|
||||
srslte_carrier_nr_t carrier;
|
||||
|
@ -113,15 +111,15 @@ SRSLTE_API srslte_basegraph_t srslte_sch_nr_select_basegraph(uint32_t tbs, doubl
|
|||
|
||||
/**
|
||||
* @brief Calculates all the parameters required for performing TS 38.212 V15.9.0 5.4 General procedures for LDPC
|
||||
* @param pdsch_cfg Provides higher layers configuration
|
||||
* @param sch_cfg Provides higher layers configuration
|
||||
* @param tb Provides transport block configuration
|
||||
* @param cfg SCH object
|
||||
* @return
|
||||
*/
|
||||
SRSLTE_API int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
srslte_sch_nr_common_cfg_t* cfg);
|
||||
SRSLTE_API int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* sch_cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
srslte_sch_nr_common_cfg_t* cfg);
|
||||
|
||||
SRSLTE_API int srslte_sch_nr_init_tx(srslte_sch_nr_t* q);
|
||||
|
||||
|
@ -131,19 +129,19 @@ SRSLTE_API int srslte_sch_nr_set_carrier(srslte_sch_nr_t* q, const srslte_carrie
|
|||
|
||||
SRSLTE_API void srslte_sch_nr_free(srslte_sch_nr_t* q);
|
||||
|
||||
SRSLTE_API int srslte_dlsch_nr_encode(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
const uint8_t* data,
|
||||
uint8_t* e_bits);
|
||||
SRSLTE_API int srslte_dlsch_nr_encode(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
const uint8_t* data,
|
||||
uint8_t* e_bits);
|
||||
|
||||
SRSLTE_API int srslte_sch_nr_decoder_set_carrier(srslte_sch_nr_t* q, const srslte_carrier_nr_t* carrier);
|
||||
|
||||
SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
int8_t* e_bits,
|
||||
uint8_t* data,
|
||||
bool* crc_ok);
|
||||
SRSLTE_API int srslte_dlsch_nr_decode(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* sch_cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
int8_t* e_bits,
|
||||
uint8_t* data,
|
||||
bool* crc_ok);
|
||||
|
||||
#endif // SRSLTE_SCH_NR_H
|
|
@ -670,7 +670,7 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
|
|||
const srslte_pdsch_dmrs_cfg_t* dmrs_cfg =
|
||||
grant->mapping == srslte_pdsch_mapping_type_A ? &pdsch_cfg->dmrs_cfg_typeA : &pdsch_cfg->dmrs_cfg_typeB;
|
||||
|
||||
cf_t* ce = chest_res->ce[0][0];
|
||||
cf_t* ce = q->temp;
|
||||
uint32_t symbol_sz = q->carrier.nof_prb * SRSLTE_NRE; // Symbol size in resource elements
|
||||
|
||||
// Get symbols indexes
|
||||
|
@ -722,13 +722,41 @@ int srslte_dmrs_pdsch_estimate(srslte_dmrs_pdsch_t* q,
|
|||
srslte_interp_linear_offset(&q->interpolator_type2, q->pilot_estimates, ce, delta, 3 - delta);
|
||||
}
|
||||
|
||||
// Time domain hold
|
||||
for (uint32_t i = 1; i < grant->L; i++) {
|
||||
srslte_vec_cf_copy(&ce[i * nof_re_x_symbol], ce, nof_re_x_symbol);
|
||||
}
|
||||
// Time domain hold, extract resource elements estimates for PDSCH
|
||||
uint32_t symbol_idx = 0;
|
||||
uint32_t count = 0;
|
||||
for (uint32_t l = grant->S; l < grant->L; l++) {
|
||||
while (symbols[symbol_idx] < l && symbol_idx < nof_symbols) {
|
||||
symbol_idx++;
|
||||
}
|
||||
|
||||
if (symbols[symbol_idx] == l) {
|
||||
switch (dmrs_cfg->type) {
|
||||
|
||||
case srslte_dmrs_pdsch_type_1:
|
||||
for (uint32_t i = 0; i < nof_re_x_symbol; i++) {
|
||||
if (i % 2 != delta) {
|
||||
chest_res->ce[0][0][count] = ce[i];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case srslte_dmrs_pdsch_type_2:
|
||||
for (uint32_t i = 0; i < nof_re_x_symbol; i++) {
|
||||
if ((i % 6 != delta) && (i % 6 != delta + 1)) {
|
||||
chest_res->ce[0][0][count] = ce[i];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
srslte_vec_cf_copy(&chest_res->ce[0][0][count], ce, nof_re_x_symbol);
|
||||
count += nof_re_x_symbol;
|
||||
}
|
||||
}
|
||||
// Set other values in the estimation result
|
||||
chest_res->nof_re = nof_re_x_symbol * grant->L;
|
||||
chest_res->nof_re = count;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -19,6 +19,148 @@
|
|||
*
|
||||
*/
|
||||
#include "srslte/phy/phch/pdsch_nr.h"
|
||||
#include "srslte/phy/common/phy_common_nr.h"
|
||||
|
||||
int pdsch_nr_init_common(srslte_pdsch_nr_t* q)
|
||||
{
|
||||
for (srslte_mod_t mod = SRSLTE_MOD_BPSK; mod < SRSLTE_MOD_NITEMS; mod++) {
|
||||
if (srslte_modem_table_lte(&q->modem_tables[mod], mod) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error initialising modem table for %s\n", srslte_mod_string(mod));
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_init_tx(srslte_pdsch_nr_t* q)
|
||||
{
|
||||
|
||||
if (q == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (pdsch_nr_init_common(q) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
if (srslte_sch_nr_init_tx(&q->sch)) {
|
||||
ERROR("Initialising SCH\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_init_rx(srslte_pdsch_nr_t* q)
|
||||
{
|
||||
|
||||
if (q == NULL) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (pdsch_nr_init_common(q) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
srslte_sch_nr_decoder_cfg_t decoder_cfg = {};
|
||||
if (srslte_sch_nr_init_rx(&q->sch, &decoder_cfg)) {
|
||||
ERROR("Initialising SCH\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_set_carrier(srslte_pdsch_nr_t* q,
|
||||
const srslte_carrier_nr_t* carrier,
|
||||
const srslte_sch_cfg_t* sch_cfg)
|
||||
{
|
||||
// Set carrier
|
||||
q->carrier = *carrier;
|
||||
|
||||
// Reallocate symbols if necessary
|
||||
if (q->max_layers < sch_cfg->max_mimo_layers || q->max_prb < carrier->nof_prb) {
|
||||
q->max_layers = sch_cfg->max_mimo_layers;
|
||||
q->max_prb = carrier->nof_prb;
|
||||
|
||||
// Free current allocations
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) {
|
||||
if (q->x[i] != NULL) {
|
||||
free(q->x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate for new sizes
|
||||
for (uint32_t i = 0; i < q->max_layers; i++) {
|
||||
q->x[i] = srslte_vec_cf_malloc(SRSLTE_SLOT_LEN_RE_NR(q->max_prb));
|
||||
if (q->x[i] == NULL) {
|
||||
ERROR("Malloc");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate code words according to table 7.3.1.3-1
|
||||
uint32_t max_cw = (q->max_layers > 5) ? 2 : 1;
|
||||
if (q->max_cw < max_cw) {
|
||||
q->max_cw = max_cw;
|
||||
|
||||
for (uint32_t i = 0; i < max_cw; i++) {
|
||||
if (q->b[i] == NULL) {
|
||||
q->b[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR);
|
||||
if (q->b[i] == NULL) {
|
||||
ERROR("Malloc");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (q->d[i] == NULL) {
|
||||
q->d[i] = srslte_vec_cf_malloc(SRSLTE_SLOT_MAX_LEN_RE_NR);
|
||||
if (q->d[i] == NULL) {
|
||||
ERROR("Malloc");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set carrier in SCH
|
||||
if (srslte_sch_nr_set_carrier(&q->sch, carrier) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void srslte_pdsch_nr_free(srslte_pdsch_nr_t* q)
|
||||
{
|
||||
if (q == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) {
|
||||
if (q->b[cw]) {
|
||||
free(q->b[cw]);
|
||||
}
|
||||
|
||||
if (q->d[cw]) {
|
||||
free(q->d[cw]);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_sch_nr_free(&q->sch);
|
||||
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) {
|
||||
if (q->x[i]) {
|
||||
free(q->x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (srslte_mod_t mod = SRSLTE_MOD_BPSK; mod < SRSLTE_MOD_NITEMS; mod++) {
|
||||
srslte_modem_table_free(&q->modem_tables[mod]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copies a number of countiguous Resource Elements
|
||||
|
@ -197,21 +339,197 @@ static int srslte_pdsch_nr_cp(const srslte_pdsch_nr_t* q,
|
|||
return count;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_put(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols)
|
||||
static int srslte_pdsch_nr_put(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols)
|
||||
{
|
||||
return srslte_pdsch_nr_cp(q, cfg, grant, symbols, sf_symbols, true);
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q,
|
||||
uint32_t slot_idx,
|
||||
srslte_pdsch_cfg_nr_t* cfg,
|
||||
uint8_t* data[SRSLTE_MAX_CODEWORDS],
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS])
|
||||
static int srslte_pdsch_nr_get(const srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
cf_t* symbols,
|
||||
cf_t* sf_symbols)
|
||||
{
|
||||
return srslte_pdsch_nr_cp(q, cfg, grant, symbols, sf_symbols, false);
|
||||
}
|
||||
|
||||
static inline int pdsch_nr_encode_codeword(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
const uint8_t* data,
|
||||
uint16_t rnti)
|
||||
{
|
||||
// Early return if TB is not enabled
|
||||
if (!tb->enabled) {
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
// Check codeword index
|
||||
if (tb->cw_idx >= q->max_cw) {
|
||||
ERROR("Unsupported codeword index %d\n", tb->cw_idx);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Check modulation
|
||||
if (tb->mod >= SRSLTE_MOD_NITEMS) {
|
||||
ERROR("Invalid modulation %s\n", srslte_mod_string(tb->mod));
|
||||
return SRSLTE_ERROR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
// Encode SCH
|
||||
if (srslte_dlsch_nr_encode(&q->sch, &cfg->sch_cfg, tb, data, q->b[tb->cw_idx]) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error in DL-SCH encoding\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 7.3.1.1 Scrambling
|
||||
uint32_t n_id = q->carrier.id;
|
||||
if (cfg->scrambling_id_present && SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
n_id = cfg->scambling_id;
|
||||
}
|
||||
uint32_t cinit = ((uint32_t)rnti << 15U) + (tb->cw_idx << 14U) + n_id;
|
||||
srslte_sequence_apply_bit(q->b[tb->cw_idx], q->b[tb->cw_idx], tb->nof_bits, cinit);
|
||||
|
||||
// 7.3.1.2 Modulation
|
||||
srslte_mod_modulate(&q->modem_tables[tb->mod], q->b[tb->cw_idx], q->d[tb->cw_idx], tb->nof_bits);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_encode(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint8_t* data[SRSLTE_MAX_TB],
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS])
|
||||
{
|
||||
uint32_t nof_cw = 0;
|
||||
|
||||
// Check input pointers
|
||||
if (!q || !cfg || !grant || !data || !sf_symbols) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Check number of layers
|
||||
if (q->max_layers < grant->nof_layers) {
|
||||
ERROR("Error number of layers (%d) exceeds configured maximum (%d)\n", grant->nof_layers, q->max_layers);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// 7.3.1.1 and 7.3.1.2
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
nof_cw += grant->tb[tb].enabled ? 1 : 0;
|
||||
|
||||
if (pdsch_nr_encode_codeword(q, cfg, &grant->tb[tb], data[tb], grant->rnti) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding TB %d\n", tb);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// 7.3.1.3 Layer mapping
|
||||
cf_t** x = q->d;
|
||||
if (grant->nof_layers > 1) {
|
||||
x = q->x;
|
||||
srslte_layermap_nr(q->d, nof_cw, x, grant->nof_layers, grant->nof_layers);
|
||||
}
|
||||
|
||||
// 7.3.1.4 Antenna port mapping
|
||||
// ... Not implemented
|
||||
|
||||
// 7.3.1.5 Mapping to virtual resource blocks
|
||||
// ... Not implemented
|
||||
|
||||
// 7.3.1.6 Mapping from virtual to physical resource blocks
|
||||
srslte_pdsch_nr_put(q, cfg, grant, x[0], sf_symbols[0]);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int pdsch_nr_decode_codeword(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
srslte_pdsch_res_nr_t* res,
|
||||
uint16_t rnti)
|
||||
{
|
||||
// Early return if TB is not enabled
|
||||
if (!tb->enabled) {
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
// Check codeword index
|
||||
if (tb->cw_idx >= q->max_cw) {
|
||||
ERROR("Unsupported codeword index %d\n", tb->cw_idx);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Check modulation
|
||||
if (tb->mod >= SRSLTE_MOD_NITEMS) {
|
||||
ERROR("Invalid modulation %s\n", srslte_mod_string(tb->mod));
|
||||
return SRSLTE_ERROR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
// Demodulation
|
||||
cf_t** d = (tb->N_L > 1) ? q->d : q->x;
|
||||
int8_t* llr = (int8_t*)q->b;
|
||||
if (srslte_demod_soft_demodulate_b(tb->mod, d[tb->cw_idx], llr, tb->nof_bits)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Descrambling
|
||||
uint32_t n_id = q->carrier.id;
|
||||
if (cfg->scrambling_id_present && SRSLTE_RNTI_ISUSER(rnti)) {
|
||||
n_id = cfg->scambling_id;
|
||||
}
|
||||
uint32_t cinit = ((uint32_t)rnti << 15U) + (tb->cw_idx << 14U) + n_id;
|
||||
srslte_sequence_apply_c(llr, llr, tb->nof_bits, cinit);
|
||||
|
||||
// Decode SCH
|
||||
if (srslte_dlsch_nr_decode(&q->sch, &cfg->sch_cfg, tb, llr, res->payload, &res->crc) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error in DL-SCH encoding\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_pdsch_nr_decode(srslte_pdsch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
srslte_chest_dl_res_t* channel,
|
||||
cf_t* sf_symbols[SRSLTE_MAX_PORTS],
|
||||
srslte_pdsch_res_nr_t data[SRSLTE_MAX_TB])
|
||||
{
|
||||
uint32_t nof_cw = 0;
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
nof_cw += grant->tb[tb].enabled ? 1 : 0;
|
||||
}
|
||||
|
||||
// Demapping from virtual to physical resource blocks
|
||||
srslte_pdsch_nr_get(q, cfg, grant, q->x[0], sf_symbols[0]);
|
||||
|
||||
// Demapping to virtual resource blocks
|
||||
// ... Not implemented
|
||||
|
||||
// Antenna port demapping
|
||||
// ... Not implemented
|
||||
|
||||
// Layer demapping
|
||||
if (grant->nof_layers > 1) {
|
||||
srslte_layermap_nr(q->d, nof_cw, q->x, grant->nof_layers, grant->nof_layers);
|
||||
}
|
||||
|
||||
// SCH decode
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
nof_cw += grant->tb[tb].enabled ? 1 : 0;
|
||||
|
||||
if (pdsch_nr_decode_codeword(q, cfg, &grant->tb[tb], &data[tb], grant->rnti) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding TB %d\n", tb);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -209,7 +209,7 @@ srslte_mod_t srslte_ra_nr_mod_from_mcs(srslte_mcs_table_t mcs_table,
|
|||
return SRSLTE_MOD_NITEMS;
|
||||
}
|
||||
|
||||
static int ra_nr_determine_N_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant)
|
||||
int srslte_ra_dl_nr_slot_nof_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const srslte_pdsch_grant_nr_t* grant)
|
||||
{
|
||||
// the number of symbols of the PDSCH allocation within the slot
|
||||
int n_sh_symb = grant->L;
|
||||
|
@ -222,7 +222,7 @@ static int ra_nr_determine_N_re(const srslte_pdsch_cfg_nr_t* pdsch_cfg, const sr
|
|||
|
||||
// the overhead configured by higher layer parameter xOverhead in PDSCH-ServingCellConfig
|
||||
uint32_t n_prb_oh = 0;
|
||||
switch (pdsch_cfg->serving_cell_cfg.xoverhead) {
|
||||
switch (pdsch_cfg->sch_cfg.xoverhead) {
|
||||
case srslte_xoverhead_0:
|
||||
n_prb_oh = 0;
|
||||
break;
|
||||
|
@ -325,18 +325,20 @@ uint32_t srslte_ra_nr_tbs(uint32_t N_re, double S, double R, uint32_t Qm, uint32
|
|||
int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_pdsch_grant_nr_t* grant,
|
||||
uint32_t mcs_idx,
|
||||
srslte_ra_tb_nr_t* tb)
|
||||
srslte_sch_tb_t* tb)
|
||||
{
|
||||
uint32_t cw_idx = 0;
|
||||
|
||||
// Get target Rate
|
||||
double R =
|
||||
srslte_ra_nr_R_from_mcs(pdsch_cfg->mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
double R = srslte_ra_nr_R_from_mcs(
|
||||
pdsch_cfg->sch_cfg.mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
if (!isnormal(R)) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Get modulation
|
||||
srslte_mod_t m =
|
||||
srslte_ra_nr_mod_from_mcs(pdsch_cfg->mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
srslte_mod_t m = srslte_ra_nr_mod_from_mcs(
|
||||
pdsch_cfg->sch_cfg.mcs_table, grant->dci_format, grant->dci_search_space, grant->rnti, mcs_idx);
|
||||
if (m >= SRSLTE_MOD_NITEMS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -364,19 +366,23 @@ int srslte_ra_nr_fill_tb(const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
|||
}
|
||||
|
||||
// 1) The UE shall first determine the number of REs (N RE ) within the slot.
|
||||
int N_re = ra_nr_determine_N_re(pdsch_cfg, grant);
|
||||
int N_re = srslte_ra_dl_nr_slot_nof_re(pdsch_cfg, grant);
|
||||
if (N_re < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Calculate number of layers accordingly
|
||||
uint32_t nof_cw = grant->nof_layers < 5 ? 1 : 2;
|
||||
uint32_t nof_layers_cw1 = grant->nof_layers / nof_cw;
|
||||
uint32_t nof_layers_cw2 = grant->nof_layers - nof_layers_cw1;
|
||||
tb->N_L = (cw_idx == 0) ? nof_layers_cw1 : nof_layers_cw2;
|
||||
|
||||
// Steps 2,3,4
|
||||
tb->tbs = (int)srslte_ra_nr_tbs(N_re, S, R, Qm, grant->nof_layers);
|
||||
tb->tbs = (int)srslte_ra_nr_tbs(N_re, S, R, Qm, tb->N_L);
|
||||
tb->R = R;
|
||||
tb->mod = m;
|
||||
tb->nof_bits = N_re * Qm * grant->nof_layers;
|
||||
|
||||
// Calculate number of layers accordingly
|
||||
tb->N_L = grant->nof_layers;
|
||||
tb->enabled = true;
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
#include "srslte/phy/fec/cbsegm.h"
|
||||
#include "srslte/phy/fec/ldpc/ldpc_common.h"
|
||||
#include "srslte/phy/fec/ldpc/ldpc_rm.h"
|
||||
#include "srslte/phy/phch/ra_nr.h"
|
||||
#include "srslte/phy/utils/bit.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
|
@ -70,13 +71,13 @@ uint32_t sch_nr_n_prb_lbrm(uint32_t nof_prb)
|
|||
return 273;
|
||||
}
|
||||
|
||||
int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
srslte_sch_nr_common_cfg_t* cfg)
|
||||
int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* sch_cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
srslte_sch_nr_common_cfg_t* cfg)
|
||||
{
|
||||
|
||||
if (!pdsch_cfg || !tb || !cfg) {
|
||||
if (!sch_cfg || !tb || !cfg) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
|
@ -119,8 +120,8 @@ int srslte_dlsch_nr_fill_cfg(srslte_sch_nr_t* q,
|
|||
// Calculate Nref
|
||||
uint32_t N_re_lbrm = 156 * sch_nr_n_prb_lbrm(q->carrier.nof_prb);
|
||||
double R_lbrm = 948.0 / 1024.0;
|
||||
uint32_t Qm_lbrm = (pdsch_cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6;
|
||||
uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, R_lbrm, Qm_lbrm, pdsch_cfg->serving_cell_cfg.max_mimo_layers);
|
||||
uint32_t Qm_lbrm = (sch_cfg->mcs_table == srslte_mcs_table_256qam) ? 8 : 6;
|
||||
uint32_t TBS_LRBM = srslte_ra_nr_tbs(N_re_lbrm, 1.0, R_lbrm, Qm_lbrm, sch_cfg->max_mimo_layers);
|
||||
cfg->Nref = ceil(TBS_LRBM / (cbsegm.C * 2.0 / 3.0));
|
||||
|
||||
// Calculate number of code blocks after applying CBGTI... not implemented, activate all CB
|
||||
|
@ -354,11 +355,11 @@ void srslte_sch_nr_free(srslte_sch_nr_t* q)
|
|||
srslte_ldpc_rm_rx_free_c(&q->rx_rm);
|
||||
}
|
||||
|
||||
int srslte_dlsch_nr_encode(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
const uint8_t* data,
|
||||
uint8_t* e_bits)
|
||||
int srslte_dlsch_nr_encode(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* pdsch_cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
const uint8_t* data,
|
||||
uint8_t* e_bits)
|
||||
{
|
||||
// Pointer protection
|
||||
if (!q || !pdsch_cfg || !tb || !data || !e_bits) {
|
||||
|
@ -477,22 +478,22 @@ int srslte_dlsch_nr_encode(srslte_sch_nr_t* q,
|
|||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int srslte_dlsch_nr_decode(srslte_sch_nr_t* q,
|
||||
const srslte_pdsch_cfg_nr_t* pdsch_cfg,
|
||||
const srslte_ra_tb_nr_t* tb,
|
||||
int8_t* e_bits,
|
||||
uint8_t* data,
|
||||
bool* crc_ok)
|
||||
int srslte_dlsch_nr_decode(srslte_sch_nr_t* q,
|
||||
const srslte_sch_cfg_t* sch_cfg,
|
||||
const srslte_sch_tb_t* tb,
|
||||
int8_t* e_bits,
|
||||
uint8_t* data,
|
||||
bool* crc_ok)
|
||||
{
|
||||
// Pointer protection
|
||||
if (!q || !pdsch_cfg || !tb || !data || !e_bits || !crc_ok) {
|
||||
if (!q || !sch_cfg || !tb || !data || !e_bits || !crc_ok) {
|
||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
int8_t* input_ptr = e_bits;
|
||||
|
||||
srslte_sch_nr_common_cfg_t cfg = {};
|
||||
if (srslte_dlsch_nr_fill_cfg(q, pdsch_cfg, tb, &cfg) < SRSLTE_SUCCESS) {
|
||||
if (srslte_dlsch_nr_fill_cfg(q, sch_cfg, tb, &cfg) < SRSLTE_SUCCESS) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -625,3 +625,7 @@ endif(RF_FOUND)
|
|||
add_executable(dlsch_nr_test dlsch_nr_test.c)
|
||||
target_link_libraries(dlsch_nr_test srslte_phy)
|
||||
add_test(dlsch_nr_test dlsch_nr_test -m 0 -n 1)
|
||||
|
||||
add_executable(pdsch_nr_test pdsch_nr_test.c)
|
||||
target_link_libraries(pdsch_nr_test srslte_phy)
|
||||
add_test(pdsch_nr_test pdsch_nr_test)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "srslte/phy/phch/ra_nr.h"
|
||||
#include "srslte/phy/phch/sch_nr.h"
|
||||
#include "srslte/phy/ue/ue_dl_nr_data.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
|
@ -44,8 +45,8 @@ void usage(char* prog)
|
|||
printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb);
|
||||
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
|
||||
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
|
||||
srslte_mcs_table_to_str(pdsch_cfg.mcs_table));
|
||||
printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.serving_cell_cfg.max_mimo_layers);
|
||||
srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
|
||||
printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.sch_cfg.max_mimo_layers);
|
||||
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
|
@ -61,10 +62,10 @@ int parse_args(int argc, char** argv)
|
|||
mcs = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'T':
|
||||
pdsch_cfg.mcs_table = srslte_mcs_table_from_str(argv[optind]);
|
||||
pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_from_str(argv[optind]);
|
||||
break;
|
||||
case 'L':
|
||||
pdsch_cfg.serving_cell_cfg.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
pdsch_cfg.sch_cfg.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
|
@ -91,8 +92,8 @@ int main(int argc, char** argv)
|
|||
uint8_t* data_rx = srslte_vec_u8_malloc(1024 * 1024);
|
||||
|
||||
// Set default PDSCH configuration
|
||||
pdsch_cfg.mcs_table = srslte_mcs_table_64qam;
|
||||
pdsch_cfg.serving_cell_cfg.max_mimo_layers = 1;
|
||||
pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam;
|
||||
pdsch_cfg.sch_cfg.max_mimo_layers = 1;
|
||||
|
||||
if (parse_args(argc, argv) < SRSLTE_SUCCESS) {
|
||||
goto clean_exit;
|
||||
|
@ -108,7 +109,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
srslte_sch_nr_decoder_cfg_t decoder_cfg = {};
|
||||
decoder_cfg.disable_simd = true;
|
||||
decoder_cfg.disable_simd = false;
|
||||
if (srslte_sch_nr_init_rx(&sch_nr_rx, &decoder_cfg) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error initiating SCH NR for Rx\n");
|
||||
goto clean_exit;
|
||||
|
@ -145,7 +146,7 @@ int main(int argc, char** argv)
|
|||
ERROR("Error loading default grant\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
pdsch_grant.nof_layers = pdsch_cfg.serving_cell_cfg.max_mimo_layers;
|
||||
pdsch_grant.nof_layers = pdsch_cfg.sch_cfg.max_mimo_layers;
|
||||
pdsch_grant.dci_format = srslte_dci_format_nr_1_0;
|
||||
|
||||
uint32_t n_prb_start = 1;
|
||||
|
@ -156,7 +157,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
uint32_t mcs_start = 0;
|
||||
uint32_t mcs_end = pdsch_cfg.mcs_table == srslte_mcs_table_256qam ? 28 : 29;
|
||||
uint32_t mcs_end = pdsch_cfg.sch_cfg.mcs_table == srslte_mcs_table_256qam ? 28 : 29;
|
||||
if (mcs < mcs_end) {
|
||||
mcs_start = SRSLTE_MIN(mcs, mcs_end - 1);
|
||||
mcs_end = SRSLTE_MIN(mcs + 1, mcs_end);
|
||||
|
@ -169,7 +170,7 @@ int main(int argc, char** argv)
|
|||
pdsch_grant.prb_idx[n] = (n < n_prb);
|
||||
}
|
||||
|
||||
srslte_ra_tb_nr_t tb = {};
|
||||
srslte_sch_tb_t tb = {};
|
||||
if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &tb) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error filing tb\n");
|
||||
goto clean_exit;
|
||||
|
@ -181,7 +182,7 @@ int main(int argc, char** argv)
|
|||
|
||||
tb.softbuffer.tx = &softbuffer_tx;
|
||||
|
||||
if (srslte_dlsch_nr_encode(&sch_nr_tx, &pdsch_cfg, &tb, data_tx, encoded) < SRSLTE_SUCCESS) {
|
||||
if (srslte_dlsch_nr_encode(&sch_nr_tx, &pdsch_cfg.sch_cfg, &tb, data_tx, encoded) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
@ -194,7 +195,7 @@ int main(int argc, char** argv)
|
|||
srslte_softbuffer_rx_reset(tb.softbuffer.rx);
|
||||
|
||||
bool crc = false;
|
||||
if (srslte_dlsch_nr_decode(&sch_nr_rx, &pdsch_cfg, &tb, llr, data_rx, &crc) < SRSLTE_SUCCESS) {
|
||||
if (srslte_dlsch_nr_decode(&sch_nr_rx, &pdsch_cfg.sch_cfg, &tb, llr, data_rx, &crc) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srslte/phy/phch/pdsch_nr.h"
|
||||
#include "srslte/phy/phch/ra_nr.h"
|
||||
#include "srslte/phy/ue/ue_dl_nr_data.h"
|
||||
#include "srslte/phy/utils/debug.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include <getopt.h>
|
||||
#include <srslte/phy/utils/random.h>
|
||||
|
||||
static srslte_carrier_nr_t carrier = {
|
||||
0, // cell_id
|
||||
0, // numerology
|
||||
SRSLTE_MAX_PRB_NR, // nof_prb
|
||||
0 // start
|
||||
};
|
||||
|
||||
static uint32_t n_prb = 0; // Set to 0 for steering
|
||||
static uint32_t mcs = 30; // Set to 30 for steering
|
||||
static srslte_pdsch_cfg_nr_t pdsch_cfg = {};
|
||||
static srslte_pdsch_grant_nr_t pdsch_grant = {};
|
||||
|
||||
void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [pTL] \n", prog);
|
||||
printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb);
|
||||
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
|
||||
printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
|
||||
srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
|
||||
printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.sch_cfg.max_mimo_layers);
|
||||
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
int parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "pmTLv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
n_prb = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'm':
|
||||
mcs = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'T':
|
||||
pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_from_str(argv[optind]);
|
||||
break;
|
||||
case 'L':
|
||||
pdsch_cfg.sch_cfg.max_mimo_layers = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'v':
|
||||
srslte_verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = SRSLTE_ERROR;
|
||||
srslte_pdsch_nr_t pdsch_tx = {};
|
||||
srslte_pdsch_nr_t pdsch_rx = {};
|
||||
srslte_chest_dl_res_t chest = {};
|
||||
srslte_pdsch_res_nr_t pdsch_res[SRSLTE_MAX_TB] = {};
|
||||
srslte_random_t rand_gen = srslte_random_init(1234);
|
||||
|
||||
uint8_t* data_tx[SRSLTE_MAX_TB] = {};
|
||||
uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {};
|
||||
cf_t* sf_symbols[SRSLTE_MAX_LAYERS_NR] = {};
|
||||
|
||||
// Set default PDSCH configuration
|
||||
pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam;
|
||||
pdsch_cfg.sch_cfg.max_mimo_layers = 1;
|
||||
if (parse_args(argc, argv) < SRSLTE_SUCCESS) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_nr_init_tx(&pdsch_tx) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error initiating PDSCH for Tx\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
srslte_sch_nr_decoder_cfg_t decoder_cfg = {};
|
||||
decoder_cfg.disable_simd = false;
|
||||
if (srslte_pdsch_nr_init_rx(&pdsch_rx) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error initiating SCH NR for Rx\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_nr_set_carrier(&pdsch_tx, &carrier, &pdsch_cfg.sch_cfg)) {
|
||||
ERROR("Error setting SCH NR carrier\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_nr_set_carrier(&pdsch_rx, &carrier, &pdsch_cfg.sch_cfg)) {
|
||||
ERROR("Error setting SCH NR carrier\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < pdsch_cfg.sch_cfg.max_mimo_layers; i++) {
|
||||
sf_symbols[i] = srslte_vec_cf_malloc(SRSLTE_SLOT_LEN_RE_NR(carrier.nof_prb));
|
||||
if (sf_symbols[i] == NULL) {
|
||||
ERROR("Error malloc\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < pdsch_tx.max_cw; i++) {
|
||||
data_tx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
|
||||
data_rx[i] = srslte_vec_u8_malloc(SRSLTE_SLOT_MAX_NOF_BITS_NR);
|
||||
if (data_tx[i] == NULL || data_rx[i] == NULL) {
|
||||
ERROR("Error malloc\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
pdsch_res[i].payload = data_rx[i];
|
||||
}
|
||||
|
||||
srslte_softbuffer_tx_t softbuffer_tx = {};
|
||||
srslte_softbuffer_rx_t softbuffer_rx = {};
|
||||
|
||||
if (srslte_softbuffer_tx_init_guru(&softbuffer_tx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) <
|
||||
SRSLTE_SUCCESS) {
|
||||
ERROR("Error init soft-buffer\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srslte_softbuffer_rx_init_guru(&softbuffer_rx, SRSLTE_SCH_NR_MAX_NOF_CB_LDPC, SRSLTE_LDPC_MAX_LEN_ENCODED_CB) <
|
||||
SRSLTE_SUCCESS) {
|
||||
ERROR("Error init soft-buffer\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// Use grant default A time resources with m=0
|
||||
if (srslte_ue_dl_nr_pdsch_time_resource_default_A(0, pdsch_cfg.dmrs_cfg_typeA.typeA_pos, &pdsch_grant) <
|
||||
SRSLTE_SUCCESS) {
|
||||
ERROR("Error loading default grant\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
pdsch_grant.nof_layers = pdsch_cfg.sch_cfg.max_mimo_layers;
|
||||
pdsch_grant.dci_format = srslte_dci_format_nr_1_0;
|
||||
|
||||
uint32_t n_prb_start = 1;
|
||||
uint32_t n_prb_end = carrier.nof_prb + 1;
|
||||
if (n_prb > 0) {
|
||||
n_prb_start = SRSLTE_MIN(n_prb, n_prb_end - 1);
|
||||
n_prb_end = SRSLTE_MIN(n_prb + 1, n_prb_end);
|
||||
}
|
||||
|
||||
uint32_t mcs_start = 0;
|
||||
uint32_t mcs_end = pdsch_cfg.sch_cfg.mcs_table == srslte_mcs_table_256qam ? 28 : 29;
|
||||
if (mcs < mcs_end) {
|
||||
mcs_start = SRSLTE_MIN(mcs, mcs_end - 1);
|
||||
mcs_end = SRSLTE_MIN(mcs + 1, mcs_end);
|
||||
}
|
||||
|
||||
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
|
||||
for (mcs = mcs_start; mcs < mcs_end; mcs++) {
|
||||
|
||||
for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) {
|
||||
pdsch_grant.prb_idx[n] = (n < n_prb);
|
||||
}
|
||||
|
||||
if (srslte_ra_nr_fill_tb(&pdsch_cfg, &pdsch_grant, mcs, &pdsch_grant.tb[0]) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error filing tb\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
// Skip TB if no allocated
|
||||
if (data_tx[tb] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < pdsch_grant.tb[tb].tbs; i++) {
|
||||
data_tx[tb][i] = (uint8_t)srslte_random_uniform_int_dist(rand_gen, 0, UINT8_MAX);
|
||||
}
|
||||
pdsch_grant.tb[tb].softbuffer.tx = &softbuffer_tx;
|
||||
}
|
||||
|
||||
if (srslte_pdsch_nr_encode(&pdsch_tx, &pdsch_cfg, &pdsch_grant, data_tx, sf_symbols) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||||
pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx;
|
||||
srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx);
|
||||
}
|
||||
|
||||
if (srslte_pdsch_nr_decode(&pdsch_rx, &pdsch_cfg, &pdsch_grant, &chest, sf_symbols, pdsch_res) < SRSLTE_SUCCESS) {
|
||||
ERROR("Error encoding\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!pdsch_res[0].crc) {
|
||||
ERROR("Failed to match CRC; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs);
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (memcmp(data_tx, data_rx, pdsch_grant.tb[0].tbs / 8) != 0) {
|
||||
ERROR("Failed to match Tx/Rx data; n_prb=%d; mcs=%d; TBS=%d;\n", n_prb, mcs, pdsch_grant.tb[0].tbs);
|
||||
printf("Tx data: ");
|
||||
srslte_vec_fprint_byte(stdout, data_tx[0], pdsch_grant.tb[0].tbs / 8);
|
||||
printf("Rx data: ");
|
||||
srslte_vec_fprint_byte(stdout, data_rx[0], pdsch_grant.tb[0].tbs / 8);
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
printf("n_prb=%d; mcs=%d; TBS=%d; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = SRSLTE_SUCCESS;
|
||||
|
||||
clean_exit:
|
||||
srslte_random_free(rand_gen);
|
||||
srslte_pdsch_nr_free(&pdsch_tx);
|
||||
srslte_pdsch_nr_free(&pdsch_rx);
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (data_tx[i]) {
|
||||
free(data_tx[i]);
|
||||
}
|
||||
if (data_rx[i]) {
|
||||
free(data_rx[i]);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_LAYERS_NR; i++) {
|
||||
if (sf_symbols[i]) {
|
||||
free(sf_symbols[i]);
|
||||
}
|
||||
}
|
||||
srslte_softbuffer_tx_free(&softbuffer_tx);
|
||||
srslte_softbuffer_rx_free(&softbuffer_rx);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue