mirror of https://github.com/PentHertz/srsLTE.git
Added MAC NR RA procedure with a minimal test case
This commit is contained in:
parent
3d3c80262c
commit
24123313bf
|
@ -116,6 +116,26 @@ struct rach_cfg_t {
|
|||
}
|
||||
};
|
||||
|
||||
// 38.321 5.1.1 Not complete yet
|
||||
struct rach_nr_cfg_t {
|
||||
uint32_t prach_ConfigurationIndex;
|
||||
int PreambleReceivedTargetPower;
|
||||
uint32_t preambleTransMax;
|
||||
uint32_t powerRampingStep;
|
||||
uint32_t ra_responseWindow;
|
||||
uint32_t ra_ContentionResolutionTimer;
|
||||
|
||||
rach_nr_cfg_t() { reset(); }
|
||||
void reset()
|
||||
{
|
||||
prach_ConfigurationIndex = 0;
|
||||
PreambleReceivedTargetPower = 0;
|
||||
powerRampingStep = 0;
|
||||
preambleTransMax = 0;
|
||||
ra_responseWindow = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct mac_cfg_t {
|
||||
// Default constructor with default values as in 36.331 9.2.2
|
||||
mac_cfg_t() { set_defaults(); }
|
||||
|
|
|
@ -95,11 +95,11 @@ public:
|
|||
// MAC informs PHY about UL grant included in RAR PDU
|
||||
virtual int set_ul_grant(std::array<uint8_t, SRSLTE_RAR_UL_GRANT_NBITS>) = 0;
|
||||
|
||||
// MAC instructs PHY to send a PRACH at the next given occasion
|
||||
virtual void send_prach(uint32_t prach_occasion, uint32_t preamble_index, int preamble_received_target_power) = 0;
|
||||
|
||||
// MAC instructs PHY to transmit MAC TB at the given TTI
|
||||
virtual int tx_request(const tx_request_t& request) = 0;
|
||||
|
||||
/// Instruct PHY to send PRACH in the next occasion.
|
||||
virtual void send_prach(const uint32_t prach_occasion, const int preamble_index, const float preamble_received_target_power, const float ta_base_sec = 0.0f) = 0;
|
||||
};
|
||||
|
||||
class phy_interface_rrc_nr
|
||||
|
|
|
@ -130,7 +130,7 @@ std::string mac_rar_subpdu_nr::to_string()
|
|||
{
|
||||
std::stringstream ss;
|
||||
if (has_rapid()) {
|
||||
ss << "RAPID: " << rapid << ", Temp C-RNTI: " << temp_crnti << ", TA: " << ta << ", UL Grant: ";
|
||||
ss << "RAPID: " << rapid << ", Temp C-RNTI: " << std::hex << temp_crnti << ", TA: " << ta << ", UL Grant: ";
|
||||
} else {
|
||||
ss << "Backoff Indicator: " << backoff_indicator << " ";
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ public:
|
|||
void start_plot();
|
||||
|
||||
// MAC interface
|
||||
int tx_request(const tx_request_t& request);
|
||||
int tx_request(const tx_request_t& request);
|
||||
int set_ul_grant(std::array<uint8_t, SRSLTE_RAR_UL_GRANT_NBITS>) { return SRSLTE_SUCCESS; };
|
||||
void send_prach(uint32_t prach_occasion, uint32_t preamble_index, int preamble_received_target_power){};
|
||||
void send_prach(const uint32_t preamble_idx, const int prach_occasion, const float target_power_dbm, const float ta_base_sec = 0.0f){};
|
||||
|
||||
private:
|
||||
std::unique_ptr<srslte::srslte_basic_vnf> vnf;
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#ifndef SRSUE_MAC_NR_H
|
||||
#define SRSUE_MAC_NR_H
|
||||
|
||||
#include "mac_nr_interfaces.h"
|
||||
#include "proc_ra_nr.h"
|
||||
#include "srslte/common/block_queue.h"
|
||||
#include "srslte/common/mac_pcap.h"
|
||||
#include "srslte/interfaces/mac_interface_types.h"
|
||||
|
@ -30,7 +32,7 @@ struct mac_nr_args_t {
|
|||
uint32_t drb_lcid;
|
||||
};
|
||||
|
||||
class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr
|
||||
class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, public mac_interface_proc_ra_nr
|
||||
{
|
||||
public:
|
||||
mac_nr(srslte::ext_task_sched_handle task_sched_);
|
||||
|
@ -65,12 +67,30 @@ public:
|
|||
void setup_lcid(const srslte::logical_channel_config_t& config);
|
||||
void set_config(const srslte::bsr_cfg_t& bsr_cfg);
|
||||
void set_config(const srslte::sr_cfg_t& sr_cfg);
|
||||
void set_config(const srslte::rach_nr_cfg_t& rach_cfg);
|
||||
void set_contention_id(const uint64_t ue_identity);
|
||||
bool set_crnti(const uint16_t crnti);
|
||||
void start_ra_procedure();
|
||||
|
||||
/// procedure ra nr interface
|
||||
uint64_t get_contention_id();
|
||||
uint16_t get_c_rnti();
|
||||
void set_c_rnti(uint64_t c_rnti_);
|
||||
|
||||
bool msg3_is_transmitted() { return true; }
|
||||
void msg3_flush() {}
|
||||
void msg3_prepare() {}
|
||||
bool msg3_is_empty() { return true; }
|
||||
|
||||
/// stack interface
|
||||
void process_pdus();
|
||||
|
||||
static bool is_in_window(uint32_t tti, int* start, int* len);
|
||||
|
||||
// PHY Interface
|
||||
void prach_sent(const uint32_t tti);
|
||||
void tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti);
|
||||
|
||||
private:
|
||||
void write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); // If PCAPs are enabled for this MAC
|
||||
void handle_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
|
@ -97,7 +117,7 @@ private:
|
|||
|
||||
bool started = false;
|
||||
|
||||
uint16_t crnti = 0xdead;
|
||||
uint16_t c_rnti = SRSLTE_INVALID_RNTI;
|
||||
uint64_t contention_id = 0;
|
||||
|
||||
static constexpr uint32_t MIN_RLC_PDU_LEN =
|
||||
|
@ -117,6 +137,9 @@ private:
|
|||
srslte::unique_byte_buffer_t rlc_buffer = nullptr;
|
||||
|
||||
srslte::task_multiqueue::queue_handle stack_task_dispatch_queue;
|
||||
|
||||
// MAC Uplink-related procedures
|
||||
proc_ra_nr proc_ra;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
*
|
||||
* \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 SRSUE_MAC_NR_INTERFACES_H
|
||||
#define SRSUE_MAC_NR_INTERFACES_H
|
||||
|
||||
#include "srslte/common/interfaces_common.h"
|
||||
|
||||
namespace srsue {
|
||||
/**
|
||||
* @brief Interface from MAC NR parent class to subclass random access procedure
|
||||
*/
|
||||
class mac_interface_proc_ra_nr
|
||||
{
|
||||
public:
|
||||
// Functions for identity handling, e.g., contention id and c-rnti
|
||||
virtual uint64_t get_contention_id() = 0;
|
||||
virtual uint16_t get_c_rnti() = 0;
|
||||
virtual void set_c_rnti(uint64_t c_rnti) = 0;
|
||||
|
||||
// Functions for msg3 manipulation which shall be transparent to the procedure
|
||||
virtual bool msg3_is_transmitted() = 0;
|
||||
virtual void msg3_flush() = 0;
|
||||
virtual void msg3_prepare() = 0;
|
||||
virtual bool msg3_is_empty() = 0;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_MAC_NR_INTERFACES_H
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
*
|
||||
* \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 SRSUE_PROC_RA_NR_H
|
||||
#define SRSUE_PROC_RA_NR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mac_nr_interfaces.h"
|
||||
#include "srslte/common/common.h"
|
||||
#include "srslte/common/task_scheduler.h"
|
||||
#include "srslte/interfaces/ue_nr_interfaces.h"
|
||||
#include "srslte/srslog/srslog.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class proc_ra_nr
|
||||
{
|
||||
public:
|
||||
proc_ra_nr(srslog::basic_logger& logger_);
|
||||
~proc_ra_nr(){};
|
||||
|
||||
void init(phy_interface_mac_nr* phy_h_, mac_interface_proc_ra_nr* mac_, srslte::ext_task_sched_handle* task_sched_);
|
||||
void set_config(const srslte::rach_nr_cfg_t& rach_cfg);
|
||||
bool is_contention_resolution();
|
||||
|
||||
bool is_rar_opportunity(uint32_t tti);
|
||||
uint16_t get_rar_rnti();
|
||||
|
||||
// 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 pdcch_to_crnti();
|
||||
|
||||
void start_by_rrc();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
srslog::basic_logger& logger;
|
||||
phy_interface_mac_nr* phy = nullptr;
|
||||
mac_interface_proc_ra_nr* mac = nullptr;
|
||||
srslte::ext_task_sched_handle* task_sched = nullptr;
|
||||
srslte::task_multiqueue::queue_handle task_queue;
|
||||
|
||||
int ra_window_length = -1, ra_window_start = -1;
|
||||
uint16_t rar_rnti = SRSLTE_INVALID_RNTI;
|
||||
uint16_t temp_rnti = SRSLTE_INVALID_RNTI;
|
||||
|
||||
srslte::rach_nr_cfg_t rach_cfg = {};
|
||||
bool configured = false;
|
||||
|
||||
enum ra_state_t {
|
||||
IDLE = 0,
|
||||
PDCCH_SETUP,
|
||||
WAITING_FOR_PRACH_SENT,
|
||||
WAITING_FOR_RESPONSE_RECEPTION,
|
||||
WAITING_FOR_CONTENTION_RESOLUTION,
|
||||
WAITING_FOR_COMPLETION,
|
||||
MAX_RA_STATES,
|
||||
};
|
||||
|
||||
std::atomic<ra_state_t> state = {IDLE};
|
||||
|
||||
enum initiators_t { MAC, RRC, initiators_t_NULLTYPE };
|
||||
std::atomic<initiators_t> started_by = {initiators_t_NULLTYPE};
|
||||
|
||||
srslte::timer_handler::unique_timer prach_send_timer;
|
||||
srslte::timer_handler::unique_timer rar_timeout_timer;
|
||||
srslte::timer_handler::unique_timer contention_resolution_timer;
|
||||
|
||||
// 38.321 5.1.1 Variables
|
||||
uint32_t preamble_index = 0;
|
||||
uint32_t preamble_transmission_counter = 0;
|
||||
uint32_t preamble_power_ramping_step = 0;
|
||||
int preamble_received_target_power = 0;
|
||||
uint32_t scaling_factor_bi = 0;
|
||||
// uint32_t temporary_c_rnti;
|
||||
uint32_t power_offset_2step_ra = 0;
|
||||
|
||||
// not explicty mentioned
|
||||
uint32_t preambleTransMax = 0;
|
||||
uint32_t prach_occasion = 0;
|
||||
|
||||
uint32_t current_ta = 0;
|
||||
void timer_expired(uint32_t timer_id);
|
||||
// 38.321 Steps 5.1.1 - 5.1.6
|
||||
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_contention_resolution();
|
||||
void ra_contention_resolution(uint64_t rx_contention_id);
|
||||
void ra_completion();
|
||||
void ra_error();
|
||||
};
|
||||
} // namespace srsue
|
||||
#endif
|
|
@ -6,5 +6,6 @@
|
|||
# the distribution.
|
||||
#
|
||||
|
||||
set(SOURCES mac_nr.cc)
|
||||
add_library(srsue_mac_nr STATIC ${SOURCES})
|
||||
set(SOURCES mac_nr.cc proc_ra_nr.cc)
|
||||
add_library(srsue_mac_nr STATIC ${SOURCES})
|
||||
target_link_libraries(srsue_mac_nr srslte_mac)
|
|
@ -12,11 +12,12 @@
|
|||
|
||||
#include "srsue/hdr/stack/mac_nr/mac_nr.h"
|
||||
#include "srslte/mac/mac_rar_pdu_nr.h"
|
||||
#include "srsue/hdr/stack/mac_nr/proc_ra_nr.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
mac_nr::mac_nr(srslte::ext_task_sched_handle task_sched_) :
|
||||
task_sched(task_sched_), logger(srslog::fetch_basic_logger("MAC"))
|
||||
task_sched(task_sched_), logger(srslog::fetch_basic_logger("MAC")), proc_ra(logger)
|
||||
{
|
||||
tx_buffer = srslte::make_byte_buffer();
|
||||
rlc_buffer = srslte::make_byte_buffer();
|
||||
|
@ -72,7 +73,7 @@ void mac_nr::run_tti(const uint32_t tti)
|
|||
|
||||
uint16_t mac_nr::get_ul_sched_rnti(const uint32_t tti)
|
||||
{
|
||||
return crnti;
|
||||
return c_rnti;
|
||||
}
|
||||
|
||||
bool mac_nr::is_si_opportunity()
|
||||
|
@ -118,12 +119,12 @@ uint16_t mac_nr::get_dl_sched_rnti(const uint32_t tti)
|
|||
|
||||
bool mac_nr::has_crnti()
|
||||
{
|
||||
return crnti != SRSLTE_INVALID_RNTI;
|
||||
return c_rnti != SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
|
||||
uint16_t mac_nr::get_crnti()
|
||||
{
|
||||
return crnti;
|
||||
return c_rnti;
|
||||
}
|
||||
|
||||
void mac_nr::bch_decoded_ok(uint32_t tti, srslte::unique_byte_buffer_t payload)
|
||||
|
@ -184,7 +185,7 @@ void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant)
|
|||
// handle PDU
|
||||
if (SRSLTE_RNTI_ISRAR(grant.rnti)) { // TODO: replace with proc_ra->get_rar_rnti()
|
||||
// TODO: pass to RA proc
|
||||
handle_rar_pdu(grant);
|
||||
// handle_rar_pdu(grant);
|
||||
} else {
|
||||
// Push DL PDUs to queue for back-ground processing
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; ++i) {
|
||||
|
@ -198,27 +199,6 @@ void mac_nr::tb_decoded(const uint32_t cc_idx, mac_nr_grant_dl_t& grant)
|
|||
stack_task_dispatch_queue.push([this]() { process_pdus(); });
|
||||
}
|
||||
|
||||
// Temporary helper until RA proc is complete
|
||||
void mac_nr::handle_rar_pdu(mac_nr_grant_dl_t& grant)
|
||||
{
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; ++i) {
|
||||
if (grant.tb[i] != nullptr) {
|
||||
srslte::mac_rar_pdu_nr pdu;
|
||||
if (!pdu.unpack(grant.tb[i]->msg, grant.tb[i]->N_bytes)) {
|
||||
logger.warning("Error unpacking RAR PDU");
|
||||
return;
|
||||
}
|
||||
logger.info(pdu.to_string());
|
||||
|
||||
for (auto& subpdu : pdu.get_subpdus()) {
|
||||
if (subpdu.has_rapid() && subpdu.get_rapid() == 0 /* selected preamble */) {
|
||||
phy->set_ul_grant(subpdu.get_ul_grant());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mac_nr::new_grant_ul(const uint32_t cc_idx, const mac_nr_grant_ul_t& grant)
|
||||
{
|
||||
phy_interface_stack_nr::tx_request_t tx_request = {};
|
||||
|
@ -303,23 +283,32 @@ void mac_nr::set_config(const srslte::sr_cfg_t& sr_cfg)
|
|||
logger.warning("Not Scheduling Request Config yet");
|
||||
}
|
||||
|
||||
void mac_nr::set_config(const srslte::rach_nr_cfg_t& rach_cfg){
|
||||
proc_ra.set_config(rach_cfg);
|
||||
}
|
||||
|
||||
void mac_nr::set_contention_id(uint64_t ue_identity)
|
||||
{
|
||||
contention_id = ue_identity;
|
||||
}
|
||||
|
||||
bool mac_nr::set_crnti(const uint16_t crnti_)
|
||||
bool mac_nr::set_crnti(const uint16_t c_rnti_)
|
||||
{
|
||||
if (is_valid_crnti(crnti_)) {
|
||||
logger.info("Setting C-RNTI to 0x%X", crnti_);
|
||||
crnti = crnti_;
|
||||
if (is_valid_crnti(c_rnti_)) {
|
||||
logger.info("Setting C-RNTI to 0x%X", c_rnti_);
|
||||
c_rnti = c_rnti_;
|
||||
return true;
|
||||
} else {
|
||||
logger.warning("Failed to set C-RNTI, 0x%X is not valid.", crnti_);
|
||||
logger.warning("Failed to set C-RNTI, 0x%X is not valid.", c_rnti_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mac_nr::start_ra_procedure()
|
||||
{
|
||||
proc_ra.start_by_rrc();
|
||||
}
|
||||
|
||||
bool mac_nr::is_valid_crnti(const uint16_t crnti)
|
||||
{
|
||||
// TS 38.321 15.3.0 Table 7.1-1
|
||||
|
@ -361,4 +350,47 @@ void mac_nr::handle_pdu(srslte::unique_byte_buffer_t pdu)
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t mac_nr::get_contention_id()
|
||||
{
|
||||
return 0xdeadbeef; // TODO when rebased on PR
|
||||
}
|
||||
|
||||
uint16_t mac_nr::get_c_rnti()
|
||||
{
|
||||
return c_rnti;
|
||||
}
|
||||
|
||||
void mac_nr::set_c_rnti(uint64_t c_rnti_)
|
||||
{
|
||||
c_rnti = c_rnti_;
|
||||
}
|
||||
|
||||
// TODO same function as for mac_eutra
|
||||
bool mac_nr::is_in_window(uint32_t tti, int* start, int* len)
|
||||
{
|
||||
uint32_t st = (uint32_t)*start;
|
||||
uint32_t l = (uint32_t)*len;
|
||||
|
||||
if (srslte_tti_interval(tti, st) < l + 5) {
|
||||
if (tti > st) {
|
||||
if (tti <= st + l) {
|
||||
return true;
|
||||
} else {
|
||||
*start = 0;
|
||||
*len = 0;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tti <= (st + l) % 10240) {
|
||||
return true;
|
||||
} else {
|
||||
*start = 0;
|
||||
*len = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace srsue
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
/**
|
||||
*
|
||||
* \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/proc_ra_nr.h"
|
||||
#include "srsue/hdr/stack/mac_nr/mac_nr.h"
|
||||
#include "srslte/mac/mac_rar_pdu_nr.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
const char* state_str_nr[] = {"RA: IDLE: ",
|
||||
"RA: PDCCH_SETUP: ",
|
||||
"RA: WAITING_FOR_PRACH_SENT: ",
|
||||
"RA: WAITING_FOR_RESPONSE_RECEPTION: ",
|
||||
"RA: WAITING_FOR_COMPLETION: ",
|
||||
"RA: MAX_RA_STATES: "};
|
||||
|
||||
// Table 7.2-1. Backoff Parameter values
|
||||
uint32_t backoff_table_nr[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 1920, 1920, 1920};
|
||||
|
||||
// Table 7.6-1: DELTA_PREAMBLE values long
|
||||
int delta_preamble_db_table_nr[5] = {0, -3, -6, 0};
|
||||
|
||||
proc_ra_nr::proc_ra_nr(srslog::basic_logger& logger_) : logger(logger_) {}
|
||||
|
||||
void proc_ra_nr::init(phy_interface_mac_nr* phy_,
|
||||
mac_interface_proc_ra_nr* mac_,
|
||||
srslte::ext_task_sched_handle* task_sched_)
|
||||
{
|
||||
phy = phy_;
|
||||
mac = mac_;
|
||||
task_sched = task_sched_;
|
||||
task_queue = task_sched->make_task_queue();
|
||||
prach_send_timer = task_sched->get_unique_timer();
|
||||
rar_timeout_timer = task_sched->get_unique_timer();
|
||||
contention_resolution_timer = task_sched->get_unique_timer();
|
||||
}
|
||||
|
||||
/* Sets a new configuration. The configuration is applied by initialization() function */
|
||||
void proc_ra_nr::set_config(const srslte::rach_nr_cfg_t& rach_cfg_)
|
||||
{
|
||||
if (state != IDLE) {
|
||||
logger.warning("Wrong state for ra reponse reception %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, IDLE));
|
||||
return;
|
||||
}
|
||||
rach_cfg = rach_cfg_;
|
||||
configured = true;
|
||||
logger.info("Set RACH common config (Config Index %d, preambleTransMax %d, Repsonse Window %d)",
|
||||
rach_cfg.prach_ConfigurationIndex,
|
||||
rach_cfg.preambleTransMax,
|
||||
rach_cfg.ra_responseWindow);
|
||||
}
|
||||
|
||||
void proc_ra_nr::start_by_rrc()
|
||||
{
|
||||
if (state != IDLE || configured == false) {
|
||||
logger.warning("Trying to start PRACH by RRC order in invalid state (%s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state));
|
||||
return;
|
||||
}
|
||||
started_by = initiators_t::RRC;
|
||||
logger.info("Starting PRACH by RRC order");
|
||||
ra_procedure_initialization();
|
||||
}
|
||||
|
||||
bool proc_ra_nr::is_rar_opportunity(uint32_t tti)
|
||||
{
|
||||
// TODO replace second "&&"" by rar_timeout_timer.running if timer thread safe and delayed starting (tti+3)
|
||||
if (state == WAITING_FOR_RESPONSE_RECEPTION && ra_window_start > 0 && ra_window_length > 0 &&
|
||||
mac_nr::is_in_window(tti, &ra_window_start, &ra_window_length)) {
|
||||
logger.debug("SCHED: Searching RAR-RNTI=0x%x, tti=%d", rar_rnti, tti);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t proc_ra_nr::get_rar_rnti()
|
||||
{
|
||||
if (rar_rnti == SRSLTE_INVALID_RNTI || state != WAITING_FOR_RESPONSE_RECEPTION) {
|
||||
logger.error("Requested ra rnti is invalid. Anyway we return an invalid ra rnti\n");
|
||||
return SRSLTE_INVALID_RNTI;
|
||||
}
|
||||
return rar_rnti;
|
||||
}
|
||||
|
||||
void proc_ra_nr::timer_expired(uint32_t timer_id)
|
||||
{
|
||||
if (prach_send_timer.id() == timer_id) {
|
||||
logger.error("PRACH Send timer expired. PRACH was not transmitted within %d ttis by phy. (TODO)",
|
||||
prach_send_timer.duration());
|
||||
ra_error();
|
||||
} else if (rar_timeout_timer.id() == timer_id) {
|
||||
logger.error("RAR Timer expired. RA response not received within the response window Response Error (TODO)");
|
||||
ra_error();
|
||||
} else if (contention_resolution_timer.id() == timer_id) {
|
||||
logger.error("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error (TODO)");
|
||||
ra_error();
|
||||
} else {
|
||||
logger.error("Timer not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// 5.1.2 Random Access Resource selection
|
||||
void proc_ra_nr::ra_procedure_initialization()
|
||||
{
|
||||
mac->msg3_flush();
|
||||
preamble_power_ramping_step = rach_cfg.powerRampingStep;
|
||||
scaling_factor_bi = 1;
|
||||
preambleTransMax = rach_cfg.preambleTransMax;
|
||||
ra_resource_selection();
|
||||
}
|
||||
|
||||
// 5.1.2 Random Access Resource selection (TODO)
|
||||
void proc_ra_nr::ra_resource_selection()
|
||||
{
|
||||
ra_preamble_transmission();
|
||||
}
|
||||
|
||||
// 5.1.3 Random Access Preamble transmission
|
||||
void proc_ra_nr::ra_preamble_transmission()
|
||||
{
|
||||
uint32_t delta_preamble = 0; // TODO calulate the delta preamble based on delta_preamble_db_table_nr
|
||||
preamble_received_target_power = rach_cfg.PreambleReceivedTargetPower + delta_preamble +
|
||||
(preamble_transmission_counter - 1) * rach_cfg.powerRampingStep +
|
||||
power_offset_2step_ra;
|
||||
preamble_index = 0;
|
||||
prach_occasion = 0;
|
||||
// instruct the physical layer to transmit the Random Access Preamble using the selected PRACH occasion, corresponding
|
||||
// RA-RNTI (if available), PREAMBLE_INDEX, and PREAMBLE_RECEIVED_TARGET_POWER.
|
||||
phy->send_prach(prach_occasion, preamble_index, preamble_received_target_power);
|
||||
prach_send_timer.set(100, [this](uint32_t tid) { timer_expired(tid); }); // TODO find a suitable 100?
|
||||
prach_send_timer.run();
|
||||
state = WAITING_FOR_PRACH_SENT;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (state != WAITING_FOR_RESPONSE_RECEPTION) {
|
||||
logger.warning(
|
||||
"Wrong state for ra reponse reception %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, WAITING_FOR_RESPONSE_RECEPTION));
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop rar timer
|
||||
rar_timeout_timer.stop();
|
||||
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; ++i) {
|
||||
if (grant.tb[i] != nullptr) {
|
||||
srslte::mac_rar_pdu_nr pdu;
|
||||
if (!pdu.unpack(grant.tb[i]->msg, grant.tb[i]->N_bytes)) {
|
||||
logger.warning("Error unpacking RAR PDU");
|
||||
return;
|
||||
}
|
||||
logger.info(pdu.to_string());
|
||||
|
||||
for (auto& subpdu : pdu.get_subpdus()) {
|
||||
if (subpdu.has_rapid() && subpdu.get_rapid() == preamble_index) {
|
||||
phy->set_ul_grant(subpdu.get_ul_grant());
|
||||
// reset all parameters that are used before rar
|
||||
rar_rnti = SRSLTE_INVALID_RNTI;
|
||||
mac->msg3_prepare();
|
||||
temp_rnti = subpdu.get_temp_crnti();
|
||||
current_ta = subpdu.get_ta();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
contention_resolution_timer.set(rach_cfg.ra_ContentionResolutionTimer, [this](uint32_t tid) { timer_expired(tid); });
|
||||
contention_resolution_timer.run();
|
||||
logger.debug("Waiting for Contention Resolution");
|
||||
state = WAITING_FOR_CONTENTION_RESOLUTION;
|
||||
}
|
||||
|
||||
// TS 38.321 Section 5.1.5 2 ways to resolve contention resolution
|
||||
// if the C-RNTI MAC CE was included in Msg3: (only this one is implemented)
|
||||
void proc_ra_nr::ra_contention_resolution()
|
||||
{
|
||||
if (state != WAITING_FOR_CONTENTION_RESOLUTION) {
|
||||
logger.warning(
|
||||
"Wrong state for ra contention resolution by phy %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, WAITING_FOR_CONTENTION_RESOLUTION));
|
||||
return;
|
||||
}
|
||||
if (started_by == initiators_t::RRC || started_by == initiators_t::MAC) {
|
||||
logger.info("PDCCH to C-RNTI received with a new UL grant of transmission");
|
||||
contention_resolution_timer.stop();
|
||||
state = WAITING_FOR_COMPLETION;
|
||||
ra_completion();
|
||||
} else {
|
||||
logger.error("Not started by the correct initiator MAC or RRC");
|
||||
}
|
||||
}
|
||||
|
||||
// or else if the CCCH SDU was included in Msg3 and the PDCCH transmission is addressed to its TEMPORARY_C-RNTI:
|
||||
void proc_ra_nr::ra_contention_resolution(uint64_t rx_contention_id)
|
||||
{
|
||||
if (state != WAITING_FOR_CONTENTION_RESOLUTION) {
|
||||
logger.warning(
|
||||
"Wrong state for ra contention resolution by phy %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, WAITING_FOR_CONTENTION_RESOLUTION));
|
||||
return;
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
|
||||
void proc_ra_nr::ra_completion()
|
||||
{
|
||||
if (state != WAITING_FOR_COMPLETION) {
|
||||
logger.warning("Wrong state for ra completion by phy %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, WAITING_FOR_COMPLETION));
|
||||
return;
|
||||
}
|
||||
mac->set_c_rnti(temp_rnti);
|
||||
srslte::console("Random Access Complete. c-rnti=0x%x, ta=%d\n", mac->get_c_rnti(), current_ta);
|
||||
logger.info("Random Access Complete. c-rnti=0x%x, ta=%d", mac->get_c_rnti(), current_ta);
|
||||
temp_rnti = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
void proc_ra_nr::ra_error()
|
||||
{
|
||||
logger.error("NR random access procedure error recovery not implemented yet\n");
|
||||
}
|
||||
|
||||
// Is called by PHY once it has transmitted the prach transmitted, than configure RA-RNTI and wait for RAR reception
|
||||
void proc_ra_nr::prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id)
|
||||
{
|
||||
task_queue.push([this, tti, s_id, t_id, f_id, ul_carrier_id]() {
|
||||
if (state != WAITING_FOR_PRACH_SENT) {
|
||||
logger.warning("Wrong state for prach sent notification by phy %s (expected state %s)",
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, state),
|
||||
srslte::enum_to_text(state_str_nr, (uint32_t)ra_state_t::MAX_RA_STATES, WAITING_FOR_PRACH_SENT));
|
||||
return;
|
||||
}
|
||||
prach_send_timer.stop();
|
||||
rar_rnti = 1 + s_id + 14 * t_id + 14 * 80 * f_id + 14 * 80 * 8 * ul_carrier_id;
|
||||
logger.info(
|
||||
"prach_occasion=%d, preamble_index=%d, ra-rnti=0x%x, ra-tti=%d, s_id=%d, t_id=%d, f_id=%d, ul_carrier_id=%d",
|
||||
prach_occasion,
|
||||
preamble_index,
|
||||
rar_rnti,
|
||||
tti,
|
||||
s_id,
|
||||
t_id,
|
||||
f_id,
|
||||
ul_carrier_id);
|
||||
srslte::console("Random Access Transmission: prach_occasion=%d, preamble_index=%d, ra-rnti=0x%x, tti=%d\n",
|
||||
prach_occasion,
|
||||
preamble_index,
|
||||
rar_rnti,
|
||||
tti);
|
||||
uint32_t rar_window_st = TTI_ADD(tti, 3);
|
||||
// TODO check ra_response window (delayed start)?
|
||||
rar_timeout_timer.set(rach_cfg.ra_responseWindow + 3, [this](uint32_t tid) { timer_expired(tid); });
|
||||
rar_timeout_timer.run();
|
||||
// Wait for RAR reception
|
||||
ra_window_length = rach_cfg.ra_responseWindow;
|
||||
ra_window_start = TTI_ADD(tti, 3);
|
||||
logger.debug("Calculated ra_window_start=%d, ra_window_length=%d", ra_window_start, ra_window_length);
|
||||
state = WAITING_FOR_RESPONSE_RECEPTION;
|
||||
});
|
||||
}
|
||||
|
||||
// Called by PHY thread through MAC parent
|
||||
void proc_ra_nr::handle_rar_pdu(mac_interface_phy_nr::mac_nr_grant_dl_t& grant)
|
||||
{
|
||||
// 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)));
|
||||
}
|
||||
|
||||
// Called from PHY thread, defer actions therefore.
|
||||
void proc_ra_nr::pdcch_to_crnti()
|
||||
{
|
||||
task_queue.push([this]() { ra_contention_resolution(); });
|
||||
}
|
||||
|
||||
bool proc_ra_nr::is_contention_resolution()
|
||||
{
|
||||
return state == WAITING_FOR_CONTENTION_RESOLUTION;
|
||||
}
|
||||
|
||||
void proc_ra_nr::reset()
|
||||
{
|
||||
state = IDLE;
|
||||
started_by = initiators_t::initiators_t_NULLTYPE;
|
||||
prach_send_timer.stop();
|
||||
rar_timeout_timer.stop();
|
||||
contention_resolution_timer.stop();
|
||||
}
|
||||
} // namespace srsue
|
|
@ -9,6 +9,10 @@
|
|||
add_subdirectory(phy)
|
||||
add_subdirectory(upper)
|
||||
|
||||
if (ENABLE_5GNR)
|
||||
add_subdirectory(mac_nr)
|
||||
endif (ENABLE_5GNR)
|
||||
|
||||
if (ENABLE_TTCN3)
|
||||
add_subdirectory(ttcn3)
|
||||
endif (ENABLE_TTCN3)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
add_executable(proc_ra_nr_test proc_ra_nr_test.cc)
|
||||
target_link_libraries(proc_ra_nr_test srsue_mac_nr srslte_common)
|
||||
add_test(proc_ra_nr_test proc_ra_nr_test)
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 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 "srslte/common/common.h"
|
||||
#include "srslte/common/log_filter.h"
|
||||
#include "srslte/common/test_common.h"
|
||||
#include "srsue/hdr/stack/mac_nr/proc_ra_nr.h"
|
||||
|
||||
using namespace srsue;
|
||||
|
||||
class dummy_phy : public phy_interface_mac_nr
|
||||
{
|
||||
public:
|
||||
dummy_phy() {}
|
||||
void send_prach(const uint32_t prach_occasion_, const int preamble_index_, const float preamble_received_target_power_, const float ta_base_sec_ = 0.0f)
|
||||
{
|
||||
prach_occasion = prach_occasion_;
|
||||
preamble_index = preamble_index_;
|
||||
preamble_received_target_power = preamble_received_target_power_;
|
||||
}
|
||||
int tx_request(const tx_request_t& request) {return 0;}
|
||||
int set_ul_grant(std::array<uint8_t, SRSLTE_RAR_UL_GRANT_NBITS>) { return 0; }
|
||||
|
||||
void get_last_send_prach(uint32_t* prach_occasion_, uint32_t* preamble_index_, int* preamble_received_target_power_)
|
||||
{
|
||||
*prach_occasion_ = prach_occasion;
|
||||
*preamble_index_ = preamble_index;
|
||||
*preamble_received_target_power_ = preamble_received_target_power;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t prach_occasion;
|
||||
uint32_t preamble_index;
|
||||
int preamble_received_target_power;
|
||||
};
|
||||
|
||||
class dummy_mac : public mac_interface_proc_ra_nr
|
||||
{
|
||||
public:
|
||||
uint64_t get_contention_id() { return 0xdeadbeaf; }
|
||||
uint16_t get_c_rnti() { return crnti; }
|
||||
void set_c_rnti(uint64_t c_rnti) { crnti = c_rnti; }
|
||||
|
||||
bool msg3_is_transmitted() { return true; }
|
||||
void msg3_flush() {}
|
||||
void msg3_prepare() {}
|
||||
bool msg3_is_empty() { return true; }
|
||||
|
||||
void msga_flush(){};
|
||||
|
||||
private:
|
||||
uint16_t crnti;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
srslog::init();
|
||||
auto& mac_logger = srslog::fetch_basic_logger("MAC");
|
||||
mac_logger.set_level(srslog::basic_levels::debug);
|
||||
mac_logger.set_hex_dump_max_size(-1);
|
||||
|
||||
dummy_phy dummy_phy;
|
||||
dummy_mac dummy_mac;
|
||||
srslte::task_scheduler task_sched{5, 2};
|
||||
srslte::ext_task_sched_handle ext_task_sched_h(&task_sched);
|
||||
|
||||
proc_ra_nr proc_ra_nr(mac_logger);
|
||||
|
||||
proc_ra_nr.init(&dummy_phy, &dummy_mac, &ext_task_sched_h);
|
||||
TESTASSERT(proc_ra_nr.is_rar_opportunity(1) == false);
|
||||
srslte::rach_nr_cfg_t rach_cfg;
|
||||
rach_cfg.powerRampingStep = 4;
|
||||
rach_cfg.prach_ConfigurationIndex = 16;
|
||||
rach_cfg.PreambleReceivedTargetPower = -110;
|
||||
rach_cfg.preambleTransMax = 7;
|
||||
rach_cfg.ra_ContentionResolutionTimer = 64;
|
||||
rach_cfg.ra_responseWindow = 10;
|
||||
proc_ra_nr.set_config(rach_cfg);
|
||||
proc_ra_nr.start_by_rrc();
|
||||
|
||||
// Test send prach parameters
|
||||
uint32_t prach_occasion = 0;
|
||||
uint32_t preamble_index = 0;
|
||||
int preamble_received_target_power = 0;
|
||||
dummy_phy.get_last_send_prach(&prach_occasion, &preamble_index, &preamble_received_target_power);
|
||||
TESTASSERT(prach_occasion == 0);
|
||||
TESTASSERT(preamble_index == 0);
|
||||
TESTASSERT(preamble_received_target_power == -114);
|
||||
// Simulate PHY and call prach_sent (random values)
|
||||
uint32_t tti_start = 0;
|
||||
proc_ra_nr.prach_sent(tti_start, 6, 0, 4, 1);
|
||||
|
||||
for (uint32_t i = tti_start; i < rach_cfg.ra_responseWindow; i++) {
|
||||
// update clock and run internal tasks
|
||||
task_sched.tic();
|
||||
task_sched.run_pending_tasks();
|
||||
bool rar_opportunity = proc_ra_nr.is_rar_opportunity(i);
|
||||
if (i < 3 + tti_start) {
|
||||
TESTASSERT(rar_opportunity == false);
|
||||
} else if (3 + tti_start > i && i < 3 + rach_cfg.ra_responseWindow) {
|
||||
TESTASSERT(rar_opportunity == true);
|
||||
TESTASSERT(proc_ra_nr.get_rar_rnti() == 0x3487);
|
||||
}
|
||||
}
|
||||
mac_interface_phy_nr::mac_nr_grant_dl_t grant;
|
||||
grant.rnti = 0x3487;
|
||||
grant.tti = rach_cfg.ra_responseWindow + tti_start + 3;
|
||||
grant.pid = 0x0123;
|
||||
uint8_t mac_dl_rar_pdu[] = {0x40, 0x05, 0xa0, 0x00, 0x11, 0x46, 0x46, 0x16, 0x00, 0x00, 0x00};
|
||||
grant.tb[0] = srslte::make_byte_buffer();
|
||||
grant.tb[0].get()->append_bytes(mac_dl_rar_pdu, sizeof(mac_dl_rar_pdu));
|
||||
proc_ra_nr.handle_rar_pdu(grant);
|
||||
|
||||
task_sched.tic();
|
||||
task_sched.run_pending_tasks();
|
||||
|
||||
proc_ra_nr.pdcch_to_crnti();
|
||||
|
||||
task_sched.tic();
|
||||
task_sched.run_pending_tasks();
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue