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 { struct rach_cfg_t {
bool enabled; bool enabled;
uint32_t nof_preambles; uint32_t nof_preambles;

@ -33,13 +33,31 @@ public:
class mac_interface_phy_nr class mac_interface_phy_nr
{ {
public: 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 { typedef struct {
srsran::unique_byte_buffer_t tb[SRSRAN_MAX_TB];
uint32_t pid;
uint16_t rnti; uint16_t rnti;
uint32_t tti; 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; } 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 // UL grant as conveyed between PHY and MAC
typedef struct { typedef struct {
uint16_t rnti; 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_dl_sched_rnti_nr(const uint32_t tti) = 0;
virtual sched_rnti_t get_ul_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 * @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) { for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
dl_grant.tb[i] = srsran::make_byte_buffer(); srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
if (dl_grant.tb[i] && dl_grant.tb[i]->get_tailroom() >= msg->pdus[i].length) { result.payload = srsran::make_byte_buffer();
memcpy(dl_grant.tb[i]->msg, msg->pdus[i].data, msg->pdus[i].length); if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
dl_grant.tb[i]->N_bytes = 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) { 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 { } else {
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length); 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->rnti_type = dci_dl->ctx.rnti_type;
pdsch_grant->tb[0].rv = dci_dl->rv; pdsch_grant->tb[0].rv = dci_dl->rv;
pdsch_grant->tb[0].mcs = dci_dl->mcs; 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 // 5.1.4 PDSCH resource mapping
if (ra_dl_resource_mapping(carrier, slot, pdsch_hl_cfg, pdsch_cfg) < SRSRAN_SUCCESS) { 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 // Find undelivered PDU info
if (not undelivered_sdus->has_sdu(sn)) { 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 { } else {
// Metrics // Metrics
auto& sdu = (*undelivered_sdus)[sn]; auto& sdu = (*undelivered_sdus)[sn];

@ -51,9 +51,6 @@ private:
srsran_ue_ul_nr_t ue_ul = {}; srsran_ue_ul_nr_t ue_ul = {};
srslog::basic_logger& logger; srslog::basic_logger& logger;
// Temporal attributes
srsran_softbuffer_rx_t softbuffer_rx = {};
// Methods for DL... // Methods for DL...
void decode_pdcch_ul(); void decode_pdcch_ul();
void decode_pdcch_dl(); 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 #ifndef SRSUE_MAC_NR_H
#define SRSUE_MAC_NR_H #define SRSUE_MAC_NR_H
#include "dl_harq_nr.h"
#include "mac_nr_interfaces.h" #include "mac_nr_interfaces.h"
#include "proc_bsr_nr.h" #include "proc_bsr_nr.h"
#include "proc_ra_nr.h" #include "proc_ra_nr.h"
#include "proc_sr_nr.h" #include "proc_sr_nr.h"
#include "srsran/common/block_queue.h"
#include "srsran/common/mac_pcap.h" #include "srsran/common/mac_pcap.h"
#include "srsran/interfaces/mac_interface_types.h" #include "srsran/interfaces/mac_interface_types.h"
#include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_nr_interfaces.h"
#include "srsran/srslog/srslog.h" #include "srsran/srslog/srslog.h"
#include "srsue/hdr/stack/mac_common/mac_common.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/mac_nr/mux_nr.h"
#include "srsue/hdr/stack/ue_stack_base.h" #include "srsue/hdr/stack/ue_stack_base.h"
#include "ul_harq_nr.h" #include "ul_harq_nr.h"
@ -44,7 +45,7 @@ public:
mac_nr(srsran::ext_task_sched_handle task_sched_); mac_nr(srsran::ext_task_sched_handle task_sched_);
~mac_nr(); ~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 stop();
void reset(); void reset();
@ -59,7 +60,8 @@ public:
sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti); sched_rnti_t get_ul_sched_rnti_nr(const uint32_t tti);
int sf_indication(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 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, void prach_sent(const uint32_t tti,
const uint32_t s_id, const uint32_t s_id,
@ -111,7 +113,9 @@ public:
static bool is_in_window(uint32_t tti, int* start, int* len); static bool is_in_window(uint32_t tti, int* start, int* len);
private: 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 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); 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; uint16_t c_rnti = SRSRAN_INVALID_RNTI;
uint64_t contention_id = 0; 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 = {}; 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; srsran::task_multiqueue::queue_handle stack_task_dispatch_queue;
// MAC Uplink-related procedures // MAC Uplink-related procedures
@ -160,10 +158,11 @@ private:
proc_sr_nr proc_sr; proc_sr_nr proc_sr;
proc_bsr_nr proc_bsr; proc_bsr_nr proc_bsr;
mux_nr mux; 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_entity_nr_vector ul_harq = {};
ul_harq_cfg_t ul_harq_cfg;
const uint8_t PCELL_CC_IDX = 0; const uint8_t PCELL_CC_IDX = 0;
}; };

@ -77,6 +77,16 @@ public:
virtual uint16_t get_csrnti() = 0; 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 } // namespace srsue
#endif // SRSUE_MAC_NR_INTERFACES_H #endif // SRSUE_MAC_NR_INTERFACES_H

@ -43,7 +43,7 @@ public:
// PHY interfaces // 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 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 pdcch_to_crnti();
void start_by_rrc(); void start_by_rrc();
@ -104,7 +104,7 @@ private:
void ra_procedure_initialization(); void ra_procedure_initialization();
void ra_resource_selection(); void ra_resource_selection();
void ra_preamble_transmission(); 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();
void ra_contention_resolution(uint64_t rx_contention_id); void ra_contention_resolution(uint64_t rx_contention_id);
void ra_completion(); void ra_completion();

@ -96,7 +96,7 @@ public:
mac.new_grant_ul(cc_idx, grant, action); 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); 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 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); mac.new_mch_dl(phy_grant, action);
} }
@ -124,8 +124,18 @@ public:
// MAC Interface for NR PHY // MAC Interface for NR PHY
int sf_indication(const uint32_t tti) final { return SRSRAN_SUCCESS; } 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, void new_grant_ul(const uint32_t cc_idx,
const mac_nr_grant_ul_t& grant, const mac_nr_grant_ul_t& grant,
mac_interface_phy_nr::tb_action_ul_t* action) final mac_interface_phy_nr::tb_action_ul_t* action) final

@ -80,7 +80,14 @@ public:
run_tti(tti); run_tti(tti);
return SRSRAN_SUCCESS; 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 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); 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"); ERROR("Error initiating UE DL NR");
return; 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() cc_worker::~cc_worker()
{ {
srsran_ue_dl_nr_free(&ue_dl); srsran_ue_dl_nr_free(&ue_dl);
srsran_ue_ul_nr_free(&ue_ul); srsran_ue_ul_nr_free(&ue_ul);
srsran_softbuffer_rx_free(&softbuffer_rx);
for (cf_t* p : rx_buffer) { for (cf_t* p : rx_buffer) {
if (p != nullptr) { if (p != nullptr) {
free(p); free(p);
@ -240,6 +233,23 @@ bool cc_worker::work_dl()
return true; 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 // Get data buffer
srsran::unique_byte_buffer_t data = srsran::make_byte_buffer(); srsran::unique_byte_buffer_t data = srsran::make_byte_buffer();
if (data == nullptr) { if (data == nullptr) {
@ -248,14 +258,10 @@ bool cc_worker::work_dl()
} }
data->N_bytes = pdsch_cfg.grant.tb[0].tbs / 8U; data->N_bytes = pdsch_cfg.grant.tb[0].tbs / 8U;
// Get soft-buffer from MAC
// ...
srsran_softbuffer_rx_reset(&softbuffer_rx);
// Initialise PDSCH Result // Initialise PDSCH Result
srsran_pdsch_res_nr_t pdsch_res = {}; srsran_pdsch_res_nr_t pdsch_res = {};
pdsch_res.tb[0].payload = data->msg; 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 // Decode actual PDSCH transmission
if (srsran_ue_dl_nr_decode_pdsch(&ue_dl, &dl_slot_cfg, &pdsch_cfg, &pdsch_res) < SRSRAN_SUCCESS) { 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 // Notify MAC about PDSCH decoding result
if (pdsch_res.tb[0].crc) { mac_interface_phy_nr::tb_action_dl_result_t mac_dl_result = {};
// Prepare grant mac_dl_result.ack = pdsch_res.tb[0].crc;
mac_interface_phy_nr::mac_nr_grant_dl_t mac_nr_grant = {}; mac_dl_result.payload = mac_dl_result.ack ? std::move(data) : nullptr; // only pass data when successful
mac_nr_grant.tb[0] = std::move(data); phy->stack->tb_decoded(cc_idx, mac_dl_grant, std::move(mac_dl_result));
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) { if (pdsch_cfg.grant.rnti_type == srsran_rnti_type_ra) {
phy->rar_grant_tti = dl_slot_cfg.idx; phy->rar_grant_tti = dl_slot_cfg.idx;
} }
// Send data to MAC if (pdsch_res.tb[0].crc) {
phy->stack->tb_decoded(cc_idx, mac_nr_grant);
// Generate DL metrics // Generate DL metrics
dl_metrics_t dl_m = {}; dl_metrics_t dl_m = {};
dl_m.mcs = pdsch_cfg.grant.tb[0].mcs; dl_m.mcs = pdsch_cfg.grant.tb[0].mcs;

@ -6,7 +6,14 @@
# the distribution. # 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}) add_library(srsue_mac_nr STATIC ${SOURCES})
target_link_libraries(srsue_mac_nr srsue_mac_common srsran_mac) target_link_libraries(srsue_mac_nr srsue_mac_common srsran_mac)

@ -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_sr(logger),
proc_bsr(logger), proc_bsr(logger),
mux(*this, logger), mux(*this, logger),
demux(logger),
pcap(nullptr) pcap(nullptr)
{ {
// Create PCell HARQ entities // 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)); 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; return SRSRAN_ERROR;
} }
if (demux.init(rlc) != SRSRAN_SUCCESS) {
logger.error("Couldn't initialize demux unit.");
return SRSRAN_ERROR;
}
// Configure PCell HARQ entities // Configure PCell HARQ entities
if (ul_harq.at(PCELL_CC_IDX)->init() != SRSRAN_SUCCESS) { if (ul_harq.at(PCELL_CC_IDX)->init() != SRSRAN_SUCCESS) {
logger.error("Couldn't initialize UL HARQ entity."); logger.error("Couldn't initialize UL HARQ entity.");
return SRSRAN_ERROR; 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; started = true;
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
@ -98,6 +113,8 @@ void mac_nr::run_tti(const uint32_t tti)
return; return;
} }
logger.set_context(tti);
// Step all procedures // Step all procedures
logger.debug("Running MAC tti=%d", tti); 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_bsr.step(tti, mac_buffer_states);
proc_sr.step(tti); proc_sr.step(tti);
// process received PDUs
stack_task_dispatch_queue.push([this]() { process_pdus(); });
} }
void mac_nr::update_buffer_states() 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 // 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) { if (pcap) {
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { if (tb.ack && tb.payload != nullptr) {
if (grant.tb[i] != nullptr) {
if (proc_ra.has_rar_rnti() && grant.rnti == proc_ra.get_rar_rnti()) { 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); pcap->write_dl_ra_rnti_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti);
} else if (grant.rnti == SRSRAN_PRNTI) { } 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); pcap->write_dl_pch_nr(tb.payload->msg, tb.payload->N_bytes, grant.rnti, true, grant.tti);
} else { } else {
pcap->write_dl_crnti_nr(grant.tb[i]->msg, grant.tb[i]->N_bytes, grant.rnti, true, grant.tti); 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 * \brief Called from PHY after decoding PDCCH for DL reception
*
* The TB can directly be used
* *
* @param cc_idx * @param cc_idx The CC index
* @param grant structure * @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)
{ {
write_pcap(cc_idx, grant); logger.debug("new_grant_dl(): cc_idx=%d, tti=%d, rnti=%d, pid=%d, tbs=%d, ndi=%d, rv=%d",
// handle PDU 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)
{
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()) { 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 { } else {
// Push DL PDUs to queue for background processing // Assert HARQ entity
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { if (dl_harq.at(cc_idx) == nullptr) {
if (grant.tb[i] != nullptr) { logger.error("HARQ entity %d has not been created", cc_idx);
metrics[cc_idx].rx_pkts++; return;
metrics[cc_idx].rx_brate += grant.tb[i]->N_bytes * 8;
pdu_queue.push(std::move(grant.tb[i]));
}
} }
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) void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant, tb_action_ul_t* action)
@ -435,48 +486,7 @@ void mac_nr::get_metrics(mac_metrics_t m[SRSRAN_MAX_CARRIERS])
*/ */
void mac_nr::process_pdus() void mac_nr::process_pdus()
{ {
while (started and not pdu_queue.empty()) { demux.process_pdus();
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());
}
}
}
} }
uint64_t mac_nr::get_contention_id() 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 // 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) { if (state != WAITING_FOR_RESPONSE_RECEPTION) {
logger.warning( logger.warning(
@ -190,11 +190,10 @@ void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_
// Stop rar timer // Stop rar timer
rar_timeout_timer.stop(); rar_timeout_timer.stop();
for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; ++i) { if (tb.ack && tb.payload != nullptr) {
if (grant.tb[i] != nullptr) {
srsran::mac_rar_pdu_nr pdu; srsran::mac_rar_pdu_nr pdu;
if (!pdu.unpack(grant.tb[i]->msg, grant.tb[i]->N_bytes)) { if (!pdu.unpack(tb.payload->msg, tb.payload->N_bytes)) {
logger.warning("Error unpacking RAR PDU (%d)", i); logger.warning("Error unpacking RAR PDU");
return; return;
} }
logger.info("%s", pdu.to_string()); logger.info("%s", pdu.to_string());
@ -221,7 +220,6 @@ void proc_ra_nr::ra_response_reception(const mac_interface_phy_nr::mac_nr_grant_
} }
} }
} }
}
contention_resolution_timer.set(rach_cfg.ra_ContentionResolutionTimer, [this](uint32_t tid) { timer_expired(tid); }); contention_resolution_timer.set(rach_cfg.ra_ContentionResolutionTimer, [this](uint32_t tid) { timer_expired(tid); });
contention_resolution_timer.run(); contention_resolution_timer.run();
logger.debug("Waiting for Contention Resolution"); logger.debug("Waiting for Contention Resolution");
@ -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 // 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 // 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)); }; auto task_handler = [this](const mac_interface_phy_nr::tb_action_dl_result_t& t) {
task_queue.push(std::bind(task_handler, std::move(grant))); ra_response_reception(std::move(t));
};
task_queue.push(std::bind(task_handler, std::move(result)));
} }
// Called from PHY thread, defer actions therefore. // Called from PHY thread, defer actions therefore.

@ -124,12 +124,13 @@ int proc_ra_normal_test()
mac_interface_phy_nr::mac_nr_grant_dl_t grant; mac_interface_phy_nr::mac_nr_grant_dl_t grant;
grant.rnti = 0x16; grant.rnti = 0x16;
grant.tti = rach_cfg.ra_responseWindow + tti_start + 3; 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}; uint8_t mac_dl_rar_pdu[] = {0x40, 0x06, 0x68, 0x03, 0x21, 0x46, 0x46, 0x02, 0x00, 0x00, 0x00};
grant.tb[0] = srsran::make_byte_buffer(); mac_interface_phy_nr::tb_action_dl_result_t result = {};
TESTASSERT(grant.tb[0] != nullptr); result.payload = srsran::make_byte_buffer();
grant.tb[0].get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu)); TESTASSERT(result.payload != nullptr);
proc_ra_nr.handle_rar_pdu(grant); 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.tic();
task_sched.run_pending_tasks(); task_sched.run_pending_tasks();

@ -34,7 +34,7 @@ ue_stack_lte::ue_stack_lte() :
rrc_logger(srslog::fetch_basic_logger("RRC", false)), rrc_logger(srslog::fetch_basic_logger("RRC", false)),
usim_logger(srslog::fetch_basic_logger("USIM", false)), usim_logger(srslog::fetch_basic_logger("USIM", false)),
nas_logger(srslog::fetch_basic_logger("NAS", 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)), rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", false)),
mac_pcap(), mac_pcap(),
mac_nr_pcap(), mac_nr_pcap(),

Loading…
Cancel
Save