Fixed multiple issues in Random Access procedure and extended MAC test

master
Ismael Gomez 6 years ago committed by Andre Puschmann
parent 5dcf3b3563
commit 773c2a9721

@ -996,9 +996,6 @@ int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_
cfg->cc_idx == 0) { // Send PUCCH over PCell only cfg->cc_idx == 0) { // Send PUCCH over PCell only
if (!cfg->ul_cfg.pucch.rnti) { if (!cfg->ul_cfg.pucch.rnti) {
cfg->ul_cfg.pucch.rnti = q->current_rnti; cfg->ul_cfg.pucch.rnti = q->current_rnti;
if (!q->current_rnti) {
printf("PUCCH: Warning PUCCH rnti or current_rnti are not set\n");
}
} }
ret = pucch_encode(q, sf, cfg, &data->uci) ? -1 : 1; ret = pucch_encode(q, sf, cfg, &data->uci) ? -1 : 1;
} else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) { } else if (srs_tx_enabled(&cfg->ul_cfg.srs, sf->tti)) {

@ -62,6 +62,7 @@ private:
dl_harq_process(); dl_harq_process();
bool init(int pid, dl_harq_entity* parent); bool init(int pid, dl_harq_entity* parent);
void reset(void); void reset(void);
void reset_ndi();
void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]);
@ -78,6 +79,7 @@ private:
bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx); bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx);
void reset(bool lock = true); void reset(bool lock = true);
void reset_ndi();
void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool* ack_ptr); void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool* ack_ptr);

@ -62,7 +62,7 @@ public:
void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action); void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action);
void new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action); void new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action);
void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]);
void bch_decoded_ok(uint8_t *payload, uint32_t len); void bch_decoded_ok(uint8_t* payload, uint32_t len);
uint16_t get_dl_sched_rnti(uint32_t tti); uint16_t get_dl_sched_rnti(uint32_t tti);
uint16_t get_ul_sched_rnti(uint32_t tti); uint16_t get_ul_sched_rnti(uint32_t tti);

@ -69,9 +69,9 @@ public:
void msg3_flush(); void msg3_flush();
bool msg3_is_transmitted(); bool msg3_is_transmitted();
void msg3_prepare(); void msg3_prepare();
bool msg3_is_pending(); bool msg3_is_pending();
bool msg3_is_empty();
void append_crnti_ce_next_tx(uint16_t crnti); void append_crnti_ce_next_tx(uint16_t crnti);
@ -103,8 +103,10 @@ private:
/* PDU Buffer */ /* PDU Buffer */
srslte::sch_pdu pdu_msg; srslte::sch_pdu pdu_msg;
bool msg3_has_been_transmitted = false;
bool msg3_pending = false; srslte::byte_buffer_t msg3_buff;
bool msg3_has_been_transmitted = false;
bool msg3_pending = false;
}; };
} // namespace srsue } // namespace srsue

@ -44,24 +44,21 @@ public:
bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t)); bzero(&softbuffer_rar, sizeof(srslte_softbuffer_rx_t));
pcap = NULL; pcap = NULL;
backoff_interval_start = 0; backoff_interval_start = 0;
backoff_inteval = 0; backoff_interval = 0;
received_target_power_dbm = 0; received_target_power_dbm = 0;
ra_rnti = 0; ra_rnti = 0;
current_ta = 0; current_ta = 0;
state = IDLE; state = IDLE;
last_msg3_group = RA_GROUP_A; last_msg3_group = RA_GROUP_A;
msg3_transmitted = false; msg3_transmitted = false;
first_rar_received = false;
phy_h = NULL; phy_h = NULL;
log_h = NULL; log_h = NULL;
mux_unit = NULL; mux_unit = NULL;
rrc = NULL; rrc = NULL;
transmitted_contention_id = 0; transmitted_contention_id = 0;
transmitted_crnti = 0; transmitted_crnti = 0;
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
started_by_pdcch = false; started_by_pdcch = false;
rar_grant_nbytes = 0; rar_grant_nbytes = 0;
msg3_flushed = false;
noncontention_enabled = false; noncontention_enabled = false;
next_preamble_idx = 0; next_preamble_idx = 0;
@ -89,11 +86,11 @@ public:
void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false); void start_mac_order(uint32_t msg_len_bits = 56, bool is_ho = false);
void step(uint32_t tti); void step(uint32_t tti);
bool is_rar_window(int* rar_window_start, int* rar_window_length); bool update_rar_window(int* rar_window_start, int* rar_window_length);
bool is_contention_resolution(); bool is_contention_resolution();
void harq_retx(); void harq_retx();
void harq_max_retx(); void harq_max_retx();
void pdcch_to_crnti(bool contains_uplink_grant); void pdcch_to_crnti(bool is_new_uplink_transmission);
void timer_expired(uint32_t timer_id); void timer_expired(uint32_t timer_id);
void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded_ok(); void tb_decoded_ok();
@ -103,16 +100,18 @@ public:
void start_pcap(srslte::mac_pcap* pcap); void start_pcap(srslte::mac_pcap* pcap);
private: private:
void state_pdcch_setup();
void state_response_reception(uint32_t tti);
void state_backoff_wait(uint32_t tti);
void state_contention_resolution();
void state_completition();
void process_timeadv_cmd(uint32_t ta_cmd); void process_timeadv_cmd(uint32_t ta_cmd);
void step_initialization(); void initialization();
void step_resource_selection(); void resource_selection();
void step_preamble_transmission(); void preamble_transmission();
void step_pdcch_setup(); void response_error();
void step_response_reception(uint32_t tti); void complete();
void step_response_error(uint32_t tti);
void step_backoff_wait(uint32_t tti);
void step_contention_resolution();
void step_completition();
// Buffer to receive RAR PDU // Buffer to receive RAR PDU
static const uint32_t MAX_RAR_PDU_LEN = 2048; static const uint32_t MAX_RAR_PDU_LEN = 2048;
@ -136,34 +135,21 @@ private:
uint32_t backoff_param_ms; uint32_t backoff_param_ms;
uint32_t sel_maskIndex; uint32_t sel_maskIndex;
uint32_t sel_preamble; uint32_t sel_preamble;
uint32_t backoff_interval_start; int backoff_interval_start;
uint32_t backoff_inteval; uint32_t backoff_interval;
int received_target_power_dbm; int received_target_power_dbm;
uint32_t ra_rnti; uint32_t ra_rnti;
uint32_t ra_tti;
uint32_t current_ta; uint32_t current_ta;
srslte_softbuffer_rx_t softbuffer_rar; srslte_softbuffer_rx_t softbuffer_rar;
enum { enum { IDLE = 0, PDCCH_SETUP, RESPONSE_RECEPTION, BACKOFF_WAIT, CONTENTION_RESOLUTION, COMPLETITION } state;
IDLE = 0,
INITIALIZATION, // Section 5.1.1
RESOURCE_SELECTION, // Section 5.1.2
PREAMBLE_TRANSMISSION, // Section 5.1.3
PDCCH_SETUP,
RESPONSE_RECEPTION, // Section 5.1.4
RESPONSE_ERROR,
BACKOFF_WAIT,
CONTENTION_RESOLUTION, // Section 5.1.5
COMPLETION, // Section 5.1.6
COMPLETION_DONE,
RA_PROBLEM // Section 5.1.5 last part
} state;
typedef enum { RA_GROUP_A, RA_GROUP_B } ra_group_t; typedef enum { RA_GROUP_A, RA_GROUP_B } ra_group_t;
ra_group_t last_msg3_group; ra_group_t last_msg3_group;
bool msg3_transmitted; bool msg3_transmitted;
bool first_rar_received;
uint32_t rar_window_st; uint32_t rar_window_st;
@ -185,12 +171,9 @@ private:
std::mutex mutex; std::mutex mutex;
enum { PDCCH_CRNTI_NOT_RECEIVED = 0, PDCCH_CRNTI_UL_GRANT, PDCCH_CRNTI_DL_GRANT } pdcch_to_crnti_received;
bool ra_is_ho; bool ra_is_ho;
bool started_by_pdcch; bool started_by_pdcch;
uint32_t rar_grant_nbytes; uint32_t rar_grant_nbytes;
bool msg3_flushed;
bool rar_received; bool rar_received;
}; };

@ -867,10 +867,12 @@ bool cc_worker::encode_uplink(mac_interface_phy_lte::tb_action_ul_t* action, srs
void cc_worker::set_uci_sr(srslte_uci_data_t* uci_data) void cc_worker::set_uci_sr(srslte_uci_data_t* uci_data)
{ {
Debug("set_uci_sr() query: sr_enabled=%d, last_tx_tti=%d\n", phy->sr_enabled, phy->sr_last_tx_tti);
if (srslte_ue_ul_gen_sr(&ue_ul_cfg, &sf_cfg_ul, uci_data, phy->sr_enabled)) { if (srslte_ue_ul_gen_sr(&ue_ul_cfg, &sf_cfg_ul, uci_data, phy->sr_enabled)) {
if (phy->sr_enabled) { if (phy->sr_enabled) {
phy->sr_last_tx_tti = CURRENT_TTI_TX; phy->sr_last_tx_tti = CURRENT_TTI_TX;
phy->sr_enabled = false; phy->sr_enabled = false;
Debug("set_uci_sr() sending SR: sr_enabled=%d, last_tx_tti=%d\n", phy->sr_enabled, phy->sr_last_tx_tti);
} }
} }
} }

@ -387,6 +387,7 @@ void phy::sr_send()
{ {
common.sr_enabled = true; common.sr_enabled = true;
common.sr_last_tx_tti = -1; common.sr_last_tx_tti = -1;
Debug("sr_send(): sr_enabled=%d, last_tx_tti=%d\n", common.sr_enabled, common.sr_last_tx_tti);
} }
int phy::sr_last_tx_tti() int phy::sr_last_tx_tti()

@ -104,12 +104,13 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
is_uecrid_successful = mac->contention_resolution_id_rcv(pending_mac_msg.get()->get_con_res_id()); is_uecrid_successful = mac->contention_resolution_id_rcv(pending_mac_msg.get()->get_con_res_id());
} }
} }
pending_mac_msg.reset(); pending_mac_msg.reset();
if (is_uecrid_successful) {
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n"); Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH);
pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH); } else {
pdus.deallocate(buff);
}
} else { } else {
Warning("Trying to push PDU with payload size zero\n"); Warning("Trying to push PDU with payload size zero\n");
} }

@ -81,14 +81,11 @@ void dl_harq_entity::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
} }
proc_ptr = &proc[grant.pid]; proc_ptr = &proc[grant.pid];
} }
// Consider the NDI to have been toggled
if (grant.rnti == rntis->temp_rnti && last_temporal_crnti != rntis->temp_rnti) { if (grant.rnti == rntis->temp_rnti && last_temporal_crnti != rntis->temp_rnti) {
grant.tb[0].ndi = true;
last_temporal_crnti = rntis->temp_rnti; last_temporal_crnti = rntis->temp_rnti;
Info("Set NDI=1 for Temp-RNTI DL dci\n"); proc_ptr->reset_ndi();
} Info("Considering NDI in pid=%d to be toggled for first Temporal C-RNTI\n", grant.pid);
if (grant.rnti == rntis->crnti && proc_ptr->is_sps()) {
grant.tb[0].ndi = true;
Info("Set NDI=1 for C-RNTI DL dci\n");
} }
proc_ptr->new_grant_dl(grant, action); proc_ptr->new_grant_dl(grant, action);
} else { } else {
@ -152,6 +149,13 @@ void dl_harq_entity::dl_harq_process::reset(void)
} }
} }
void dl_harq_entity::dl_harq_process::reset_ndi()
{
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
subproc[tb].reset_ndi();
}
}
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy_lte::tb_action_dl_t* action) mac_interface_phy_lte::tb_action_dl_t* action)
{ {
@ -245,6 +249,11 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock)
} }
} }
void dl_harq_entity::dl_harq_process::dl_tb_process::reset_ndi()
{
is_first_tb = true;
}
void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy_lte::tb_action_dl_t* action) mac_interface_phy_lte::tb_action_dl_t* action)
{ {

@ -121,6 +121,7 @@ void mac::start_pcap(srslte::mac_pcap* pcap_)
ra_procedure.start_pcap(pcap); ra_procedure.start_pcap(pcap);
} }
// FIXME: Change the function name and implement reconfiguration as in specs
// Implement Section 5.8 // Implement Section 5.8
void mac::reconfiguration(const uint32_t& cc_idx, const bool& enable) void mac::reconfiguration(const uint32_t& cc_idx, const bool& enable)
{ {
@ -229,8 +230,9 @@ void mac::run_tti(const uint32_t tti)
} }
ra_procedure.step(tti); ra_procedure.step(tti);
ra_window_start = 0; ra_window_start = -1;
ra_procedure.is_rar_window(&ra_window_start, &ra_window_length); ra_window_length = -1;
ra_procedure.update_rar_window(&ra_window_start, &ra_window_length);
timers.step_all(); timers.step_all();
} }
@ -261,7 +263,8 @@ void mac::clear_rntis()
{ {
p_window_start = 0; p_window_start = 0;
si_window_start = 0; si_window_start = 0;
ra_window_start = 0; ra_window_start = -1;
ra_window_length = -1;
bzero(&uernti, sizeof(ue_rnti_t)); bzero(&uernti, sizeof(ue_rnti_t));
} }

@ -355,6 +355,7 @@ void mux::msg3_flush()
if (log_h) { if (log_h) {
Debug("Msg3 buffer flushed\n"); Debug("Msg3 buffer flushed\n");
} }
msg3_buff.clear();
msg3_has_been_transmitted = false; msg3_has_been_transmitted = false;
msg3_pending = false; msg3_pending = false;
} }
@ -365,6 +366,7 @@ bool mux::msg3_is_transmitted()
} }
void mux::msg3_prepare() { void mux::msg3_prepare() {
msg3_has_been_transmitted = false;
msg3_pending = true; msg3_pending = true;
} }
@ -372,15 +374,29 @@ bool mux::msg3_is_pending() {
return msg3_pending; return msg3_pending;
} }
bool mux::msg3_is_empty()
{
return msg3_buff.N_bytes == 0;
}
/* Returns a pointer to the Msg3 buffer */ /* Returns a pointer to the Msg3 buffer */
uint8_t* mux::msg3_get(srslte::byte_buffer_t* payload, uint32_t pdu_sz) uint8_t* mux::msg3_get(srslte::byte_buffer_t* payload, uint32_t pdu_sz)
{ {
if (pdu_get(payload, pdu_sz) != nullptr) { if (pdu_sz < msg3_buff.get_tailroom()) {
msg3_pending = false; if (msg3_is_empty()) {
if (!pdu_get(&msg3_buff, pdu_sz)) {
Error("Moving PDU from Mux unit to Msg3 buffer\n");
return NULL;
}
msg3_pending = false;
}
*payload = msg3_buff;
msg3_has_been_transmitted = true; msg3_has_been_transmitted = true;
return payload->msg; return payload->msg;
} else {
Error("Msg3 size exceeds buffer\n");
return NULL;
} }
return nullptr;
} }
} }

@ -378,8 +378,9 @@ bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t* bsr)
// This function is called by MUX only if Regular BSR has not been triggered before // This function is called by MUX only if Regular BSR has not been triggered before
if (nof_padding_bytes >= 2) { if (nof_padding_bytes >= 2) {
// generate padding BSR // generate padding BSR
triggered_bsr_type = PADDING; set_trigger(PADDING);
generate_bsr(bsr, nof_padding_bytes); generate_bsr(bsr, nof_padding_bytes);
set_trigger(NONE);
ret = true; ret = true;
} }

@ -38,12 +38,20 @@
namespace srsue { namespace srsue {
const char* state_str[6] = {
"RA: INIT: ", "RA: PDCCH: ", "RA: Rx: ", "RA: Backof: ", "RA: ConRes: ", "RA: Complt: "};
#define rError(fmt, ...) Error("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rInfo(fmt, ...) Info("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rDebug(fmt, ...) Debug("%s" fmt, state_str[state], ##__VA_ARGS__)
// Table 7.2-1. Backoff Parameter values // Table 7.2-1. Backoff Parameter values
uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 960, 960, 960}; uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 960, 960, 960, 960};
// Table 7.6-1: DELTA_PREAMBLE values. // Table 7.6-1: DELTA_PREAMBLE values.
int delta_preamble_db_table[5] = {0, 0, -3, -3, 8}; int delta_preamble_db_table[5] = {0, 0, -3, -3, 8};
// Initializes memory and pointers to other objects
void ra_proc::init(phy_interface_mac_lte* phy_h_, void ra_proc::init(phy_interface_mac_lte* phy_h_,
rrc_interface_mac* rrc_, rrc_interface_mac* rrc_,
srslte::log* log_h_, srslte::log* log_h_,
@ -80,15 +88,17 @@ void ra_proc::reset() {
void ra_proc::start_pcap(srslte::mac_pcap* pcap_) void ra_proc::start_pcap(srslte::mac_pcap* pcap_)
{ {
pcap = pcap_; pcap = pcap_;
} }
/* Sets a new configuration. The configuration is applied by initialization() function */
void ra_proc::set_config(srsue::mac_interface_rrc::rach_cfg_t& rach_cfg) void ra_proc::set_config(srsue::mac_interface_rrc::rach_cfg_t& rach_cfg)
{ {
std::unique_lock<std::mutex> ul(mutex); std::unique_lock<std::mutex> ul(mutex);
new_cfg = rach_cfg; new_cfg = rach_cfg;
} }
/* Reads the configuration and configures internal variables */
void ra_proc::read_params() void ra_proc::read_params()
{ {
mutex.lock(); mutex.lock();
@ -117,75 +127,129 @@ void ra_proc::read_params()
} }
} }
bool ra_proc::is_contention_resolution() { /* Function called by MAC every TTI. Runs a state function until it changes to a different state
return state == CONTENTION_RESOLUTION; */
void ra_proc::step(uint32_t tti_)
{
switch (state) {
case IDLE:
break;
case PDCCH_SETUP:
state_pdcch_setup();
break;
case RESPONSE_RECEPTION:
state_response_reception(tti_);
break;
case BACKOFF_WAIT:
state_backoff_wait(tti_);
break;
case CONTENTION_RESOLUTION:
state_contention_resolution();
break;
case COMPLETITION:
state_completition();
break;
}
} }
const char* state_str[12] = {"Idle", /* Waits for PRACH to be transmitted by PHY. Once it's transmitted, configure RA-RNTI and wait for RAR reception
"RA: INIT: ", */
"RA: Select: ", void ra_proc::state_pdcch_setup()
"RA: TX: ", {
"RA: PDCCH: ",
"RA: Rx: ",
"RA: RxErr: ",
"RA: Backof: ",
"RA: ConRes: ",
"RA: Done: ",
"RA: Done: ",
"RA: Error: "};
#define rError(fmt, ...) Error("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rInfo(fmt, ...) Info("%s" fmt, state_str[state], ##__VA_ARGS__)
#define rDebug(fmt, ...) Debug("%s" fmt, state_str[state], ##__VA_ARGS__)
phy_interface_mac_lte::prach_info_t info = phy_h->prach_get_info();
// Process Timing Advance Command as defined in Section 5.2 if (info.is_transmitted) {
void ra_proc::process_timeadv_cmd(uint32_t ta) { ra_tti = info.tti_ra;
if (preambleIndex == 0) { ra_rnti = 1 + (ra_tti % 10) + info.f_id;
// Preamble not selected by UE MAC rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d, f_id=%d\n", sel_preamble, ra_rnti, info.tti_ra, info.f_id);
phy_h->set_timeadv_rar(ta); log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti);
// Only if timer is running reset the timer rar_window_st = ra_tti + 3;
if (time_alignment_timer->is_running()) { rntis->rar_rnti = ra_rnti;
time_alignment_timer->reset(); state = RESPONSE_RECEPTION;
time_alignment_timer->run();
}
Debug("Applying RAR TA CMD %d\n", ta);
} else { } else {
// Preamble selected by UE MAC rDebug("preamble not yet transmitted\n");
if (!time_alignment_timer->is_running()) { }
phy_h->set_timeadv_rar(ta); }
time_alignment_timer->run();
Debug("Applying RAR TA CMD %d\n", ta); /* Waits for RAR reception. rar_received variable will be set by tb_decoded_ok() function which is called when a DL
* TB assigned to RA-RNTI is received
*/
void ra_proc::state_response_reception(uint32_t tti)
{
// do nothing. Processing done in tb_decoded_ok()
if (!rar_received) {
uint32_t interval = srslte_tti_interval(tti, ra_tti + 3 + rach_cfg.responseWindowSize - 1);
if (interval > 0 && interval < 100) {
Error("RA response not received within the response window\n");
response_error();
}
}
}
/* Waits for given backoff interval to expire
*/
void ra_proc::state_backoff_wait(uint32_t tti)
{
if (backoff_interval > 0) {
// Backoff_interval = 0 is handled before entering here
// When we arrive to this state, there is already 1 TTI delay
if (backoff_interval == 1) {
resource_selection();
} else { } else {
// Ignore TA CMD // If it's the first time, save TTI
Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n"); if (backoff_interval_start == -1) {
backoff_interval_start = tti;
backoff_interval--;
}
if (srslte_tti_interval(tti, backoff_interval_start) >= backoff_interval) {
backoff_interval = 0;
resource_selection();
}
} }
} }
} }
void ra_proc::step_initialization() { /* Actions during contention resolution state as defined in 5.1.5
* Resolution of the Contention is made by contention_resolution_id_received() and pdcch_to_crnti()
*/
void ra_proc::state_contention_resolution()
{
// Once Msg3 is transmitted, start contention resolution timer
if (mux_unit->msg3_is_transmitted() && !contention_resolution_timer->is_running()) {
// Start contention resolution timer
rInfo("Starting ContentionResolutionTimer=%d ms\n", contention_resolution_timer->get_timeout());
contention_resolution_timer->reset();
contention_resolution_timer->run();
}
}
/* This step just configures the PHY to generate the C-RNTI. It is called from a state because it takes a long time to
* compute
*/
void ra_proc::state_completition()
{
phy_h->set_crnti(rntis->crnti);
state = IDLE;
}
/* RA procedure initialization as defined in 5.1.1 */
void ra_proc::initialization()
{
read_params(); read_params();
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED; transmitted_contention_id = 0;
transmitted_contention_id = 0;
preambleTransmissionCounter = 1; preambleTransmissionCounter = 1;
first_rar_received = true;
mux_unit->msg3_flush(); mux_unit->msg3_flush();
msg3_flushed = false; backoff_param_ms = 0;
backoff_param_ms = 0;
// FIXME: This is because RA in Connected state not working in amarisoft
transmitted_crnti = rntis->crnti;
if(transmitted_crnti) {
state = RESPONSE_ERROR;
}
// Instruct phy to configure PRACH // Instruct phy to configure PRACH
phy_h->configure_prach_params(); phy_h->configure_prach_params();
state = RESOURCE_SELECTION;
// Jump directly to Resource selection
resource_selection();
} }
void ra_proc::step_resource_selection() /* Resource selection as defined in 5.1.2 */
void ra_proc::resource_selection()
{ {
ra_group_t sel_group; ra_group_t sel_group;
@ -217,7 +281,7 @@ void ra_proc::step_resource_selection()
sel_preamble = rand() % rach_cfg.nof_groupA_preambles; sel_preamble = rand() % rach_cfg.nof_groupA_preambles;
} else { } else {
rError("Selected group preamble A but nof_groupA_preambles=0\n"); rError("Selected group preamble A but nof_groupA_preambles=0\n");
state = RA_PROBLEM; state = IDLE;
return; return;
} }
} else { } else {
@ -226,7 +290,7 @@ void ra_proc::step_resource_selection()
sel_preamble = rach_cfg.nof_groupA_preambles + rand() % nof_groupB_preambles; sel_preamble = rach_cfg.nof_groupA_preambles + rand() % nof_groupB_preambles;
} else { } else {
rError("Selected group preamble B but nof_groupA_preambles=0\n"); rError("Selected group preamble B but nof_groupA_preambles=0\n");
state = RA_PROBLEM; state = IDLE;
return; return;
} }
} }
@ -238,51 +302,55 @@ void ra_proc::step_resource_selection()
sel_maskIndex, sel_maskIndex,
rach_cfg.nof_groupA_preambles, rach_cfg.nof_groupA_preambles,
nof_groupB_preambles); nof_groupB_preambles);
state = PREAMBLE_TRANSMISSION;
// Jump directly to transmission
preamble_transmission();
} }
void ra_proc::step_preamble_transmission() { /* Preamble transmission as defined in 5.1.3 */
void ra_proc::preamble_transmission()
{
received_target_power_dbm = rach_cfg.iniReceivedTargetPower + delta_preamble_db + received_target_power_dbm = rach_cfg.iniReceivedTargetPower + delta_preamble_db +
(preambleTransmissionCounter - 1) * rach_cfg.powerRampingStep; (preambleTransmissionCounter - 1) * rach_cfg.powerRampingStep;
rar_received = false;
phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm); phy_h->prach_send(sel_preamble, sel_maskIndex - 1, received_target_power_dbm);
rntis->rar_rnti = 0;
ra_tti = 0;
rar_received = false;
backoff_interval_start = -1;
state = PDCCH_SETUP; state = PDCCH_SETUP;
} }
bool ra_proc::is_rar_window(int* rar_window_start, int* rar_window_length) // Process Timing Advance Command as defined in Section 5.2
void ra_proc::process_timeadv_cmd(uint32_t ta)
{ {
if (state == RESPONSE_RECEPTION) { if (preambleIndex == 0) {
if (rar_window_length) { // Preamble not selected by UE MAC
*rar_window_length = rach_cfg.responseWindowSize; phy_h->set_timeadv_rar(ta);
} // Only if timer is running reset the timer
if (rar_window_start) { if (time_alignment_timer->is_running()) {
*rar_window_start = rar_window_st; time_alignment_timer->reset();
time_alignment_timer->run();
} }
return true; Debug("Applying RAR TA CMD %d\n", ta);
} else { } else {
if (rar_window_length) { // Preamble selected by UE MAC
*rar_window_length = -1; if (!time_alignment_timer->is_running()) {
phy_h->set_timeadv_rar(ta);
time_alignment_timer->run();
Debug("Applying RAR TA CMD %d\n", ta);
} else {
// Ignore TA CMD
Warning("Ignoring RAR TA CMD because timeAlignmentTimer still running\n");
} }
return false;
}
}
void ra_proc::step_pdcch_setup()
{
phy_interface_mac_lte::prach_info_t info = phy_h->prach_get_info();
if (info.is_transmitted) {
ra_rnti = 1 + info.tti_ra % 10 + info.f_id;
rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d, f_id=%d\n", sel_preamble, ra_rnti, info.tti_ra, info.f_id);
log_h->console("Random Access Transmission: seq=%d, ra-rnti=0x%x\n", sel_preamble, ra_rnti);
rar_window_st = info.tti_ra + 3;
rntis->rar_rnti = ra_rnti;
state = RESPONSE_RECEPTION;
} }
} }
/* Called upon the reception of a DL grant for RA-RNTI
* Configures the action and softbuffer for the reception of the associated TB
*/
void ra_proc::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action) void ra_proc::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action)
{ {
bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
@ -299,10 +367,12 @@ void ra_proc::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_inte
} }
} else { } else {
rError("Received RAR dci exceeds buffer length (%d>%d)\n", grant.tb[0].tbs, MAX_RAR_PDU_LEN); rError("Received RAR dci exceeds buffer length (%d>%d)\n", grant.tb[0].tbs, MAX_RAR_PDU_LEN);
state = RESPONSE_ERROR;
} }
} }
/* Called upon the successful decoding of a TB addressed to RA-RNTI.
* Processes the reception of a RAR as defined in 5.1.4
*/
void ra_proc::tb_decoded_ok() { void ra_proc::tb_decoded_ok() {
if (pcap) { if (pcap) {
pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, 0); pcap->write_dl_ranti(rar_pdu_buffer, rar_grant_nbytes, ra_rnti, true, 0);
@ -312,6 +382,7 @@ void ra_proc::tb_decoded_ok() {
rar_pdu_msg.init_rx(rar_grant_nbytes); rar_pdu_msg.init_rx(rar_grant_nbytes);
rar_pdu_msg.parse_packet(rar_pdu_buffer); rar_pdu_msg.parse_packet(rar_pdu_buffer);
// Set Backoff parameter // Set Backoff parameter
if (rar_pdu_msg.has_backoff()) { if (rar_pdu_msg.has_backoff()) {
backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff()%16]; backoff_param_ms = backoff_table[rar_pdu_msg.get_backoff()%16];
@ -345,14 +416,14 @@ void ra_proc::tb_decoded_ok() {
if (preambleIndex > 0) { if (preambleIndex > 0) {
// Preamble selected by Network // Preamble selected by Network
state = COMPLETION; complete();
} else { } else {
// Preamble selected by UE MAC // Preamble selected by UE MAC
mux_unit->msg3_prepare(); mux_unit->msg3_prepare();
rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti(); rntis->temp_rnti = rar_pdu_msg.get()->get_temp_crnti();
if (first_rar_received) { // If this is the first successfully received RAR within this procedure, Msg3 is empty
first_rar_received = false; if (mux_unit->msg3_is_empty()) {
// Save transmitted C-RNTI (if any) // Save transmitted C-RNTI (if any)
transmitted_crnti = rntis->crnti; transmitted_crnti = rntis->crnti;
@ -361,16 +432,14 @@ void ra_proc::tb_decoded_ok() {
if (transmitted_crnti) { if (transmitted_crnti) {
rInfo("Appending C-RNTI MAC CE 0x%x in next transmission\n", transmitted_crnti); rInfo("Appending C-RNTI MAC CE 0x%x in next transmission\n", transmitted_crnti);
mux_unit->append_crnti_ce_next_tx(transmitted_crnti); mux_unit->append_crnti_ce_next_tx(transmitted_crnti);
rntis->crnti = transmitted_crnti;
} }
} }
rDebug("Going to Contention Resolution state\n");
state = CONTENTION_RESOLUTION;
// Start contention resolution timer // Save transmitted UE contention id, as defined by higher layers
rInfo("Starting ContentionResolutionTimer=%d ms\n", contention_resolution_timer->get_timeout()); transmitted_contention_id = rntis->contention_id;
contention_resolution_timer->reset();
contention_resolution_timer->run(); rDebug("Waiting for Contention Resolution\n");
state = CONTENTION_RESOLUTION;
} }
} else { } else {
if (rar_pdu_msg.get()->has_rapid()) { if (rar_pdu_msg.get()->has_rapid()) {
@ -380,170 +449,61 @@ void ra_proc::tb_decoded_ok() {
} }
} }
void ra_proc::step_response_reception(uint32_t tti) /* Called after RA response window expiration without a valid RAPID or after a reception of an invalid
{ * Contention Resolution ID
// do nothing. Processing done in tb_decoded_ok() */
phy_interface_mac_lte::prach_info_t prach_info = phy_h->prach_get_info(); void ra_proc::response_error()
if (prach_info.is_transmitted && !rar_received) {
uint32_t interval = srslte_tti_interval(tti, prach_info.tti_ra + 3 + rach_cfg.responseWindowSize);
if (interval > 1 && interval < 100) {
Error("RA response not received within the response window\n");
state = RESPONSE_ERROR;
}
}
}
void ra_proc::step_response_error(uint32_t tti)
{ {
rntis->temp_rnti = 0;
preambleTransmissionCounter++; preambleTransmissionCounter++;
if (preambleTransmissionCounter >= rach_cfg.preambleTransMax + 1) { if (preambleTransmissionCounter >= rach_cfg.preambleTransMax + 1) {
rError("Maximum number of transmissions reached (%d)\n", rach_cfg.preambleTransMax); rError("Maximum number of transmissions reached (%d)\n", rach_cfg.preambleTransMax);
rrc->ra_problem(); rrc->ra_problem();
state = RA_PROBLEM; state = IDLE;
if (ra_is_ho) { if (ra_is_ho) {
rrc->ho_ra_completed(false); rrc->ho_ra_completed(false);
} }
} else { } else {
backoff_interval_start = tti; backoff_interval_start = -1;
if (backoff_param_ms) { if (backoff_param_ms) {
backoff_inteval = rand() % backoff_param_ms; backoff_interval = rand() % backoff_param_ms;
} else { } else {
backoff_inteval = 0; backoff_interval = 0;
} }
if (backoff_inteval) { if (backoff_interval) {
rDebug("Backoff wait interval %d\n", backoff_inteval); rDebug("Backoff wait interval %d\n", backoff_interval);
state = BACKOFF_WAIT; state = BACKOFF_WAIT;
} else { } else {
rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, rach_cfg.preambleTransMax); rDebug("Transmitting inmediatly (%d/%d)\n", preambleTransmissionCounter, rach_cfg.preambleTransMax);
state = RESOURCE_SELECTION; resource_selection();
} }
} }
} }
void ra_proc::step_backoff_wait(uint32_t tti) bool ra_proc::is_contention_resolution()
{ {
if (srslte_tti_interval(tti, backoff_interval_start) >= backoff_inteval) { return state == CONTENTION_RESOLUTION;
state = RESOURCE_SELECTION;
}
}
// Random Access initiated by RRC by the transmission of CCCH SDU
bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) {
bool uecri_successful = false;
rDebug("MAC PDU Contains Contention Resolution ID CE\n");
// MAC PDU successfully decoded and contains MAC CE contention Id
contention_resolution_timer->stop();
if (transmitted_contention_id == rx_contention_id)
{
// UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3
uecri_successful = true;
state = COMPLETION;
} else {
rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%" PRIu64 " != 0x%" PRIu64 ")\n",
transmitted_contention_id, rx_contention_id);
// Discard MAC PDU
uecri_successful = false;
// Contention Resolution not successfully is like RAR not successful
// FIXME: Need to flush Msg3 HARQ buffer. Why?
state = RESPONSE_ERROR;
}
return uecri_successful;
}
void ra_proc::step_contention_resolution() {
// If Msg3 has been sent
if (mux_unit->msg3_is_transmitted())
{
msg3_transmitted = true;
if (transmitted_crnti) {
// Random Access with transmission of MAC C-RNTI CE
if ((!started_by_pdcch && pdcch_to_crnti_received == PDCCH_CRNTI_UL_GRANT) ||
(started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED))
{
rDebug("PDCCH for C-RNTI received\n");
contention_resolution_timer->stop();
state = COMPLETION;
}
pdcch_to_crnti_received = PDCCH_CRNTI_NOT_RECEIVED;
} else {
// RA with transmission of CCCH SDU is resolved in contention_resolution_id_received() callback function
if (!transmitted_contention_id) {
// Save transmitted UE contention id, as defined by higher layers
transmitted_contention_id = rntis->contention_id;
rntis->contention_id = 0;
}
}
} else {
rDebug("Msg3 not yet transmitted\n");
}
} }
void ra_proc::step_completition() /* Perform the actions upon completition of the RA procedure as defined in 5.1.6 */
void ra_proc::complete()
{ {
/* Start looking for PDCCH CRNTI */
// Start looking for PDCCH CRNTI
if (!transmitted_crnti) { if (!transmitted_crnti) {
rntis->crnti = rntis->temp_rnti; rntis->crnti = rntis->temp_rnti;
} }
rntis->temp_rnti = 0; rntis->temp_rnti = 0;
log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta); mux_unit->msg3_flush();
rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
if (!msg3_flushed) {
mux_unit->msg3_flush();
msg3_flushed = true;
}
phy_h->set_crnti(rntis->crnti);
msg3_transmitted = false; msg3_transmitted = false;
state = COMPLETION_DONE;
if (ra_is_ho) { if (ra_is_ho) {
rrc->ho_ra_completed(true); rrc->ho_ra_completed(true);
} }
} log_h->console("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
rInfo("Random Access Complete. c-rnti=0x%x, ta=%d\n", rntis->crnti, current_ta);
void ra_proc::step(uint32_t tti_) state = COMPLETITION;
{
switch(state) {
case IDLE:
break;
case INITIALIZATION:
step_initialization();
break;
case RESOURCE_SELECTION:
step_resource_selection();
break;
case PREAMBLE_TRANSMISSION:
step_preamble_transmission();
break;
case PDCCH_SETUP:
step_pdcch_setup();
break;
case RESPONSE_RECEPTION:
step_response_reception(tti_);
break;
case RESPONSE_ERROR:
step_response_error(tti_);
break;
case BACKOFF_WAIT:
step_backoff_wait(tti_);
break;
case CONTENTION_RESOLUTION:
step_contention_resolution();
break;
case COMPLETION:
step_completition();
case COMPLETION_DONE:
case RA_PROBLEM:
break;
}
} }
void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) { void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) {
@ -555,21 +515,25 @@ void ra_proc::start_noncont(uint32_t preamble_index, uint32_t prach_mask) {
void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho) void ra_proc::start_mac_order(uint32_t msg_len_bits, bool is_ho)
{ {
if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { if (state == IDLE) {
ra_is_ho = is_ho; ra_is_ho = is_ho;
started_by_pdcch = false; started_by_pdcch = false;
new_ra_msg_len = msg_len_bits; new_ra_msg_len = msg_len_bits;
state = INITIALIZATION;
rInfo("Starting PRACH by MAC order\n"); rInfo("Starting PRACH by MAC order\n");
initialization();
} else {
Warning("Trying to start PRACH by MAC order in invalid state (%s)\n", state_str[state]);
} }
} }
void ra_proc::start_pdcch_order() void ra_proc::start_pdcch_order()
{ {
if (state == IDLE || state == COMPLETION_DONE || state == RA_PROBLEM) { if (state == IDLE) {
started_by_pdcch = true; started_by_pdcch = true;
state = INITIALIZATION;
rInfo("Starting PRACH by PDCCH order\n"); rInfo("Starting PRACH by PDCCH order\n");
initialization();
} else {
Warning("Trying to start PRACH by MAC order in invalid state (%s)\n", state_str[state]);
} }
} }
@ -577,29 +541,79 @@ void ra_proc::start_pdcch_order()
void ra_proc::timer_expired(uint32_t timer_id) void ra_proc::timer_expired(uint32_t timer_id)
{ {
rInfo("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error\n"); rInfo("Contention Resolution Timer expired. Stopping PDCCH Search and going to Response Error\n");
bzero(rntis, sizeof(mac_interface_rrc::ue_rnti_t)); response_error();
state = RESPONSE_ERROR; }
/* Function called by MAC when a Contention Resolution ID CE is received.
* Performs the actions defined in 5.1.5 for Temporal C-RNTI Contention Resolution
*/
bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id)
{
bool uecri_successful = false;
rDebug("MAC PDU Contains Contention Resolution ID CE\n");
// MAC PDU successfully decoded and contains MAC CE contention Id
contention_resolution_timer->stop();
if (transmitted_contention_id == rx_contention_id) {
// UE Contention Resolution ID included in MAC CE matches the CCCH SDU transmitted in Msg3
uecri_successful = true;
complete();
} else {
rInfo("Transmitted UE Contention Id differs from received Contention ID (0x%lx != 0x%lx)\n",
transmitted_contention_id,
rx_contention_id);
// Discard MAC PDU
uecri_successful = false;
// Contention Resolution not successfully is like RAR not successful
response_error();
}
return uecri_successful;
} }
void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) { void ra_proc::pdcch_to_crnti(bool is_new_uplink_transmission)
rDebug("PDCCH to C-RNTI received %s UL dci\n", contains_uplink_grant ? "with" : "without"); {
if (contains_uplink_grant) { rDebug("PDCCH to C-RNTI received %s new UL transmission\n", is_new_uplink_transmission ? "with" : "without");
pdcch_to_crnti_received = PDCCH_CRNTI_UL_GRANT; if ((!started_by_pdcch && is_new_uplink_transmission) || started_by_pdcch) {
} else if (pdcch_to_crnti_received == PDCCH_CRNTI_NOT_RECEIVED) { rDebug("PDCCH for C-RNTI received\n");
pdcch_to_crnti_received = PDCCH_CRNTI_DL_GRANT; contention_resolution_timer->stop();
complete();
}
}
bool ra_proc::update_rar_window(int* rar_window_start, int* rar_window_length)
{
if (state == RESPONSE_RECEPTION) {
if (rar_window_length) {
*rar_window_length = rach_cfg.responseWindowSize;
}
if (rar_window_start) {
*rar_window_start = rar_window_st;
}
return true;
} else {
if (rar_window_length) {
*rar_window_length = -1;
}
return false;
} }
} }
// Restart timer at each Msg3 HARQ retransmission (5.1.5)
void ra_proc::harq_retx() void ra_proc::harq_retx()
{ {
rInfo("Restarting ContentionResolutionTimer=%d ms\n", contention_resolution_timer->get_timeout());
contention_resolution_timer->reset(); contention_resolution_timer->reset();
} }
void ra_proc::harq_max_retx() void ra_proc::harq_max_retx()
{ {
Warning("Contention Resolution is considered not successful. Stopping PDCCH Search and going to Response Error\n"); Warning("Contention Resolution is considered not successful. Stopping PDCCH Search and going to Response Error\n");
bzero(rntis, sizeof(mac_interface_rrc::ue_rnti_t)); response_error();
state = RESPONSE_ERROR;
} }
} }

@ -49,7 +49,8 @@ void sr_proc::reset()
bool sr_proc::need_tx(uint32_t tti) bool sr_proc::need_tx(uint32_t tti)
{ {
int last_tx_tti = phy_h->sr_last_tx_tti(); int last_tx_tti = phy_h->sr_last_tx_tti();
Info("SR: need_tx(): last_tx_tti=%d, tti=%d\n", last_tx_tti, tti);
if (last_tx_tti >= 0) { if (last_tx_tti >= 0) {
if (tti > (uint32_t)last_tx_tti) { if (tti > (uint32_t)last_tx_tti) {
if (tti - last_tx_tti > 8) { if (tti - last_tx_tti > 8) {

@ -199,10 +199,6 @@ void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy_lte::mac_gr
harq_feedback = grant.hi_value; harq_feedback = grant.hi_value;
} }
if (grant.rnti == harq_entity->rntis->crnti && harq_entity->ra_procedure->is_contention_resolution()) {
harq_entity->ra_procedure->pdcch_to_crnti(true);
}
// Get maximum retransmissions // Get maximum retransmissions
uint32_t max_retx; uint32_t max_retx;
if (grant_is_rar()) { if (grant_is_rar()) {
@ -218,7 +214,7 @@ void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy_lte::mac_gr
harq_entity->ra_procedure->harq_max_retx(); harq_entity->ra_procedure->harq_max_retx();
} }
reset(); reset();
} else if (grant_is_rar()) { } else if (grant_is_rar() && current_tx_nb) {
harq_entity->ra_procedure->harq_retx(); harq_entity->ra_procedure->harq_retx();
} }
} }
@ -244,6 +240,10 @@ void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy_lte::mac_gr
// New transmission // New transmission
reset(); reset();
if (grant.rnti == harq_entity->rntis->crnti && harq_entity->ra_procedure->is_contention_resolution()) {
harq_entity->ra_procedure->pdcch_to_crnti(true);
}
// Check buffer size // Check buffer size
if (grant.tb.tbs > payload_buffer_len) { if (grant.tb.tbs > payload_buffer_len) {
Error("Grant size exceeds payload buffer size (%d > %d)\n", grant.tb.tbs, payload_buffer_len); Error("Grant size exceeds payload buffer size (%d > %d)\n", grant.tb.tbs, payload_buffer_len);

@ -31,7 +31,7 @@
using namespace srsue; using namespace srsue;
using namespace srslte; using namespace srslte;
#define HAVE_PCAP 0 #define HAVE_PCAP 1
static std::unique_ptr<srslte::mac_pcap> pcap_handle = nullptr; static std::unique_ptr<srslte::mac_pcap> pcap_handle = nullptr;
@ -57,7 +57,7 @@ public:
uint32_t len = SRSLTE_MIN(ul_queues[lcid], nof_bytes); uint32_t len = SRSLTE_MIN(ul_queues[lcid], nof_bytes);
// set payload bytes to LCID so we can check later if the scheduling was correct // set payload bytes to LCID so we can check later if the scheduling was correct
memset(payload, lcid, len); memset(payload, lcid > 0 ? lcid : 0xf, len);
// remove from UL queue // remove from UL queue
ul_queues[lcid] -= len; ul_queues[lcid] -= len;
@ -88,24 +88,74 @@ class phy_dummy : public phy_interface_mac_lte
{ {
public: public:
phy_dummy() : scell_cmd(0){}; phy_dummy() : scell_cmd(0){};
void set_log(srslte::log* log_h) { this->log_h = log_h; }
void reset()
{
last_preamble_idx = 0;
last_target_power = 0;
prach_delay_cnt = 0;
prach_tti = 0;
nof_rar_grants = 0;
rar_temp_rnti = 0;
rar_time_adv = 0;
last_crnti = 0;
prach_transmitted = false;
prach_info_tx = false;
}
void set_prach_tti(uint32_t tti, bool reset_transmitted = true)
{
this->prach_tti = tti;
if (reset_transmitted) {
prach_transmitted = false;
}
}
// phy_interface_mac_lte // phy_interface_mac_lte
void configure_prach_params(){}; void configure_prach_params(){};
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm){};
void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm)
{
prach_delay_cnt = 0;
last_preamble_idx = preamble_idx;
last_target_power = target_power_dbm;
prach_transmitted = true;
prach_info_tx = true;
log_h->info("PRACH will be transmitted at tti=%d, preamble_idx=%d\n", prach_tti, preamble_idx);
}
prach_info_t prach_get_info() prach_info_t prach_get_info()
{ {
prach_info_t info = {}; prach_info_t info = {};
if (prach_info_tx) {
prach_delay_cnt++;
if (prach_delay_cnt > prach_delay) {
info.tti_ra = prach_tti;
prach_info_tx = false;
info.is_transmitted = true;
log_h->info("PRACH has been transmitted\n");
}
}
return info; return info;
}; };
void sr_send(){}; void sr_send(){};
int sr_last_tx_tti() { return 0; }; int sr_last_tx_tti() { return 0; };
void set_mch_period_stop(uint32_t stop){}; void set_mch_period_stop(uint32_t stop){};
// phy_interface_mac_common // phy_interface_mac_common
void set_crnti(uint16_t rnti){}; void set_crnti(uint16_t rnti) { last_crnti = rnti; }
void set_timeadv_rar(uint32_t ta_cmd){}; void set_timeadv_rar(uint32_t ta_cmd) { rar_time_adv = ta_cmd; }
void set_timeadv(uint32_t ta_cmd){}; void set_timeadv(uint32_t ta_cmd){};
void set_activation_deactivation_scell(uint32_t cmd) { scell_cmd = cmd; }; void set_activation_deactivation_scell(uint32_t cmd) { scell_cmd = cmd; };
void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti){}; void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti)
{
memcpy(rar_payload, grant_payload, SRSLTE_RAR_GRANT_LEN);
rar_temp_rnti = rnti;
nof_rar_grants++;
}
uint32_t get_current_tti() { return 0; } uint32_t get_current_tti() { return 0; }
float get_phr() { return 0; }; float get_phr() { return 0; };
float get_pathloss_db() { return 0; }; float get_pathloss_db() { return 0; };
@ -113,17 +163,161 @@ public:
// getter for test execution // getter for test execution
uint32_t get_scell_cmd() { return scell_cmd; } uint32_t get_scell_cmd() { return scell_cmd; }
// Testing methods
int dl_grant(mac* mac_h, bool ack, uint16_t rnti, uint32_t len, const uint8_t* payload)
{
bool ack_v[SRSLTE_MAX_CODEWORDS] = {ack, 0};
mac_interface_phy_lte::tb_action_dl_t dl_action = {};
mac_interface_phy_lte::mac_grant_dl_t dl_mac_grant = {};
// Send grant to MAC
dl_mac_grant.rnti = rnti;
dl_mac_grant.tb[0].ndi = dl_ndi;
dl_mac_grant.tb[0].ndi_present = true;
dl_mac_grant.tb[0].tbs = len;
mac_h->new_grant_dl(0, dl_mac_grant, &dl_action);
if (ack && !SRSLTE_RNTI_ISRAR(rnti)) {
dl_ndi = !dl_ndi;
}
TESTASSERT(dl_action.tb[0].enabled);
TESTASSERT((int)dl_action.tb[0].rv == dl_mac_grant.tb[0].rv);
// Copy data and send tb_decoded
memcpy(dl_action.tb[0].payload, payload, len);
// print generated PDU
log_h->info_hex(
dl_action.tb[0].payload, dl_mac_grant.tb[0].tbs, "Generated DL PDU (%d B)\n", dl_mac_grant.tb[0].tbs);
#if HAVE_PCAP
pcap_handle->write_dl_crnti(dl_action.tb[0].payload, dl_mac_grant.tb[0].tbs, rnti, true, 1);
#endif
mac_h->tb_decoded(0, dl_mac_grant, ack_v);
return 0;
}
int rar_and_check(mac* mac_h, bool preamble_matches, uint32_t temp_rnti)
{
// Generate RAR to MAC
uint8_t grant[SRSLTE_RAR_GRANT_LEN] = {};
memset(grant, 1, SRSLTE_RAR_GRANT_LEN);
uint32_t rar_timeadv = 16;
srslte::rar_pdu rar_pdu_msg;
byte_buffer.clear();
rar_pdu_msg.init_tx(&byte_buffer, 7);
if (rar_pdu_msg.new_subh()) {
rar_pdu_msg.get()->set_rapid(preamble_matches ? last_preamble_idx : (last_preamble_idx + 1));
rar_pdu_msg.get()->set_ta_cmd(rar_timeadv);
rar_pdu_msg.get()->set_temp_crnti(temp_rnti);
rar_pdu_msg.get()->set_sched_grant(grant);
}
rar_pdu_msg.write_packet(byte_buffer.msg);
// Send RAR grant to MAC
dl_grant(mac_h, true, get_rar_rnti(), 7, byte_buffer.msg);
// Check MAC passes RAR grant and TA cmd to PHY
if (preamble_matches) {
TESTASSERT(!memcmp(rar_payload, grant, SRSLTE_RAR_GRANT_LEN));
TESTASSERT(rar_temp_rnti == temp_rnti);
TESTASSERT(rar_time_adv == rar_timeadv);
}
return 0;
}
int ul_grant_and_check_tv(mac* mac_h, bool ack, uint16_t rnti, uint32_t len, const uint8_t* tv)
{
mac_interface_phy_lte::tb_action_ul_t ul_action = {};
mac_interface_phy_lte::mac_grant_ul_t ul_mac_grant = {};
// Generate UL Grant
ul_mac_grant.phich_available = !ack;
ul_mac_grant.rnti = rnti;
ul_mac_grant.tb.ndi = ul_ndi;
ul_mac_grant.tb.ndi_present = ack;
ul_mac_grant.tb.tbs = len;
if (ack) {
ul_ndi = !ul_ndi;
}
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
mac_h->new_grant_ul(0, ul_mac_grant, &ul_action);
// print generated PDU
log_h->info_hex(ul_action.tb.payload, ul_mac_grant.tb.tbs, "Generated UL PDU (%d B)\n", ul_mac_grant.tb.tbs);
#if HAVE_PCAP
pcap_handle->write_ul_crnti(ul_action.tb.payload, ul_mac_grant.tb.tbs, rnti, true, 1);
#endif
if (tv && ul_action.tb.payload) {
return memcmp(ul_action.tb.payload, tv, len);
} else {
return 0;
}
}
int get_last_preamble() { return last_preamble_idx; }
uint32_t is_prach_transmitted() { return prach_transmitted; }
uint32_t get_rar_rnti() { return (prach_tti % 10) + 1; }
uint16_t get_crnti() { return last_crnti; }
const static uint32_t prach_delay = 5;
private: private:
uint32_t scell_cmd; uint32_t scell_cmd = 0;
uint32_t prach_delay_cnt = 0;
uint32_t prach_tti = 0;
bool prach_info_tx = false;
bool prach_transmitted = false;
float last_target_power = 0;
int last_preamble_idx = -1;
uint16_t last_crnti = 0;
srslte::log* log_h;
bool ul_ndi = false;
bool dl_ndi = false;
byte_buffer_t byte_buffer;
uint32_t nof_rar_grants = 0;
uint32_t rar_time_adv = 0;
uint16_t rar_temp_rnti = 0;
uint8_t rar_payload[SRSLTE_RAR_GRANT_LEN];
}; };
class rrc_dummy : public rrc_interface_mac class rrc_dummy : public rrc_interface_mac
{ {
public: public:
void ho_ra_completed(bool ra_successful) { printf("%s\n", __FUNCTION__); } void ho_ra_completed(bool ra_successful)
{
ho_finish = true;
ho_finish_successful = ra_successful;
}
void release_pucch_srs() { printf("%s\n", __FUNCTION__); } void release_pucch_srs() { printf("%s\n", __FUNCTION__); }
void run_tti(uint32_t tti) { printf("%s\n", __FUNCTION__); } void run_tti(uint32_t tti) { printf("%s\n", __FUNCTION__); }
void ra_problem() { printf("%s\n", __FUNCTION__); } void ra_problem() { rach_problem++; }
bool ho_finish = false;
bool ho_finish_successful = false;
uint32_t rach_problem = 0;
}; };
} // namespace srslte } // namespace srslte
@ -873,10 +1067,185 @@ int mac_ul_sch_pdu_three_byte_test()
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
// UL-SCH with Trucated BSR and 6 B Msg3 struct ra_test {
int mac_ul_sch_pdu_msg3_test() uint32_t nof_prachs;
uint32_t rar_nof_rapid; // set to zero to don't transmit RAR
uint32_t rar_nof_invalid_rapid;
uint16_t crnti;
uint16_t temp_rnti;
uint32_t nof_msg3_retx;
uint32_t preamble_idx;
int assume_prach_transmitted;
bool send_valid_ul_grant;
bool msg4_enable;
bool msg4_valid_conres;
bool check_ra_successful;
asn1::rrc::rach_cfg_common_s rach_cfg;
};
struct ra_test test;
int run_mac_ra_test(struct ra_test test, mac* mac, phy_dummy* phy, uint32_t* tti_state)
{
uint32_t tti = *tti_state;
const uint8_t tv_msg3[] = {0x3c, 0x00, 0xd0, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
const uint8_t tv_msg3_ce[] = {0x1b, 0x00, 0x65};
uint32_t msg4_len = 7;
const uint8_t tv_msg4_nocontres[] = {0x1f, 0x1f};
const uint8_t tv_msg4_valid[] = {0x1c, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
const uint8_t tv_msg4_invalid[] = {0x1c, 0x0f, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f};
uint16_t temp_rnti = test.temp_rnti;
bool new_prach = false;
for (uint32_t j = 0; j < test.nof_prachs; j++) {
// In the next TTI, a BSR shall be triggered which triggers SR which triggers PRACH
if (test.assume_prach_transmitted != (int)j) {
phy->set_prach_tti(tti + phy->prach_delay);
mac->run_tti(tti++);
}
// Check MAC instructs PHY to transmit PRACH
TESTASSERT(phy->is_prach_transmitted());
// Test preamble index
if (test.preamble_idx) {
TESTASSERT(phy->get_last_preamble() == (int)test.preamble_idx);
} else {
TESTASSERT(phy->get_last_preamble() < test.rach_cfg.preamb_info.nof_ra_preambs.to_number());
}
// TODO: Test power ramping
// Check MAC does not schedule RA-RNTI before window starts
for (uint32_t i = 0; i < phy->prach_delay + 3 - 1; i++) {
mac->run_tti(tti);
TESTASSERT(!SRSLTE_RNTI_ISRAR(mac->get_dl_sched_rnti(tti)));
tti++;
}
bool rapid_found = false;
// Check MAC schedules correct RA-RNTI during window
for (uint32_t i = 0; i < test.rach_cfg.ra_supervision_info.ra_resp_win_size.to_number() && !rapid_found; i++) {
mac->run_tti(tti);
TESTASSERT(mac->get_dl_sched_rnti(tti) == phy->get_rar_rnti());
tti++;
// Receive RAR
if (test.rar_nof_rapid > 0) {
rapid_found = i >= test.rar_nof_invalid_rapid;
if (phy->rar_and_check(mac, rapid_found, temp_rnti)) {
return -1;
}
}
}
// Run Contention Resolution if received correct RAPID
if (rapid_found) {
// Skip Contention resolution if preamble chosen by network
if (test.preamble_idx) {
break;
}
// Request Msg3 (re)-transmission
for (uint32_t i = 0; i < test.nof_msg3_retx + 1; i++) {
// Step to contention resolution. Make sure timer does not start until Msg3 is transmitted
// and restarts on every retx
for (int j = 0; j < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; j++) {
mac->run_tti(tti);
TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti));
tti++;
}
if (i == test.rach_cfg.max_harq_msg3_tx) {
phy->set_prach_tti(tti + phy->prach_delay, false);
}
if (test.crnti) {
TESTASSERT(!phy->ul_grant_and_check_tv(mac, i == 0, temp_rnti, 3, tv_msg3_ce));
} else {
TESTASSERT(!phy->ul_grant_and_check_tv(mac, i == 0, temp_rnti, 9, tv_msg3));
}
}
if (test.nof_msg3_retx == test.rach_cfg.max_harq_msg3_tx) {
TESTASSERT(mac->get_dl_sched_rnti(tti) != temp_rnti);
break;
}
for (int i = 0; i < test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 1; i++) {
mac->run_tti(tti);
TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti));
tti++;
if (test.msg4_enable) {
if (test.crnti) {
// Test a DL grant does not resolve the contention resolution
if (phy->dl_grant(mac, true, test.crnti, 2, tv_msg4_nocontres)) {
return -1;
}
TESTASSERT(phy->get_crnti() != test.crnti);
// UL grant is checked later
if (test.send_valid_ul_grant) {
if (phy->ul_grant_and_check_tv(mac, true, test.crnti, 2, NULL)) {
return -1;
}
break;
} else if ((int)i == test.rach_cfg.ra_supervision_info.mac_contention_resolution_timer.to_number() - 2) {
new_prach = true;
}
} else {
if (phy->dl_grant(
mac, true, temp_rnti, msg4_len, test.msg4_valid_conres ? tv_msg4_valid : tv_msg4_invalid)) {
return -1;
}
if (!test.msg4_valid_conres) {
new_prach = true;
}
break;
}
}
}
}
if (new_prach) {
test.assume_prach_transmitted = (int)j + 1;
phy->set_prach_tti(tti + phy->prach_delay, false);
TESTASSERT(mac->get_dl_sched_rnti(tti) != temp_rnti);
mac->run_tti(tti++);
}
}
// RA procedure should be completed here
if (test.check_ra_successful) {
mac->run_tti(tti);
TESTASSERT(phy->get_crnti() == (test.crnti ? test.crnti : test.temp_rnti));
TESTASSERT(mac->get_dl_sched_rnti(tti) == (test.crnti ? test.crnti : test.temp_rnti));
tti++;
}
*tti_state = tti;
return 0;
}
/* Tests MAC RA procedure specified in 5.1 of 36.321
* Currently not covered:
* - Selection of groupA/groupB sequences
* - Backoff timer
* - PDCCH order RACH initiation
* - Ignore RAR TA cmd when TA-Timer is running
*/
int mac_random_access_test()
{ {
const uint8_t tv[] = {0x3c, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint64_t contention_id = 0xf0f0f0f0f0f;
srslte::log_filter phy_log("PHY");
phy_log.set_level(srslte::LOG_LEVEL_DEBUG);
phy_log.set_hex_limit(100000);
srslte::log_filter mac_log("MAC"); srslte::log_filter mac_log("MAC");
mac_log.set_level(srslte::LOG_LEVEL_DEBUG); mac_log.set_level(srslte::LOG_LEVEL_DEBUG);
@ -888,14 +1257,26 @@ int mac_ul_sch_pdu_msg3_test()
// dummy layers // dummy layers
phy_dummy phy; phy_dummy phy;
phy.set_log(&phy_log);
rlc_dummy rlc(&rlc_log); rlc_dummy rlc(&rlc_log);
rrc_dummy rrc; rrc_dummy rrc;
// the actual MAC // Configure default RACH parameters
asn1::rrc::rach_cfg_common_s rach_cfg = {};
rach_cfg.preamb_info.nof_ra_preambs = asn1::rrc::rach_cfg_common_s::preamb_info_s_::nof_ra_preambs_opts::n12;
rach_cfg.ra_supervision_info.preamb_trans_max = asn1::rrc::preamb_trans_max_opts::n8;
rach_cfg.ra_supervision_info.ra_resp_win_size =
asn1::rrc::rach_cfg_common_s::ra_supervision_info_s_::ra_resp_win_size_e_::sf4;
rach_cfg.max_harq_msg3_tx = 2;
rach_cfg.ra_supervision_info.mac_contention_resolution_timer =
asn1::rrc::rach_cfg_common_s::ra_supervision_info_s_::mac_contention_resolution_timer_opts::sf8;
// Configure MAC
mac mac(&mac_log); mac mac(&mac_log);
mac.init(&phy, &rlc, &rrc); mac.init(&phy, &rlc, &rrc);
const uint16_t crnti = 0x1001; mac_interface_rrc::mac_cfg_t mac_cfg;
mac.set_ho_rnti(crnti, 0); mac_cfg.set_rach_cfg_common(rach_cfg);
mac.set_config(mac_cfg);
// generate config for LCIDs in different LCGs than CCCH // generate config for LCIDs in different LCGs than CCCH
std::vector<logical_channel_config_t> lcids; std::vector<logical_channel_config_t> lcids;
@ -913,41 +1294,148 @@ int mac_ul_sch_pdu_msg3_test()
mac.setup_lcid(channel.lcid, channel.lcg, channel.priority, channel.PBR, channel.BSD); mac.setup_lcid(channel.lcid, channel.lcg, channel.priority, channel.PBR, channel.BSD);
} }
// write dummy data // Generate Msg3
mac.set_contention_id(contention_id);
rlc.write_sdu(0, 6); // UL-CCCH with Msg3 rlc.write_sdu(0, 6); // UL-CCCH with Msg3
rlc.write_sdu(3, 100); // DRB data on other LCG rlc.write_sdu(3, 100); // DRB data on other LCG
// generate TTI
uint32 tti = 0; uint32 tti = 0;
mac.run_tti(tti++);
usleep(100);
// create UL action and grant and push MAC PDU
{
mac_interface_phy_lte::tb_action_ul_t ul_action = {};
mac_interface_phy_lte::mac_grant_ul_t mac_grant = {};
mac_grant.rnti = crnti; // make sure MAC picks it up as valid UL grant
mac_grant.tb.ndi_present = true;
mac_grant.tb.ndi = true;
mac_grant.tb.tbs = 9; // give room for MAC subheader, SDU and one padding byte
int cc_idx = 0;
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
mac.new_grant_ul(cc_idx, mac_grant, &ul_action);
// print generated PDU // Structure that defines the test to be executed
mac_log.info_hex(ul_action.tb.payload, mac_grant.tb.tbs, "Generated PDU (%d B)\n", mac_grant.tb.tbs); struct ra_test my_test;
#if HAVE_PCAP uint32_t test_id = 1;
pcap_handle->write_ul_crnti(ul_action.tb.payload, mac_grant.tb.tbs, 0x1001, true, 1); ZERO_OBJECT(my_test);
#endif my_test.temp_rnti = 100;
my_test.assume_prach_transmitted = -1;
// Test 1: No RAR is received.
// According to end of 5.1.5, UE sends up to preamb_trans_max upon which indicates RA problem to higher layers
mac_log.info("\n=========== Test %d =============\n", test_id++);
my_test.rach_cfg = rach_cfg;
my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number();
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Make sure it triggers RRC signal
mac.run_tti(tti++);
TESTASSERT(rrc.rach_problem == 1);
// Reset MAC
mac.reset();
phy.reset();
mac.set_contention_id(contention_id);
// Test 2: RAR received but no matching RAPID
// The UE receives a RAR without a matching RAPID on every RAR response window TTI.
// According to 5.1.5, the RA procedure is considered non successful and tries again
mac_log.info("\n=========== Test %d =============\n", test_id++);
my_test.rar_nof_rapid = 1;
my_test.nof_prachs = 1;
my_test.rar_nof_invalid_rapid = rach_cfg.ra_supervision_info.ra_resp_win_size.to_number();
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Test 3: RAR received but no matching RAPID. Test Msg3 retransmissions
// On each HARQ retx, contention resolution timer must be restarted (5.1.5)
// When max-HARQ-msg3-retx, contention not successful
mac_log.info("\n=========== Test %d =============\n", test_id++);
my_test.rar_nof_invalid_rapid = 0;
my_test.nof_msg3_retx = rach_cfg.max_harq_msg3_tx;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Test 4: RAR with valid RAPID. Msg3 transmitted, Msg4 received but invalid ConRes
// Contention resolution is defined in 5.1.5. If ConResID does not match, the ConRes is considered
// not successful and tries again
mac_log.info("\n=========== Test %d =============\n", test_id++);
phy.reset();
my_test.nof_msg3_retx = 0;
my_test.msg4_enable = true;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Test 5: Msg4 received and valid ConRes. In this case a valid ConResID is received and RA procedure is successful
mac_log.info("\n=========== Test %d =============\n", test_id++);
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
my_test.msg4_valid_conres = true;
my_test.check_ra_successful = true;
my_test.assume_prach_transmitted = 0;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Test 6: RA with existing C-RNTI (Sends C-RNTI MAC CE)
// The transmission of C-RNTI MAC CE is only done if no CCCH is present (5.1.4).
// To trigger a new RA we have to either generate more data for DRB or wait until BSR-reTX is triggered
rlc.write_sdu(3, 100);
phy.set_crnti(0);
mac_log.info("\n=========== Test %d =============\n", test_id++);
my_test.crnti = my_test.temp_rnti;
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
my_test.assume_prach_transmitted = -1;
my_test.send_valid_ul_grant = true;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
// Test 7: Test Contention based Random Access. This is used eg in HO where preamble is chosen by UE.
// It is similar to Test 5 because C-RNTI is available to the UE when start the RA but
// In this case we will let the procedure expire the Contention Resolution window and make sure
// and RRC HO fail signal is sent to RRC.
mac_log.info("\n=========== Test %d =============\n", test_id++);
phy.set_prach_tti(tti + phy.prach_delay);
phy.set_crnti(0);
mac.start_cont_ho();
mac.run_tti(tti++);
rrc.ho_finish = false;
my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number();
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
my_test.msg4_valid_conres = false;
my_test.assume_prach_transmitted = 0;
my_test.check_ra_successful = false;
my_test.send_valid_ul_grant = false;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
TESTASSERT(!rrc.ho_finish_successful && rrc.ho_finish);
// Test 8: Test Contention based Random Access. Same as above but we let the procedure finish successfully.
mac_log.info("\n=========== Test %d =============\n", test_id++);
phy.set_prach_tti(tti + phy.prach_delay);
phy.set_crnti(0);
mac.start_cont_ho();
mac.run_tti(tti++);
rrc.ho_finish = false;
my_test.nof_prachs = 1;
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
my_test.send_valid_ul_grant = true;
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
TESTASSERT(rrc.ho_finish_successful && rrc.ho_finish);
// Test 9: Test non-Contention based HO. Used in HO but preamble is given by the network. In addition to checking
// that the given preamble is correctly passed to the PHY, in this case there is no contention.
// In this first test, no RAR is received and RA procedure fails
mac_log.info("\n=========== Test %d =============\n", test_id++);
phy.set_prach_tti(tti + phy.prach_delay);
mac.run_tti(tti++);
phy.set_crnti(0);
rrc.ho_finish = false;
my_test.preamble_idx = 3;
mac.start_noncont_ho(my_test.preamble_idx, 0);
my_test.nof_prachs = rach_cfg.ra_supervision_info.preamb_trans_max.to_number();
my_test.rar_nof_invalid_rapid = rach_cfg.ra_supervision_info.ra_resp_win_size.to_number();
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
mac.run_tti(tti++);
TESTASSERT(!rrc.ho_finish_successful && rrc.ho_finish);
TESTASSERT(memcmp(ul_action.tb.payload, tv, sizeof(tv)) == 0); // Test 10: Test non-Contention based HO. Used in HO but preamble is given by the network. We check that
} // the procedure is considered successful without waiting for contention
mac_log.info("\n=========== Test %d =============\n", test_id++);
phy.set_prach_tti(tti + phy.prach_delay);
mac.run_tti(tti++);
phy.set_crnti(0);
rrc.ho_finish = false;
my_test.preamble_idx = 3;
mac.start_noncont_ho(my_test.preamble_idx, 0);
my_test.nof_prachs = 1;
my_test.rar_nof_invalid_rapid = 0;
my_test.check_ra_successful = true;
my_test.temp_rnti++; // Temporal C-RNTI has to change to avoid duplicate
TESTASSERT(!run_mac_ra_test(my_test, &mac, &phy, &tti));
mac.run_tti(tti++);
TESTASSERT(rrc.ho_finish_successful && rrc.ho_finish);
// make sure MAC PDU thread picks up before stopping
sleep(1);
mac.run_tti(0);
mac.stop(); mac.stop();
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -1010,7 +1498,7 @@ int main(int argc, char** argv)
return -1; return -1;
} }
if (mac_ul_sch_pdu_msg3_test()) { if (mac_random_access_test()) {
printf("mac_ul_sch_pdu_msg3_test() test failed.\n"); printf("mac_ul_sch_pdu_msg3_test() test failed.\n");
return -1; return -1;
} }

Loading…
Cancel
Save