Integrated PUSCH decoder in gNb

master
Xavier Arteaga 3 years ago committed by Xavier Arteaga
parent f07d925be1
commit ecc0b92142

@ -44,7 +44,7 @@ public:
* @brief Carrier reference configuration for 10MHz serving cell bandwidth * @brief Carrier reference configuration for 10MHz serving cell bandwidth
* - CORESET: all channel, 1 symbol * - CORESET: all channel, 1 symbol
* - Single common Search Space * - Single common Search Space
* - 1 possible candidate per aggregation level * - 2 possible candidate per aggregation level to allow DL and UL grants simultaneously
*/ */
R_PDCCH_CUSTOM_COMMON_SS = 0, R_PDCCH_CUSTOM_COMMON_SS = 0,
} pdcch = R_PDCCH_CUSTOM_COMMON_SS; } pdcch = R_PDCCH_CUSTOM_COMMON_SS;

@ -242,9 +242,9 @@ public:
}; };
struct pusch_t { struct pusch_t {
uint32_t pid = 0; ///< HARQ process ID
srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration srsran_sch_cfg_nr_t sch = {}; ///< PUSCH configuration
std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer std::array<uint8_t*, SRSRAN_MAX_TB> data = {}; ///< Data pointer
std::array<srsran_softbuffer_tx_t*, SRSRAN_MAX_TB> softbuffer_tx = {}; ///< Tx Softbuffer
}; };
struct pucch_t { struct pucch_t {
@ -265,7 +265,9 @@ public:
struct pusch_info_t { struct pusch_info_t {
uint16_t rnti; uint16_t rnti;
uint32_t pid = 0; ///< HARQ process ID
srsran_pusch_res_nr_t pusch_data; srsran_pusch_res_nr_t pusch_data;
srsran_uci_cfg_nr_t uci_cfg; ///< Provides UCI configuration, so stack does not need to keep the pending state
// ... add signal measurements here // ... add signal measurements here
}; };

@ -65,4 +65,10 @@ SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q
char* str, char* str,
uint32_t str_len); uint32_t str_len);
SRSRAN_API uint32_t srsran_gnb_ul_pusch_info(srsran_gnb_ul_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len);
#endif // SRSRAN_GNB_UL_H #endif // SRSRAN_GNB_UL_H

@ -65,7 +65,7 @@ void phy_cfg_nr_default_t::make_pdcch_custom_common_ss(srsran_pdcch_cfg_nr_t& pd
// Generate 1 candidate for each aggregation level if possible // Generate 1 candidate for each aggregation level if possible
for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
pdcch.search_space[1].nof_candidates[L] = pdcch.search_space[1].nof_candidates[L] =
SRSRAN_MIN(1, srsran_pdcch_nr_max_candidates_coreset(&pdcch.coreset[1], L)); SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&pdcch.coreset[1], L));
} }
} }

@ -289,3 +289,22 @@ uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
return len; return len;
} }
uint32_t srsran_gnb_ul_pusch_info(srsran_gnb_ul_t* q,
const srsran_sch_cfg_nr_t* cfg,
const srsran_pusch_res_nr_t* res,
char* str,
uint32_t str_len)
{
if (q == NULL || cfg == NULL || res == NULL) {
return 0;
}
uint32_t len = 0;
len += srsran_pusch_nr_rx_info(&q->pusch, cfg, &cfg->grant, res, str, str_len - len);
len = srsran_print_check(str, str_len, len, "snr=%+.1f", q->chest_pusch.snr_db);
return len;
}

@ -190,7 +190,33 @@ bool slot_worker::work_ul()
// Decode PUSCH // Decode PUSCH
for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) { for (stack_interface_phy_nr::pusch_t& pusch : ul_sched.pusch) {
// ... // Get payload PDU
stack_interface_phy_nr::pusch_info_t pusch_info = {};
pusch_info.uci_cfg = pusch.sch.uci;
pusch_info.pid = pusch.pid;
pusch_info.pusch_data.tb[0].payload = pusch.data[0];
pusch_info.pusch_data.tb[1].payload = pusch.data[1];
// Decode PUCCH
if (srsran_gnb_ul_get_pusch(&gnb_ul, &ul_slot_cfg, &pusch.sch, &pusch.sch.grant, &pusch_info.pusch_data) <
SRSRAN_SUCCESS) {
logger.error("Error getting PUSCH");
return false;
}
// Inform stack
if (stack.pusch_info(ul_slot_cfg, pusch_info) < SRSRAN_SUCCESS) {
logger.error("Error pushing PUSCH information to stack");
return false;
}
// Log PUSCH decoding
if (logger.info.enabled()) {
std::array<char, 512> str;
srsran_gnb_ul_pusch_info(&gnb_ul, &pusch.sch, &pusch_info.pusch_data, str.data(), (uint32_t)str.size());
logger.info("PUSCH: %s", str.data());
}
} }
return true; return true;

@ -88,21 +88,24 @@ private:
std::mutex mutex; std::mutex mutex;
srsran_sch_cfg_nr_t pusch = {}; srsran_sch_cfg_nr_t pusch = {};
bool valid = false; bool valid = false;
uint32_t pid = 0;
public: public:
pending_pusch_t() = default; pending_pusch_t() = default;
void push(const srsran_sch_cfg_nr_t& pusch_) void push(const uint32_t& pid_, const srsran_sch_cfg_nr_t& pusch_)
{ {
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
pusch = pusch_; pusch = pusch_;
pid = pid_;
valid = true; valid = true;
} }
bool pop(srsran_sch_cfg_nr_t& pusch_) bool pop(uint32_t& pid_, srsran_sch_cfg_nr_t& pusch_)
{ {
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
bool ret = valid; bool ret = valid;
pusch_ = pusch; pusch_ = pusch;
pid_ = pid;
valid = false; valid = false;
return ret; return ret;
} }
@ -113,16 +116,12 @@ private:
srsran::circular_array<dummy_rx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> rx_harq_proc; srsran::circular_array<dummy_rx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> rx_harq_proc;
private:
bool schedule_pdsch(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched) bool schedule_pdsch(const srsran_slot_cfg_t& slot_cfg, dl_sched_t& dl_sched)
{ {
// Instantiate PDCCH and PDSCH // Instantiate PDCCH and PDSCH
pdcch_dl_t pdcch = {}; pdcch_dl_t pdcch = {};
pdsch_t pdsch = {}; pdsch_t pdsch = {};
// Select grant and set data
pdsch.data[0] = tx_harq_proc[slot_cfg.idx].data.data();
// Second TB is not used // Second TB is not used
pdsch.data[1] = nullptr; pdsch.data[1] = nullptr;
@ -161,14 +160,15 @@ private:
return false; return false;
} }
// Set TBS
// Select grant and set data
pdsch.data[0] = tx_harq_proc[slot_cfg.idx].get_tb(pdsch.sch.grant.tb[0].tbs).data();
// Generate random data // Generate random data
srsran_random_byte_vector(random_gen, pdsch.data[0], pdsch.sch.grant.tb[0].tbs / 8); srsran_random_byte_vector(random_gen, pdsch.data[0], pdsch.sch.grant.tb[0].tbs / 8);
// Set TBS
tx_harq_proc[slot_cfg.idx].tbs = pdsch.sch.grant.tb[0].tbs;
// Set softbuffer // Set softbuffer
pdsch.sch.grant.tb[0].softbuffer.tx = &tx_harq_proc[slot_cfg.idx].softbuffer; pdsch.sch.grant.tb[0].softbuffer.tx = &tx_harq_proc[slot_cfg.idx].get_softbuffer(dci.ndi);
// Reset Tx softbuffer always // Reset Tx softbuffer always
srsran_softbuffer_tx_reset(pdsch.sch.grant.tb[0].softbuffer.tx); srsran_softbuffer_tx_reset(pdsch.sch.grant.tb[0].softbuffer.tx);
@ -222,20 +222,33 @@ private:
return false; return false;
} }
// Set TBS
rx_harq_proc[slot_cfg.idx].tbs = pusch_cfg.grant.tb[0].tbs;
// Set softbuffer // Set softbuffer
pusch_cfg.grant.tb[0].softbuffer.rx = &rx_harq_proc[slot_cfg.idx].softbuffer; pusch_cfg.grant.tb[0].softbuffer.rx = &rx_harq_proc[slot_cfg.idx].get_softbuffer(dci.ndi);
// Reset Tx softbuffer always
srsran_softbuffer_rx_reset(pusch_cfg.grant.tb[0].softbuffer.rx);
// Push scheduling results // Push scheduling results
dl_sched.pdcch_ul.push_back(pdcch); dl_sched.pdcch_ul.push_back(pdcch);
// Set pending PUSCH // Set pending PUSCH
pending_pusch[TTI_TX(slot_cfg.idx) % pending_pusch.size()].push(pusch_cfg); pending_pusch[TTI_TX(slot_cfg.idx) % pending_pusch.size()].push(dci.pid, pusch_cfg);
return true;
}
bool handle_uci_data(const srsran_uci_cfg_nr_t& cfg, const srsran_uci_value_nr_t& value)
{
std::unique_lock<std::mutex> lock(mac_metrics_mutex);
for (uint32_t i = 0; i < cfg.ack.count; i++) {
const srsran_harq_ack_bit_t* ack_bit = &cfg.ack.bits[i];
bool is_ok = (value.ack[i] == 1) and value.valid;
uint32_t tb_count = (ack_bit->tb0 ? 1 : 0) + (ack_bit->tb1 ? 1 : 0);
mac_metrics.tx_brate += tx_harq_proc[ack_bit->pid].get_tbs();
mac_metrics.tx_pkts += tb_count;
if (not is_ok) {
mac_metrics.tx_errors += tb_count;
logger.debug("NACK received!");
}
}
return true; return true;
} }
@ -248,7 +261,7 @@ public:
uint32_t ss_id = 1; ///< Search Space identifier uint32_t ss_id = 1; ///< Search Space identifier
uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level uint32_t pdcch_aggregation_level = 0; ///< PDCCH aggregation level
uint32_t pdcch_dl_candidate_index = 0; ///< PDCCH DL DCI candidate index uint32_t pdcch_dl_candidate_index = 0; ///< PDCCH DL DCI candidate index
uint32_t pdcch_ul_candidate_index = 0; ///< PDCCH UL DCI candidate index uint32_t pdcch_ul_candidate_index = 1; ///< PDCCH UL DCI candidate index
uint32_t dl_start_rb = 0; ///< Start resource block uint32_t dl_start_rb = 0; ///< Start resource block
uint32_t dl_length_rb = 0; ///< Number of resource blocks uint32_t dl_length_rb = 0; ///< Number of resource blocks
uint32_t ul_start_rb = 0; ///< Start resource block uint32_t ul_start_rb = 0; ///< Start resource block
@ -258,11 +271,7 @@ public:
}; };
gnb_dummy_stack(args_t args) : gnb_dummy_stack(args_t args) :
mcs(args.mcs), mcs(args.mcs), rnti(args.rnti), dl_time_res(args.dl_time_res), phy_cfg(args.phy_cfg), ss_id(args.ss_id)
rnti(args.rnti),
dl_time_res(args.dl_time_res),
phy_cfg(args.phy_cfg),
ss_id(args.ss_id)
{ {
random_gen = srsran_random_init(0x1234); random_gen = srsran_random_init(0x1234);
logger.set_level(srslog::str_to_basic_level(args.log_level)); logger.set_level(srslog::str_to_basic_level(args.log_level));
@ -364,7 +373,7 @@ public:
} }
} }
mac_interface_phy_nr::pusch_t pusch = {}; mac_interface_phy_nr::pusch_t pusch = {};
bool has_pusch = pending_pusch[slot_cfg.idx % pending_pusch.size()].pop(pusch.sch); bool has_pusch = pending_pusch[slot_cfg.idx % pending_pusch.size()].pop(pusch.pid, pusch.sch);
srsran_uci_cfg_nr_t uci_cfg = {}; srsran_uci_cfg_nr_t uci_cfg = {};
if (not phy_cfg.get_uci_cfg(slot_cfg, ack, uci_cfg)) { if (not phy_cfg.get_uci_cfg(slot_cfg, ack, uci_cfg)) {
@ -372,7 +381,14 @@ public:
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
// Schedule PUSCH
if (has_pusch) { if (has_pusch) {
// Generate data
pusch.data[0] = rx_harq_proc[pusch.pid].get_tb(pusch.sch.grant.tb[0].tbs).data();
pusch.data[1] = nullptr;
srsran_random_byte_vector(random_gen, pusch.data[0], pusch.sch.grant.tb[0].tbs / 8);
// Put UCI configuration in PUSCH config
if (not phy_cfg.get_pusch_uci_cfg(slot_cfg, uci_cfg, pusch.sch)) { if (not phy_cfg.get_pusch_uci_cfg(slot_cfg, uci_cfg, pusch.sch)) {
logger.error("Error setting UCI configuration in PUSCH"); logger.error("Error setting UCI configuration in PUSCH");
return SRSRAN_ERROR; return SRSRAN_ERROR;
@ -380,7 +396,10 @@ public:
ul_sched.pusch.push_back(pusch); ul_sched.pusch.push_back(pusch);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} else if (has_ack) { }
// If any UCI information is triggered, schedule PUCCH
if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) {
mac_interface_phy_nr::pucch_t pucch = {}; mac_interface_phy_nr::pucch_t pucch = {};
pucch.uci_cfg = uci_cfg; pucch.uci_cfg = uci_cfg;
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.resource)) { if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.resource)) {
@ -389,35 +408,44 @@ public:
} }
ul_sched.pucch.push_back(pucch); ul_sched.pucch.push_back(pucch);
return SRSRAN_SUCCESS;
} }
return 0; // Otherwise no UL scheduling
return SRSRAN_SUCCESS;
} }
int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override int pucch_info(const srsran_slot_cfg_t& slot_cfg, const pucch_info_t& pucch_info) override
{ {
std::unique_lock<std::mutex> lock(mac_metrics_mutex); // Handle UCI data
if (not handle_uci_data(pucch_info.uci_data.cfg, pucch_info.uci_data.value)) {
for (uint32_t i = 0; i < pucch_info.uci_data.cfg.ack.count; i++) { logger.error("Error handling UCI data from PUCCH reception");
const srsran_harq_ack_bit_t* ack_bit = &pucch_info.uci_data.cfg.ack.bits[i]; return SRSRAN_ERROR;
bool is_ok = (pucch_info.uci_data.value.ack[i] == 1) and pucch_info.uci_data.value.valid;
uint32_t tb_count = (ack_bit->tb0 ? 1 : 0) + (ack_bit->tb1 ? 1 : 0);
mac_metrics.tx_brate += tx_harq_proc[ack_bit->pid].tbs;
mac_metrics.tx_pkts += tb_count;
if (not is_ok) {
mac_metrics.tx_errors += tb_count;
logger.debug("NACK received!");
}
} }
// Handle PHY metrics
// ...
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override int pusch_info(const srsran_slot_cfg_t& slot_cfg, const pusch_info_t& pusch_info) override
{ {
// ... Not implemented // Handle UCI data
if (not handle_uci_data(pusch_info.uci_cfg, pusch_info.pusch_data.uci)) {
logger.error("Error handling UCI data from PUCCH reception");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
if (not pusch_info.pusch_data.tb[0].crc) {
mac_metrics.rx_errors++;
}
mac_metrics.rx_brate += rx_harq_proc[pusch_info.pid].get_tbs();
mac_metrics.rx_pkts++;
return SRSRAN_SUCCESS;
}
srsenb::mac_ue_metrics_t get_metrics() srsenb::mac_ue_metrics_t get_metrics()
{ {
std::unique_lock<std::mutex> lock(mac_metrics_mutex); std::unique_lock<std::mutex> lock(mac_metrics_mutex);

@ -20,12 +20,16 @@
#include <srsran/common/phy_cfg_nr.h> #include <srsran/common/phy_cfg_nr.h>
#include <srsran/common/standard_streams.h> #include <srsran/common/standard_streams.h>
struct dummy_rx_harq_proc { class dummy_rx_harq_proc
static const uint32_t MAX_TB_SZ = SRSRAN_LDPC_MAX_LEN_CB * SRSRAN_SCH_NR_MAX_NOF_CB_LDPC; {
private:
srsran::byte_buffer_t data; srsran::byte_buffer_t data;
srsran_softbuffer_rx_t softbuffer = {}; srsran_softbuffer_rx_t softbuffer = {};
std::atomic<uint32_t> tbs = {0}; uint32_t tbs = {0};
bool first = true;
uint32_t ndi = 0;
public:
dummy_rx_harq_proc() : data(0) dummy_rx_harq_proc() : data(0)
{ {
// Initialise softbuffer // Initialise softbuffer
@ -36,6 +40,25 @@ struct dummy_rx_harq_proc {
} }
~dummy_rx_harq_proc() { srsran_softbuffer_rx_free(&softbuffer); } ~dummy_rx_harq_proc() { srsran_softbuffer_rx_free(&softbuffer); }
srsran::byte_buffer_t& get_tb(uint32_t tbs_)
{
tbs = tbs_;
return data;
}
srsran_softbuffer_rx_t& get_softbuffer(uint32_t ndi_)
{
if (ndi != ndi_ || first) {
srsran_softbuffer_rx_reset(&softbuffer);
ndi = ndi_;
first = false;
}
return softbuffer;
}
uint32_t get_tbs() const { return tbs; }
}; };
#endif // SRSRAN_DUMMY_RX_HARQ_PROC_H #endif // SRSRAN_DUMMY_RX_HARQ_PROC_H

@ -20,12 +20,16 @@
#include <srsran/common/phy_cfg_nr.h> #include <srsran/common/phy_cfg_nr.h>
#include <srsran/common/standard_streams.h> #include <srsran/common/standard_streams.h>
struct dummy_tx_harq_proc { class dummy_tx_harq_proc
static const uint32_t MAX_TB_SZ = SRSRAN_LDPC_MAX_LEN_CB * SRSRAN_SCH_NR_MAX_NOF_CB_LDPC; {
private:
srsran::byte_buffer_t data; srsran::byte_buffer_t data;
srsran_softbuffer_tx_t softbuffer = {}; srsran_softbuffer_tx_t softbuffer = {};
std::atomic<uint32_t> tbs = {0}; std::atomic<uint32_t> tbs = {0};
bool first = true;
uint32_t ndi = 0;
public:
dummy_tx_harq_proc() dummy_tx_harq_proc()
{ {
// Initialise softbuffer // Initialise softbuffer
@ -36,6 +40,25 @@ struct dummy_tx_harq_proc {
} }
~dummy_tx_harq_proc() { srsran_softbuffer_tx_free(&softbuffer); } ~dummy_tx_harq_proc() { srsran_softbuffer_tx_free(&softbuffer); }
srsran::byte_buffer_t& get_tb(uint32_t tbs_)
{
tbs = tbs_;
return data;
}
srsran_softbuffer_tx_t& get_softbuffer(uint32_t ndi_)
{
if (ndi_ != ndi || first) {
srsran_softbuffer_tx_reset(&softbuffer);
ndi = ndi_;
first = false;
}
return softbuffer;
}
uint32_t get_tbs() const { return tbs; }
}; };
#endif // SRSRAN_TX_DUMMY_HARQ_PROC_H #endif // SRSRAN_TX_DUMMY_HARQ_PROC_H

@ -0,0 +1,61 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2021 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSRAN_DUMMY_UE_STACK_H
#define SRSRAN_DUMMY_UE_STACK_H
#include <srsran/interfaces/ue_nr_interfaces.h>
class ue_dummy_stack : public srsue::stack_interface_phy_nr
{
private:
srsran_random_t random_gen = srsran_random_init(0x4567);
uint16_t rnti = 0;
bool valid = false;
srsran::circular_array<dummy_tx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> tx_harq_proc;
srsran::circular_array<dummy_rx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> rx_harq_proc;
public:
struct args_t {
uint16_t rnti = 0x1234;
};
ue_dummy_stack(const args_t& args) : rnti(args.rnti) { valid = true; }
~ue_dummy_stack() { srsran_random_free(random_gen); }
void in_sync() override {}
void out_of_sync() override {}
void run_tti(const uint32_t tti) override {}
int sf_indication(const uint32_t tti) override { return 0; }
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override
{
action->tb.enabled = true;
action->tb.softbuffer = &rx_harq_proc[grant.pid].get_softbuffer(grant.ndi);
}
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {}
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override
{
if (action == nullptr) {
return;
}
action->tb.enabled = true;
action->tb.payload = &tx_harq_proc[grant.pid].get_tb(grant.tbs);
action->tb.softbuffer = &tx_harq_proc[grant.pid].get_softbuffer(grant.ndi);
srsran_random_byte_vector(random_gen, action->tb.payload->msg, grant.tbs / 8);
}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {}
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; }
bool is_valid() const { return valid; }
};
#endif // SRSRAN_DUMMY_UE_STACK_H

@ -11,6 +11,7 @@
*/ */
#include "dummy_gnb_stack.h" #include "dummy_gnb_stack.h"
#include "dummy_ue_stack.h"
#include "srsran/common/phy_cfg_nr_default.h" #include "srsran/common/phy_cfg_nr_default.h"
#include "srsran/common/test_common.h" #include "srsran/common/test_common.h"
#include "test_bench.h" #include "test_bench.h"
@ -31,45 +32,6 @@ test_bench::args_t::args_t(int argc, char** argv)
cell_list[0].pdcch = phy_cfg.pdcch; cell_list[0].pdcch = phy_cfg.pdcch;
} }
class ue_dummy_stack : public srsue::stack_interface_phy_nr
{
private:
uint16_t rnti = 0;
bool valid = false;
srsran::circular_array<dummy_tx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> tx_harq_proc;
srsran::circular_array<dummy_rx_harq_proc, SRSRAN_MAX_HARQ_PROC_DL_NR> rx_harq_proc;
public:
struct args_t {
uint16_t rnti = 0x1234;
};
ue_dummy_stack(const args_t& args) : rnti(args.rnti) { valid = true; }
void in_sync() override {}
void out_of_sync() override {}
void run_tti(const uint32_t tti) override {}
int sf_indication(const uint32_t tti) override { return 0; }
sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) override { return {rnti, srsran_rnti_type_c}; }
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) override
{
action->tb.enabled = true;
action->tb.softbuffer = &rx_harq_proc[grant.pid].softbuffer;
}
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) override {}
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) override
{
if (action == nullptr) {
return;
}
action->tb.enabled = true;
action->tb.payload = &rx_harq_proc[grant.pid].data;
}
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) override {}
bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) override { return false; }
bool is_valid() const { return valid; }
};
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
srslog::init(); srslog::init();
@ -81,7 +43,7 @@ int main(int argc, char** argv)
args.gnb_args.nof_phy_threads = 1; args.gnb_args.nof_phy_threads = 1;
args.ue_args.log.id_preamble = " UE/"; args.ue_args.log.id_preamble = " UE/";
args.ue_args.log.phy_level = "info"; args.ue_args.log.phy_level = "info";
args.ue_args.log.phy_hex_limit = 0; args.ue_args.log.phy_hex_limit = 1;
args.ue_args.nof_phy_threads = 1; args.ue_args.nof_phy_threads = 1;
// Parse arguments // Parse arguments
@ -134,18 +96,37 @@ int main(int argc, char** argv)
if (mac_metrics.tx_pkts != 0) { if (mac_metrics.tx_pkts != 0) {
pdsch_bler = (float)mac_metrics.tx_errors / (float)mac_metrics.tx_pkts; pdsch_bler = (float)mac_metrics.tx_errors / (float)mac_metrics.tx_pkts;
} }
float pdsch_rate = 0.0f; float pusch_bler = 0.0f;
if (mac_metrics.rx_pkts != 0) {
pusch_bler = (float)mac_metrics.rx_errors / (float)mac_metrics.rx_pkts;
}
float pdsch_shed_rate = 0.0f;
if (mac_metrics.tx_pkts != 0) { if (mac_metrics.tx_pkts != 0) {
pdsch_rate = (float)mac_metrics.tx_brate / (float)mac_metrics.tx_pkts / 1000.0f; pdsch_shed_rate = (float)mac_metrics.tx_brate / (float)mac_metrics.tx_pkts / 1000.0f;
}
float pusch_shed_rate = 0.0f;
if (mac_metrics.rx_pkts != 0) {
pusch_shed_rate = (float)mac_metrics.rx_brate / (float)mac_metrics.rx_pkts / 1000.0f;
} }
srsran::console("PDSCH:\n"); srsran::console("PDSCH:\n");
srsran::console(" Count: %d\n", mac_metrics.tx_pkts); srsran::console(" Count: %d\n", mac_metrics.tx_pkts);
srsran::console(" BLER: %f\n", pdsch_bler); srsran::console(" BLER: %f\n", pdsch_bler);
srsran::console(" Rate: %f Mbps\n", pdsch_rate); srsran::console(" Sched Rate: %f Mbps\n", pdsch_shed_rate);
srsran::console(" Net Rate: %f Mbps\n", (1.0f - pdsch_bler) * pdsch_shed_rate);
srsran::console(" Retx Rate: %f Mbps\n", pdsch_bler * pdsch_shed_rate);
srsran::console("\n");
srsran::console("PUSCH:\n");
srsran::console(" Count: %d\n", mac_metrics.rx_pkts);
srsran::console(" BLER: %f\n", pusch_bler);
srsran::console(" Sched Rate: %f Mbps\n", pusch_shed_rate);
srsran::console(" Net Rate: %f Mbps\n", (1.0f - pusch_bler) * pusch_shed_rate);
srsran::console(" Retx Rate: %f Mbps\n", pusch_bler * pusch_shed_rate);
// Assert metrics // Assert metrics
TESTASSERT(mac_metrics.tx_errors == 0); TESTASSERT(mac_metrics.tx_errors == 0);
TESTASSERT(mac_metrics.rx_errors == 0);
// If reached here, the test is successful // If reached here, the test is successful
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;

Loading…
Cancel
Save