mac_nr: add DL HARQ

this commit adds a complete DL HARQ entity to the MAC of the UE.
It also refactors demux into an own class and adapts the PHY-MAC
interface to use the new MAC capabilities.
master
Andre Puschmann 4 years ago
parent e3e4564a7e
commit b9ae064338

@ -87,6 +87,13 @@ struct ul_harq_cfg_t {
}
};
/// NR specific config for DL HARQ with configurable number of processes
struct dl_harq_cfg_nr_t {
uint8_t nof_procs; // Number of HARQ processes used in the DL
dl_harq_cfg_nr_t() { reset(); }
void reset() { nof_procs = SRSRAN_DEFAULT_HARQ_PROC_DL_NR; }
};
struct rach_cfg_t {
bool enabled;
uint32_t nof_preambles;
@ -145,7 +152,7 @@ struct sr_cfg_item_nr_t {
#define SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP (8)
struct sr_cfg_nr_t {
bool enabled;
bool enabled;
uint8_t num_items;
sr_cfg_item_nr_t item[SRSRAN_MAX_MAX_NR_OF_SR_CFG_PER_CELL_GROUP];
};

@ -33,13 +33,31 @@ public:
class mac_interface_phy_nr
{
public:
/// For DL, PDU buffer is allocated and passed to MAC in tb_decoded()
typedef struct {
bool enabled; /// Whether or not PHY should attempt to decode PDSCH
srsran_softbuffer_rx_t* softbuffer; /// Pointer to softbuffer to use
} tb_dl_t;
/// Struct provided by MAC with all necessary information for PHY
typedef struct {
tb_dl_t tb; // only single TB in DL
} tb_action_dl_t;
typedef struct {
srsran::unique_byte_buffer_t tb[SRSRAN_MAX_TB];
uint32_t pid;
uint16_t rnti;
uint32_t tti;
uint8_t pid; // HARQ process ID
uint8_t rv; // Redundancy Version
uint8_t ndi; // Raw new data indicator extracted from DCI
uint32_t tbs; // Transport block size in Bytes
} mac_nr_grant_dl_t;
typedef struct {
srsran::unique_byte_buffer_t payload; // TB when decoded successfully, nullptr otherwise
bool ack; // HARQ information
} tb_action_dl_result_t;
// UL grant as conveyed between PHY and MAC
typedef struct {
uint16_t rnti;
@ -74,8 +92,25 @@ public:
virtual sched_rnti_t get_dl_sched_rnti_nr(const uint32_t tti) = 0;
virtual sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti) = 0;
/// Indicate succussfully received TB to MAC. The TB buffer is allocated in the PHY and handed as unique_ptr to MAC
virtual void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) = 0;
/**
* @brief Indicate reception of DL grant to MAC
*
* The TB buffer is allocated in the PHY and handed as unique_ptr to MAC.
*
* @param cc_idx The carrier index on which the grant has been received
* @param grant Reference to the grant
* @param action Pointer to the TB action to be filled by MAC
*/
virtual void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) = 0;
/**
* Indicate decoding of PDSCH
*
* @param cc_idx The index of the carrier for which the PDSCH has been decoded
* @param grant The original DL grant
* @param result Payload (if any) and ack information
*/
virtual void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) = 0;
/**
* @brief Indicate reception of UL grant to MAC

@ -182,12 +182,14 @@ int srsran_basic_vnf::handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg)
}
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
dl_grant.tb[i] = srsran::make_byte_buffer();
if (dl_grant.tb[i] && dl_grant.tb[i]->get_tailroom() >= msg->pdus[i].length) {
memcpy(dl_grant.tb[i]->msg, msg->pdus[i].data, msg->pdus[i].length);
dl_grant.tb[i]->N_bytes = msg->pdus[i].length;
srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
result.payload = srsran::make_byte_buffer();
if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
result.ack = true;
memcpy(result.payload->msg, msg->pdus[i].data, msg->pdus[i].length);
result.payload->N_bytes = msg->pdus[i].length;
if (msg->pdus[i].type == basic_vnf_api::PDSCH) {
m_ue_stack->tb_decoded(cc_idx, dl_grant);
m_ue_stack->tb_decoded(cc_idx, dl_grant, std::move(result));
}
} else {
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length);

@ -677,6 +677,8 @@ int srsran_ra_dl_dci_to_grant_nr(const srsran_carrier_nr_t* carrier,
pdsch_grant->rnti_type = dci_dl->ctx.rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv;
pdsch_grant->tb[0].mcs = dci_dl->mcs;
pdsch_grant->tb[0].ndi = dci_dl->ndi;
pdsch_grant->tb[0].pid = dci_dl->pid;
// 5.1.4 PDSCH resource mapping
if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) {

@ -719,7 +719,7 @@ void pdcp_entity_lte::notify_delivery(const pdcp_sn_vector_t& pdcp_sns)
}
// Find undelivered PDU info
if (not undelivered_sdus->has_sdu(sn)) {
logger.warning("Could not find PDU for delivery notification. Notified SN=%d", sn);
logger.info("Could not find PDU for delivery notification. Notified SN=%d", sn);
} else {
// Metrics
auto& sdu = (*undelivered_sdus)[sn];

@ -51,9 +51,6 @@ private:
srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger;
// Temporal attributes
srsran_softbuffer_rx_t softbuffer_rx = {};
// Methods for DL...
void decode_pdcch_ul();
void decode_pdcch_dl();

@ -0,0 +1,60 @@
/**
*
* \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 SRSLTE_DEMUX_NR_H
#define SRSLTE_DEMUX_NR_H
#include "mac_nr_interfaces.h"
#include "srsran/common/block_queue.h"
#include "srsran/interfaces/ue_rlc_interfaces.h"
namespace srsue {
/**
* @brief Logical Channel Demultiplexing and MAC CE dissassemble according to TS 38.321
*
* Currently only SDU handling for SCH PDU processing is implemented.
* Downlink CE are parsed but not handled.
*
* PDUs can be pushed by multiple HARQ processes in parallel.
* Handling of the PDUs is done from Stack thread which reads the enqueued PDUs
* from the thread-safe queue.
*/
class demux_nr : public demux_interface_harq_nr
{
public:
demux_nr(srslog::basic_logger& logger_);
~demux_nr();
int32_t init(rlc_interface_mac* rlc_);
void process_pdus(); /// Called by MAC to process received PDUs
// HARQ interface
void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti);
private:
// internal helpers
void handle_pdu(srsran::unique_byte_buffer_t pdu);
srslog::basic_logger& logger;
rlc_interface_mac* rlc = nullptr;
///< currently only DCH PDUs supported (add BCH, PCH, etc)
srsran::block_queue<srsran::unique_byte_buffer_t> pdu_queue;
srsran::mac_sch_pdu_nr rx_pdu;
};
} // namespace srsue
#endif // SRSLTE_DEMUX_NR_H

@ -0,0 +1,103 @@
/**
*
* \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 SRSLTE_DL_HARQ_NR_H
#define SRSLTE_DL_HARQ_NR_H
#include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/logger.h"
#include "srsue/hdr/stack/mac_nr/mac_nr_interfaces.h"
#include <mutex>
namespace srsue {
/**
* @brief Downlink HARQ entity as defined in 5.3.2 of 38.321
*
* The class supports a configurable number of HARQ processes (up to 16).
*
* The class is configured (init and reset) by the MAC class from the
* Stack thread context. Main functionality, however, is carried
* out from a PHY worker context.
*
* Concurrent access from threads is protected through rwlocks.
*
*/
class dl_harq_entity_nr
{
using mac_nr_grant_dl_t = mac_interface_phy_nr::mac_nr_grant_dl_t;
public:
dl_harq_entity_nr(uint8_t cc_idx_, mac_interface_harq_nr* mac_, demux_interface_harq_nr* demux_unit_);
~dl_harq_entity_nr();
int32_t set_config(const srsran::dl_harq_cfg_nr_t& cfg_);
void reset();
/// PHY->MAC interface for DL processes
void new_grant_dl(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_t* action);
void tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result);
float get_average_retx();
private:
class dl_harq_process_nr
{
public:
dl_harq_process_nr(dl_harq_entity_nr* parent);
~dl_harq_process_nr();
bool init(int pid);
void reset(void);
uint8_t get_ndi();
void
new_grant_dl(const mac_nr_grant_dl_t& grant, const bool& ndi_toggled, mac_interface_phy_nr::tb_action_dl_t* action);
void tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result);
private:
dl_harq_entity_nr* harq_entity = nullptr;
srslog::basic_logger& logger;
bool is_first_tb = true;
bool is_bcch = false;
uint32_t pid = 0; // HARQ Proccess ID
bool acked = false;
uint32_t n_retx = 0;
mac_nr_grant_dl_t current_grant = {};
std::unique_ptr<srsran_softbuffer_rx_t> softbuffer_rx;
};
// Private members of dl_harq_entity_nr
mac_interface_harq_nr* mac = nullptr;
srsran::dl_harq_cfg_nr_t cfg = {};
std::array<std::unique_ptr<dl_harq_process_nr>, SRSRAN_MAX_HARQ_PROC_DL_NR> harq_procs;
dl_harq_process_nr bcch_proc;
demux_interface_harq_nr* demux_unit = nullptr;
srslog::basic_logger& logger;
uint16_t last_temporal_crnti = SRSRAN_INVALID_RNTI;
float average_retx = 0.0;
uint64_t nof_pkts = 0;
uint8_t cc_idx = 0;
pthread_rwlock_t rwlock;
};
typedef std::unique_ptr<dl_harq_entity_nr> dl_harq_entity_nr_ptr;
typedef std::array<dl_harq_entity_nr_ptr, SRSRAN_MAX_CARRIERS> dl_harq_entity_nr_vector;
} // namespace srsue
#endif // SRSLTE_DL_HARQ_NR_H

@ -13,16 +13,17 @@
#ifndef SRSUE_MAC_NR_H
#define SRSUE_MAC_NR_H
#include "dl_harq_nr.h"
#include "mac_nr_interfaces.h"
#include "proc_bsr_nr.h"
#include "proc_ra_nr.h"
#include "proc_sr_nr.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/mac_pcap.h"
#include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_common/mac_common.h"
#include "srsue/hdr/stack/mac_nr/demux_nr.h"
#include "srsue/hdr/stack/mac_nr/mux_nr.h"
#include "srsue/hdr/stack/ue_stack_base.h"
#include "ul_harq_nr.h"
@ -44,7 +45,7 @@ public:
mac_nr(srsran::ext_task_sched_handle task_sched_);
~mac_nr();
int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy, rlc_interface_mac* rlc, rrc_interface_mac* rrc_);
int init(const mac_nr_args_t& args_, phy_interface_mac_nr* phy_, rlc_interface_mac* rlc_, rrc_interface_mac* rrc_);
void stop();
void reset();
@ -59,7 +60,8 @@ public:
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti);
int sf_indication(const uint32_t tti);
void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant);
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result);
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action);
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action);
void prach_sent(const uint32_t tti,
const uint32_t s_id,
@ -111,7 +113,9 @@ public:
static bool is_in_window(uint32_t tti, int* start, int* len);
private:
void write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); // If PCAPs are enabled for this MAC
void write_pcap(const uint32_t cc_idx,
const mac_nr_grant_dl_t& grant,
tb_action_dl_result_t& tb); // If PCAPs are enabled for this MAC
void handle_pdu(srsran::unique_byte_buffer_t pdu);
void get_ul_data(const mac_nr_grant_ul_t& grant, srsran::byte_buffer_t* tx_pdu);
@ -145,14 +149,8 @@ private:
uint16_t c_rnti = SRSRAN_INVALID_RNTI;
uint64_t contention_id = 0;
srsran::block_queue<srsran::unique_byte_buffer_t>
pdu_queue; ///< currently only DCH PDUs supported (add BCH, PCH, etc)
std::array<mac_metrics_t, SRSRAN_MAX_CARRIERS> metrics = {};
/// Rx buffer
srsran::mac_sch_pdu_nr rx_pdu;
srsran::task_multiqueue::queue_handle stack_task_dispatch_queue;
// MAC Uplink-related procedures
@ -160,10 +158,11 @@ private:
proc_sr_nr proc_sr;
proc_bsr_nr proc_bsr;
mux_nr mux;
demux_nr demux;
// UL HARQ
// DL/UL HARQ
dl_harq_entity_nr_vector dl_harq = {};
ul_harq_entity_nr_vector ul_harq = {};
ul_harq_cfg_t ul_harq_cfg;
const uint8_t PCELL_CC_IDX = 0;
};

@ -77,6 +77,16 @@ public:
virtual uint16_t get_csrnti() = 0;
};
/**
* @brief Interface from HARQ class to demux class
*/
class demux_interface_harq_nr
{
public:
/// Inform demux unit about a newly decoded TB.
virtual void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) = 0;
};
} // namespace srsue
#endif // SRSUE_MAC_NR_INTERFACES_H

@ -43,7 +43,7 @@ public:
// PHY interfaces
void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id);
void handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant);
void handle_rar_pdu(mac_interface_phy_nr::tb_action_dl_result_t& grant);
void pdcch_to_crnti();
void start_by_rrc();
@ -104,7 +104,7 @@ private:
void ra_procedure_initialization();
void ra_resource_selection();
void ra_preamble_transmission();
void ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_dl_t& grant);
void ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb);
void ra_contention_resolution();
void ra_contention_resolution(uint64_t rx_contention_id);
void ra_completion();

@ -96,7 +96,7 @@ public:
mac.new_grant_ul(cc_idx, grant, action);
}
void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action) final
void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action) final
{
mac.new_grant_dl(cc_idx, grant, action);
}
@ -113,7 +113,7 @@ public:
void mch_decoded(uint32_t len, bool crc) final { mac.mch_decoded(len, crc); }
void new_mch_dl(const srsran_pdsch_grant_t& phy_grant, tb_action_dl_t* action) final
void new_mch_dl(const srsran_pdsch_grant_t& phy_grant, mac_interface_phy_lte::tb_action_dl_t* action) final
{
mac.new_mch_dl(phy_grant, action);
}
@ -124,8 +124,18 @@ public:
// MAC Interface for NR PHY
int sf_indication(const uint32_t tti) final { return SRSRAN_SUCCESS; }
void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac_nr.tb_decoded(cc_idx, grant); }
void tb_decoded(const uint32_t cc_idx,
const mac_nr_grant_dl_t& grant,
mac_interface_phy_nr::tb_action_dl_result_t result) final
{
mac_nr.tb_decoded(cc_idx, grant, std::move(result));
}
void new_grant_dl(const uint32_t cc_idx,
const mac_nr_grant_dl_t& grant,
mac_interface_phy_nr::tb_action_dl_t* action) final
{
mac_nr.new_grant_dl(cc_idx, grant, action);
}
void new_grant_ul(const uint32_t cc_idx,
const mac_nr_grant_ul_t& grant,
mac_interface_phy_nr::tb_action_ul_t* action) final

@ -80,7 +80,14 @@ public:
run_tti(tti);
return SRSRAN_SUCCESS;
}
void tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) final { mac->tb_decoded(cc_idx, grant); }
void tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result) final
{
mac->tb_decoded(cc_idx, grant, std::move(result));
}
void new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action) final
{
mac->new_grant_dl(cc_idx, grant, action);
}
void new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action) final
{
mac->new_grant_ul(cc_idx, grant, action);

@ -38,19 +38,12 @@ cc_worker::cc_worker(uint32_t cc_idx_, srslog::basic_logger& log, state* phy_sta
ERROR("Error initiating UE DL NR");
return;
}
if (srsran_softbuffer_rx_init_guru(&softbuffer_rx, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) <
SRSRAN_SUCCESS) {
ERROR("Error init soft-buffer");
return;
}
}
cc_worker::~cc_worker()
{
srsran_ue_dl_nr_free(&ue_dl);
srsran_ue_ul_nr_free(&ue_ul);
srsran_softbuffer_rx_free(&softbuffer_rx);
for (cf_t* p : rx_buffer) {
if (p != nullptr) {
free(p);
@ -240,6 +233,23 @@ bool cc_worker::work_dl()
return true;
}
// Notify MAC about PDSCH grant
mac_interface_phy_nr::tb_action_dl_t dl_action = {};
mac_interface_phy_nr::mac_nr_grant_dl_t mac_dl_grant = {};
mac_dl_grant.rnti = pdsch_cfg.grant.rnti;
mac_dl_grant.pid = pdsch_cfg.grant.tb[0].pid;
mac_dl_grant.rv = pdsch_cfg.grant.tb[0].rv;
mac_dl_grant.ndi = pdsch_cfg.grant.tb[0].ndi;
mac_dl_grant.tbs = pdsch_cfg.grant.tb[0].tbs / 8;
mac_dl_grant.tti = dl_slot_cfg.idx;
phy->stack->new_grant_dl(0, mac_dl_grant, &dl_action);
// Early stop if MAC says it doesn't need the TB
if (not dl_action.tb.enabled) {
logger.info("Decoding not required. Skipping PDSCH");
return true;
}
// Get data buffer
srsran::unique_byte_buffer_t data = srsran::make_byte_buffer();
if (data == nullptr) {
@ -248,14 +258,10 @@ bool cc_worker::work_dl()
}
data->N_bytes = pdsch_cfg.grant.tb[0].tbs / 8U;
// Get soft-buffer from MAC
// ...
srsran_softbuffer_rx_reset(&softbuffer_rx);
// Initialise PDSCH Result
srsran_pdsch_res_nr_t pdsch_res = {};
pdsch_res.tb[0].payload = data->msg;
pdsch_cfg.grant.tb[0].softbuffer.rx = &softbuffer_rx;
pdsch_cfg.grant.tb[0].softbuffer.rx = dl_action.tb.softbuffer;
// Decode actual PDSCH transmission
if (srsran_ue_dl_nr_decode_pdsch(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_res) < SRSRAN_SUCCESS) {
@ -276,21 +282,16 @@ bool cc_worker::work_dl()
}
// Notify MAC about PDSCH decoding result
if (pdsch_res.tb[0].crc) {
// Prepare grant
mac_interface_phy_nr::mac_nr_grant_dl_t mac_nr_grant = {};
mac_nr_grant.tb[0] = std::move(data);
mac_nr_grant.pid = pid;
mac_nr_grant.rnti = pdsch_cfg.grant.rnti;
mac_nr_grant.tti = dl_slot_cfg.idx;
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) {
phy->rar_grant_tti = dl_slot_cfg.idx;
}
mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {};
mac_dl_result.ack = pdsch_res.tb[0].crc;
mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful
phy->stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result));
// Send data to MAC
phy->stack->tb_decoded(cc_idx, mac_nr_grant);
if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) {
phy->rar_grant_tti = dl_slot_cfg.idx;
}
if (pdsch_res.tb[0].crc) {
// Generate DL metrics
dl_metrics_t dl_m = {};
dl_m.mcs = pdsch_cfg.grant.tb[0].mcs;

@ -6,8 +6,15 @@
# the distribution.
#
set(SOURCES mac_nr.cc proc_ra_nr.cc proc_bsr_nr.cc proc_sr_nr.cc mux_nr.cc ul_harq_nr.cc)
set(SOURCES mac_nr.cc
proc_ra_nr.cc
proc_bsr_nr.cc
proc_sr_nr.cc
mux_nr.cc
demux_nr.cc
dl_harq_nr.cc
ul_harq_nr.cc)
add_library(srsue_mac_nr STATIC ${SOURCES})
target_link_libraries(srsue_mac_nr srsue_mac_common srsran_mac)
add_subdirectory(test)
add_subdirectory(test)

@ -0,0 +1,81 @@
/**
*
* \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.
*
*/
#include "srsue/hdr/stack/mac_nr/demux_nr.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/interfaces/ue_rlc_interfaces.h"
namespace srsue {
demux_nr::demux_nr(srslog::basic_logger& logger_) : logger(logger_) {}
demux_nr::~demux_nr() {}
int32_t demux_nr::init(rlc_interface_mac* rlc_)
{
rlc = rlc_;
return SRSRAN_SUCCESS;
}
// Enqueues PDU and returns quickly
void demux_nr::push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti)
{
pdu_queue.push(std::move(pdu));
}
void demux_nr::process_pdus()
{
while (not pdu_queue.empty()) {
srsran::unique_byte_buffer_t pdu = pdu_queue.wait_pop();
handle_pdu(std::move(pdu));
}
}
/// Handling of DLSCH PDUs only
void demux_nr::handle_pdu(srsran::unique_byte_buffer_t pdu)
{
logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes);
rx_pdu.init_rx();
if (rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) {
return;
}
for (uint32_t i = 0; i < rx_pdu.get_num_subpdus(); ++i) {
srsran::mac_sch_subpdu_nr subpdu = rx_pdu.get_subpdu(i);
logger.info("Handling subPDU %d/%d: rnti=0x%x lcid=%d, sdu_len=%d",
i + 1,
rx_pdu.get_num_subpdus(),
subpdu.get_c_rnti(),
subpdu.get_lcid(),
subpdu.get_sdu_length());
// Handle Timing Advance CE
switch (subpdu.get_lcid()) {
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::DRX_CMD:
logger.info("DRX CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::TA_CMD:
logger.info("Timing Advance CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::CON_RES_ID:
logger.info("Contention Resolution CE not implemented.");
break;
default:
if (subpdu.is_sdu()) {
rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length());
}
}
}
}
} // namespace srsue

@ -0,0 +1,243 @@
/**
*
* \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.
*
*/
#include "srsue/hdr/stack/mac_nr/dl_harq_nr.h"
#include "srsran/common/mac_pcap.h"
#include "srsran/common/rwlock_guard.h"
#include "srsran/srslog/logger.h"
#include "srsue/hdr/stack/mac_nr/demux_nr.h"
namespace srsue {
dl_harq_entity_nr::dl_harq_entity_nr(uint8_t cc_idx_,
mac_interface_harq_nr* mac_,
demux_interface_harq_nr* demux_unit_) :
logger(srslog::fetch_basic_logger("MAC-NR")), cc_idx(cc_idx_), mac(mac_), demux_unit(demux_unit_), bcch_proc(this)
{
// Init broadcast HARQ process
bcch_proc.init(-1);
pthread_rwlock_init(&rwlock, NULL);
}
dl_harq_entity_nr::~dl_harq_entity_nr()
{
pthread_rwlock_destroy(&rwlock);
}
// Called from Stack thread through MAC (TODO: add shared::mutex)
int32_t dl_harq_entity_nr::set_config(const srsran::dl_harq_cfg_nr_t& cfg_)
{
srsran::rwlock_write_guard lock(rwlock);
if (cfg_.nof_procs < 1 || cfg_.nof_procs > SRSRAN_MAX_HARQ_PROC_DL_NR) {
logger.error("Invalid configuration: %d HARQ processes not supported", cfg_.nof_procs);
return SRSRAN_ERROR;
}
// clear old processees
for (auto& proc : harq_procs) {
proc = nullptr;
}
// Allocate and init configured HARQ processes
for (uint32_t i = 0; i < cfg.nof_procs; i++) {
harq_procs[i] = std::unique_ptr<dl_harq_process_nr>(new dl_harq_process_nr(this));
if (!harq_procs.at(i)->init(i)) {
logger.error("Error while initializing DL-HARQ process %d", i);
return SRSRAN_ERROR;
}
}
cfg = cfg_;
logger.debug("cc_idx=%d, set number of HARQ processes for DL to %d", cc_idx, cfg.nof_procs);
return SRSRAN_SUCCESS;
}
// Called from PHY workers
void dl_harq_entity_nr::new_grant_dl(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_t* action)
{
srsran::rwlock_read_guard lock(rwlock);
*action = {};
// Fetch HARQ process
dl_harq_process_nr* proc_ptr = nullptr;
if (grant.rnti == SRSRAN_SIRNTI) {
// Set BCCH PID for SI RNTI
proc_ptr = &bcch_proc;
} else {
if (grant.pid >= cfg.nof_procs) {
logger.error("Invalid PID: %d", grant.pid);
return;
}
proc_ptr = harq_procs.at(grant.pid).get();
}
// Check NDI toggled state before forwarding to process
bool ndi_toggled = (grant.ndi != harq_procs.at(grant.pid)->get_ndi());
if (grant.rnti == mac->get_temp_crnti() && last_temporal_crnti != mac->get_temp_crnti()) {
// Consider the NDI to have been toggled
last_temporal_crnti = mac->get_temp_crnti();
logger.info("Considering NDI in pid=%d to be toggled for first Temporal C-RNTI", grant.pid);
ndi_toggled = true;
}
proc_ptr->new_grant_dl(std::move(grant), ndi_toggled, action);
}
/// Called from PHY workers
void dl_harq_entity_nr::tb_decoded(const mac_nr_grant_dl_t& grant, mac_interface_phy_nr::tb_action_dl_result_t result)
{
srsran::rwlock_read_guard lock(rwlock);
if (grant.rnti == SRSRAN_SIRNTI) {
bcch_proc.tb_decoded(grant, std::move(result));
} else {
if (grant.pid >= cfg.nof_procs) {
logger.error("Invalid PID: %d", grant.pid);
return;
}
harq_procs.at(grant.pid)->tb_decoded(grant, std::move(result));
}
}
/// Called from MAC (Stack thread after, e.g. time alignment expire)
void dl_harq_entity_nr::reset()
{
srsran::rwlock_write_guard lock(rwlock);
for (const auto& proc : harq_procs) {
if (proc != nullptr) {
proc->reset();
}
}
bcch_proc.reset();
}
float dl_harq_entity_nr::get_average_retx()
{
return average_retx;
}
dl_harq_entity_nr::dl_harq_process_nr::dl_harq_process_nr(dl_harq_entity_nr* parent_) :
harq_entity(parent_),
softbuffer_rx(std::unique_ptr<srsran_softbuffer_rx_t>(new srsran_softbuffer_rx_t())),
logger(srslog::fetch_basic_logger("MAC-NR"))
{}
dl_harq_entity_nr::dl_harq_process_nr::~dl_harq_process_nr()
{
if (softbuffer_rx != nullptr) {
srsran_softbuffer_rx_free(softbuffer_rx.get());
}
}
bool dl_harq_entity_nr::dl_harq_process_nr::init(int pid_)
{
if (softbuffer_rx == nullptr || srsran_softbuffer_rx_init_guru(softbuffer_rx.get(),
SRSRAN_SCH_NR_MAX_NOF_CB_LDPC,
SRSRAN_LDPC_MAX_LEN_ENCODED_CB) != SRSRAN_SUCCESS) {
logger.error("Couldn't allocate and/or initialize softbuffer");
return false;
}
if (pid_ < 0) {
is_bcch = true;
pid = 0;
} else {
pid = (uint32_t)pid_;
is_bcch = false;
}
return true;
}
void dl_harq_entity_nr::dl_harq_process_nr::reset(void)
{
current_grant = {};
is_first_tb = true;
n_retx = 0;
}
uint8_t dl_harq_entity_nr::dl_harq_process_nr::get_ndi()
{
return current_grant.ndi;
}
void dl_harq_entity_nr::dl_harq_process_nr::new_grant_dl(const mac_nr_grant_dl_t& grant,
const bool& ndi_toggled,
mac_interface_phy_nr::tb_action_dl_t* action)
{
// Determine if it's a new transmission 5.3.2.2
if (ndi_toggled || // 1st condition (NDI has changed)
(is_bcch && grant.rv == 0) || // 2nd condition (Broadcast and 1st transmission)
is_first_tb) // 3rd condition (is first tx for this tb)
{
// New transmission
n_retx = 0;
srsran_softbuffer_rx_reset_tbs(softbuffer_rx.get(), grant.tbs * 8);
action->tb.enabled = true;
action->tb.softbuffer = softbuffer_rx.get();
// reset conditions
is_first_tb = false;
} else {
// This is a retransmission
if (not acked) {
// If data has not yet been successfully decoded, instruct the PHY to combine the received data
action->tb.enabled = true;
action->tb.softbuffer = softbuffer_rx.get();
} else {
logger.info("DL %d: Received duplicate. Discarding and retransmitting ACK (n_retx=%d)", pid, n_retx);
}
}
// increment counter and store grant
n_retx++;
current_grant = grant;
}
void dl_harq_entity_nr::dl_harq_process_nr::tb_decoded(const mac_nr_grant_dl_t& grant,
mac_interface_phy_nr::tb_action_dl_result_t result)
{
acked = result.ack;
if (acked and result.payload != nullptr) {
if (is_bcch) {
logger.warning("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH) not implemented", grant.tbs);
reset();
} else {
if (grant.rnti == harq_entity->mac->get_temp_crnti()) {
logger.debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI) not implemented",
grant.tbs);
} else {
logger.debug("Delivering PDU=%d bytes to Dissassemble and Demux unit", grant.tbs);
harq_entity->demux_unit->push_pdu(std::move(result.payload), grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSRAN_VEC_CMA((float)n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
logger.info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d",
pid,
grant.rv == 0 ? "newTX" : "reTX ",
grant.tbs,
grant.rv,
acked ? "OK" : "KO",
grant.ndi);
}
} // namespace srsue

@ -24,9 +24,11 @@ mac_nr::mac_nr(srsran::ext_task_sched_handle task_sched_) :
proc_sr(logger),
proc_bsr(logger),
mux(*this, logger),
demux(logger),
pcap(nullptr)
{
// Create PCell HARQ entities
dl_harq.at(PCELL_CC_IDX) = dl_harq_entity_nr_ptr(new dl_harq_entity_nr(PCELL_CC_IDX, this, &demux));
ul_harq.at(PCELL_CC_IDX) = ul_harq_entity_nr_ptr(new ul_harq_entity_nr(PCELL_CC_IDX, this, &proc_ra, &mux));
}
@ -62,12 +64,25 @@ int mac_nr::init(const mac_nr_args_t& args_,
return SRSRAN_ERROR;
}
if (demux.init(rlc) != SRSRAN_SUCCESS) {
logger.error("Couldn't initialize demux unit.");
return SRSRAN_ERROR;
}
// Configure PCell HARQ entities
if (ul_harq.at(PCELL_CC_IDX)->init() != SRSRAN_SUCCESS) {
logger.error("Couldn't initialize UL HARQ entity.");
return SRSRAN_ERROR;
}
// Set default config until RRC
dl_harq_cfg_nr_t harq_cfg = {};
harq_cfg.reset();
if (dl_harq.at(PCELL_CC_IDX)->set_config(harq_cfg) != SRSRAN_SUCCESS) {
logger.error("Couldn't configure DL HARQ entity.");
return SRSRAN_ERROR;
}
started = true;
return SRSRAN_SUCCESS;
@ -98,6 +113,8 @@ void mac_nr::run_tti(const uint32_t tti)
return;
}
logger.set_context(tti);
// Step all procedures
logger.debug("Running MAC tti=%d", tti);
@ -106,6 +123,9 @@ void mac_nr::run_tti(const uint32_t tti)
proc_bsr.step(tti, mac_buffer_states);
proc_sr.step(tti);
// process received PDUs
stack_task_dispatch_queue.push([this]() { process_pdus(); });
}
void mac_nr::update_buffer_states()
@ -228,49 +248,80 @@ bool mac_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul
}
// This function handles all PCAP writing for a decoded DL TB
void mac_nr::write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant)
void mac_nr::write_pcap(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t& tb)
{
if (pcap) {
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) {
if (grant.tb[i] != nullptr) {
if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) {
pcap->write_dl_ra_rnti_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti);
} else if (grant.rnti == SRSRAN_PRNTI) {
pcap->write_dl_pch_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti);
} else {
pcap->write_dl_crnti_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti);
}
if (tb.ack && tb.payload != nullptr) {
if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) {
pcap->write_dl_ra_rnti_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti);
} else if (grant.rnti == SRSRAN_PRNTI) {
pcap->write_dl_pch_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti);
} else {
pcap->write_dl_crnti_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti);
}
}
}
}
/**
* \brief Called from PHY after decoding a TB
*
* The TB can directly be used
* \brief Called from PHY after decoding PDCCH for DL reception
*
* @param cc_idx
* @param grant structure
* @param cc_idx The CC index
* @param grant The DL grant
* @param action The DL action to be filled by MAC
*/
void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant)
void mac_nr::new_grant_dl(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_t* action)
{
logger.debug("new_grant_dl(): cc_idx=%d, tti=%d, rnti=%d, pid=%d, tbs=%d, ndi=%d, rv=%d",
cc_idx,
grant.tti,
grant.rnti,
grant.pid,
grant.tbs,
grant.ndi,
grant.rv);
// Assert HARQ entity
if (dl_harq.at(cc_idx) == nullptr) {
logger.error("HARQ entity %d has not been created", cc_idx);
return;
}
dl_harq.at(cc_idx)->new_grant_dl(grant, action);
}
void mac_nr::tb_decoded(const uint32_t cc_idx, const mac_nr_grant_dl_t& grant, tb_action_dl_result_t result)
{
write_pcap(cc_idx, grant);
// handle PDU
logger.debug("tb_decoded(): cc_idx=%d, tti=%d, rnti=%d, pid=%d, tbs=%d, ndi=%d, rv=%d, result=%s",
cc_idx,
grant.tti,
grant.rnti,
grant.pid,
grant.tbs,
grant.ndi,
grant.rv,
result.ack ? "OK" : "KO");
write_pcap(cc_idx, grant, result);
if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) {
proc_ra.handle_rar_pdu(grant);
proc_ra.handle_rar_pdu(result);
} else {
// Push DL PDUs to queue for background processing
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) {
if (grant.tb[i] != nullptr) {
metrics[cc_idx].rx_pkts++;
metrics[cc_idx].rx_brate += grant.tb[i]->N_bytes * 8;
pdu_queue.push(std::move(grant.tb[i]));
}
// Assert HARQ entity
if (dl_harq.at(cc_idx) == nullptr) {
logger.error("HARQ entity %d has not been created", cc_idx);
return;
}
dl_harq.at(cc_idx)->tb_decoded(grant, std::move(result));
}
stack_task_dispatch_queue.push([this]() { process_pdus(); });
// do metrics
metrics[cc_idx].rx_brate += grant.tbs * 8;
metrics[cc_idx].rx_pkts++;
if (not result.ack) {
metrics[cc_idx].rx_errors++;
}
}
void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action)
@ -395,7 +446,7 @@ bool mac_nr::set_crnti(const uint16_t c_rnti_)
void mac_nr::start_ra_procedure()
{
stack_task_dispatch_queue.push([this]() {proc_ra.start_by_rrc();});
stack_task_dispatch_queue.push([this]() { proc_ra.start_by_rrc(); });
}
bool mac_nr::is_valid_crnti(const uint16_t crnti)
@ -435,48 +486,7 @@ void mac_nr::get_metrics(mac_metrics_t m[SRSRAN_MAX_CARRIERS])
*/
void mac_nr::process_pdus()
{
while (started and not pdu_queue.empty()) {
srsran::unique_byte_buffer_t pdu = pdu_queue.wait_pop();
// TODO: delegate to demux class
handle_pdu(std::move(pdu));
}
}
void mac_nr::handle_pdu(srsran::unique_byte_buffer_t pdu)
{
logger.info(pdu->msg, pdu->N_bytes, "Handling MAC PDU (%d B)", pdu->N_bytes);
rx_pdu.init_rx();
if (rx_pdu.unpack(pdu->msg, pdu->N_bytes) != SRSRAN_SUCCESS) {
return;
}
for (uint32_t i = 0; i < rx_pdu.get_num_subpdus(); ++i) {
srsran::mac_sch_subpdu_nr subpdu = rx_pdu.get_subpdu(i);
logger.info("Handling subPDU %d/%d: rnti=0x%x lcid=%d, sdu_len=%d",
i + 1,
rx_pdu.get_num_subpdus(),
subpdu.get_c_rnti(),
subpdu.get_lcid(),
subpdu.get_sdu_length());
// Handle Timing Advance CE
switch (subpdu.get_lcid()) {
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::DRX_CMD:
logger.info("DRX CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::TA_CMD:
logger.info("Timing Advance CE not implemented.");
break;
case srsran::mac_sch_subpdu_nr::nr_lcid_sch_t::CON_RES_ID:
logger.info("Contention Resolution CE not implemented.");
break;
default:
if (subpdu.is_sdu()) {
rlc->write_pdu(subpdu.get_lcid(), subpdu.get_sdu(), subpdu.get_sdu_length());
}
}
}
demux.process_pdus();
}
uint64_t mac_nr::get_contention_id()

@ -178,7 +178,7 @@ void proc_ra_nr::ra_preamble_transmission()
}
// 5.1.4 Random Access Preamble transmission
void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_dl_t& grant)
void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::tb_action_dl_result_t& tb)
{
if (state != WAITING_FOR_RESPONSE_RECEPTION) {
logger.warning(
@ -190,34 +190,32 @@ void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_
// Stop rar timer
rar_timeout_timer.stop();
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) {
if (grant.tb[i] != nullptr) {
srsran::mac_rar_pdu_nr pdu;
if (!pdu.unpack(grant.tb[i]->msg, grant.tb[i]->N_bytes)) {
logger.warning("Error unpacking RAR PDU (%d)", i);
return;
}
logger.info("%s", pdu.to_string());
for (auto& subpdu : pdu.get_subpdus()) {
if (subpdu.has_rapid() && subpdu.get_rapid() == preamble_index) {
logger.debug("PROC RA NR: Setting UL grant and prepare Msg3");
temp_crnti = subpdu.get_temp_crnti();
// Set Temporary-C-RNTI if provided, otherwise C-RNTI is ok
phy->set_ul_grant(subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra);
// reset all parameters that are used before rar
rar_rnti = SRSRAN_INVALID_RNTI;
mac.msg3_prepare();
current_ta = subpdu.get_ta();
// Set Backoff parameter
if (subpdu.has_backoff()) {
preamble_backoff = backoff_table_nr[subpdu.get_backoff() % 16]; // TODO multiplied with SCALING_FACTOR_BI.
} else {
preamble_backoff = 0;
}
if (tb.ack && tb.payload != nullptr) {
srsran::mac_rar_pdu_nr pdu;
if (!pdu.unpack(tb.payload->msg, tb.payload->N_bytes)) {
logger.warning("Error unpacking RAR PDU");
return;
}
logger.info("%s", pdu.to_string());
for (auto& subpdu : pdu.get_subpdus()) {
if (subpdu.has_rapid() && subpdu.get_rapid() == preamble_index) {
logger.debug("PROC RA NR: Setting UL grant and prepare Msg3");
temp_crnti = subpdu.get_temp_crnti();
// Set Temporary-C-RNTI if provided, otherwise C-RNTI is ok
phy->set_ul_grant(subpdu.get_ul_grant(), temp_crnti, srsran_rnti_type_ra);
// reset all parameters that are used before rar
rar_rnti = SRSRAN_INVALID_RNTI;
mac.msg3_prepare();
current_ta = subpdu.get_ta();
// Set Backoff parameter
if (subpdu.has_backoff()) {
preamble_backoff = backoff_table_nr[subpdu.get_backoff() % 16]; // TODO multiplied with SCALING_FACTOR_BI.
} else {
preamble_backoff = 0;
}
}
}
@ -345,11 +343,13 @@ void proc_ra_nr::prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t
}
// Called by PHY thread through MAC parent
void proc_ra_nr::handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant)
void proc_ra_nr::handle_rar_pdu(mac_interface_phy_nr::tb_action_dl_result_t& result)
{
// Defer the handling of the grant to main stack thread in ra_response_reception
auto task_handler = [this](const mac_interface_phy_nr::mac_nr_grant_dl_t& t) { ra_response_reception(std::move(t)); };
task_queue.push(std::bind(task_handler, std::move(grant)));
auto task_handler = [this](const mac_interface_phy_nr::tb_action_dl_result_t& t) {
ra_response_reception(std::move(t));
};
task_queue.push(std::bind(task_handler, std::move(result)));
}
// Called from PHY thread, defer actions therefore.

@ -72,7 +72,7 @@ public:
void rrc_ra_problem() { logger.warning("Dummy MAC RRC ra problem"); }
private:
uint16_t crnti = SRSRAN_INVALID_RNTI;
uint16_t crnti = SRSRAN_INVALID_RNTI;
srslog::basic_logger& logger;
};
@ -124,12 +124,13 @@ int proc_ra_normal_test()
mac_interface_phy_nr::mac_nr_grant_dl_t grant;
grant.rnti = 0x16;
grant.tti = rach_cfg.ra_responseWindow + tti_start + 3;
grant.pid = 0x0123;
grant.pid = 0x0;
uint8_t mac_dl_rar_pdu[] = {0x40, 0x06, 0x68, 0x03, 0x21, 0x46, 0x46, 0x02, 0x00, 0x00, 0x00};
grant.tb[0] = srsran::make_byte_buffer();
TESTASSERT(grant.tb[0] != nullptr);
grant.tb[0].get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu));
proc_ra_nr.handle_rar_pdu(grant);
mac_interface_phy_nr::tb_action_dl_result_t result = {};
result.payload = srsran::make_byte_buffer();
TESTASSERT(result.payload != nullptr);
result.payload.get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu));
proc_ra_nr.handle_rar_pdu(result);
task_sched.tic();
task_sched.run_pending_tasks();

@ -34,7 +34,7 @@ ue_stack_lte::ue_stack_lte() :
rrc_logger(srslog::fetch_basic_logger("RRC", false)),
usim_logger(srslog::fetch_basic_logger("USIM", false)),
nas_logger(srslog::fetch_basic_logger("NAS", false)),
mac_nr_logger(srslog::fetch_basic_logger("MAC-NR", false)),
mac_nr_logger(srslog::fetch_basic_logger("MAC-NR")),
rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", false)),
mac_pcap(),
mac_nr_pcap(),

Loading…
Cancel
Save