mirror of https://github.com/pvnis/srsRAN_4G.git
Added MAC NR RA procedure with a minimal test case
parent
3d3c80262c
commit
24123313bf
@ -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
|
@ -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
|
@ -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