make DL and UL harq header-only

- move src of DL and UL harq in to header in prep for templating both
- add commong MAC header
master
Andre Puschmann 8 years ago
parent bfa10148f5
commit faf120501a

@ -27,9 +27,15 @@
#ifndef DL_HARQ_H
#define DL_HARQ_H
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/common/log.h"
#include "srslte/common/timers.h"
#include "mac/demux.h"
#include "mac/mac_common.h"
#include "mac/dl_sps.h"
#include "srslte/common/mac_pcap.h"
@ -47,58 +53,294 @@ public:
const static uint32_t NOF_HARQ_PROC = 8;
const static uint32_t HARQ_BCCH_PID = NOF_HARQ_PROC;
dl_harq_entity();
bool init(srslte::log *log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg, srslte::timers *timers_, demux *demux_unit);
dl_harq_entity()
{
pcap = NULL;
}
bool init(srslte::log *log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers *timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
mac_cfg = mac_cfg_;
si_window_start = 0;
log_h = log_h_;
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
/***************** PHY->MAC interface for DL processes **************************/
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void reset();
void start_pcap(srslte::mac_pcap* pcap);
int get_current_tbs(uint32_t harq_pid);
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action)
{
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
// Set BCCH PID for SI RNTI
if (grant.rnti_type == SRSLTE_RNTI_SI) {
harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%NOF_HARQ_PROC;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%NOF_HARQ_PROC;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[NOF_HARQ_PROC].tb_decoded(ack);
} else {
proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack);
}
}
void reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
void start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; }
int get_current_tbs(uint32_t harq_pid) { return proc[harq_pid%NOF_HARQ_PROC].get_current_tbs(); }
void set_si_window_start(int si_window_start_) { si_window_start = si_window_start_; }
float get_average_retx() { return average_retx; }
void set_si_window_start(int si_window_start);
float get_average_retx();
private:
class dl_harq_process {
public:
dl_harq_process();
bool init(uint32_t pid, dl_harq_entity *parent);
void reset();
bool is_sps();
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action);
void tb_decoded(bool ack);
int get_current_tbs();
dl_harq_process()
{
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool init(uint32_t pid_, dl_harq_entity *parent)
{
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
void reset()
{
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
private:
bool calc_is_new_transmission(mac_interface_phy::mac_grant_t grant);
void new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t *action)
{
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t));
// Fill action structure
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
void tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
bool is_sps() { return false; }
int get_current_tbs() { return cur_grant.n_bytes*8; }
private:
bool calc_is_new_transmission(mac_interface_phy::mac_grant_t grant)
{
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
bool is_initiated;
dl_harq_entity *harq_entity;
srslte::log *log_h;
bool is_new_transmission;
bool is_new_transmission;
uint32_t pid;
uint8_t *payload_buffer_ptr;
bool ack;
uint32_t n_retx;
uint32_t n_retx;
mac_interface_phy::mac_grant_t cur_grant;
srslte_softbuffer_rx_t softbuffer;
};
static bool generate_ack_callback(void *arg);
// Private members of dl_harq_entity
static bool generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
uint32_t get_harq_sps_pid(uint32_t tti);
uint32_t get_harq_sps_pid(uint32_t tti) { return 0; }
dl_sps dl_sps_assig;
@ -109,9 +351,9 @@ private:
srslte::log *log_h;
srslte::mac_pcap *pcap;
uint16_t last_temporal_crnti;
int si_window_start;
int si_window_start;
float average_retx;
float average_retx;
uint64_t nof_pkts;
};

@ -0,0 +1,45 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef MAC_COMMON_H
#define MAC_COMMON_H
namespace srsue {
typedef enum {
HARQ_RTT,
TIME_ALIGNMENT,
CONTENTION_TIMER,
BSR_TIMER_PERIODIC,
BSR_TIMER_RETX,
PHR_TIMER_PERIODIC,
PHR_TIMER_PROHIBIT,
NOF_MAC_TIMERS
} mac_timers_t;
} // namespace srsue
#endif // MAC_COMMON_H

@ -27,24 +27,31 @@
#ifndef ULHARQ_H
#define ULHARQ_H
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/log.h"
#include "mac/mux.h"
#include "mac/mac_common.h"
#include "mac/ul_sps.h"
#include "srslte/common/mac_pcap.h"
#include "srslte/common/timers.h"
#include "srslte/common/interfaces_common.h"
/* Uplink HARQ entity as defined in 5.4.2 of 36.321 */
namespace srsue {
class ul_harq_entity
{
public:
const static uint32_t NOF_HARQ_PROC = 8;
static uint32_t pidof(uint32_t tti);
static uint32_t pidof(uint32_t tti)
{
return (uint32_t) tti%NOF_HARQ_PROC;
}
ul_harq_entity() {
pcap = NULL;
@ -56,46 +63,228 @@ public:
average_retx = 0;
nof_pkts = 0;
}
bool init(srslte::log *log_h,
mac_interface_rrc::ue_rnti_t *rntis,
mac_interface_rrc::mac_cfg_t *mac_cfg,
srslte::timers* timers_,
mux *mux_unit);
void reset();
void reset_ndi();
void start_pcap(srslte::mac_pcap* pcap);
bool init(srslte::log *log_h_,
mac_interface_rrc::ue_rnti_t *rntis_,
mac_interface_rrc::mac_cfg_t *mac_cfg_,
srslte::timers* timers_db_,
mux *mux_unit_)
{
log_h = log_h_;
mux_unit = mux_unit_;
mac_cfg = mac_cfg_;
rntis = rntis_;
timers_db = timers_db_;
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
}
void reset_ndi()
{
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset_ndi();
}
}
void start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
/***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action);
void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action);
void new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t *action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
void new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t *action)
{
set_ack(grant.tti, ack);
new_grant_ul(grant, action);
}
int get_current_tbs(uint32_t tti);
void harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t *action)
{
set_ack(tti, ack);
run_tti(tti, NULL, action);
}
int get_current_tbs(uint32_t tti)
{
int tti_harq = (int) tti-4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
return proc[pid_harq].get_current_tbs();
}
float get_average_retx();
float get_average_retx()
{
return average_retx;
}
private:
private:
class ul_harq_process {
public:
ul_harq_process();
bool init(uint32_t pid, ul_harq_entity *parent);
void reset();
void reset_ndi();
ul_harq_process()
{
current_tx_nb = 0;
current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool init(uint32_t pid_, ul_harq_entity *parent)
{
if (srslte_softbuffer_tx_init(&softbuffer, 110)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void reset()
{
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void reset_ndi() { ndi = false; }
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
void run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t max_retx;
if (is_msg3) {
max_retx = harq_entity->mac_cfg->rach.max_harq_msg3_tx;
} else {
max_retx = liblte_rrc_max_harq_tx_num[harq_entity->mac_cfg->main.ulsch_cnfg.max_harq_tx];
}
// Receive and route HARQ feedbacks
if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
uint32_t get_rv();
bool has_grant();
// Uplink grant in a RAR
if (grant->is_from_rar) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
void set_harq_feedback(bool ack);
bool get_ndi();
bool is_sps();
uint32_t last_tx_tti();
uint32_t get_nof_retx();
int get_current_tbs();
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, grant, action);
}
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, action);
}
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
void set_harq_feedback(bool ack)
{
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL %d: HARQ = NACK for UL transmission\n", pid);
}
}
uint32_t get_rv()
{
int rv_of_irv[4] = {0, 2, 3, 1};
return rv_of_irv[current_irv%4];
}
bool has_grant() { return is_grant_configured; }
bool get_ndi() { return ndi; }
bool is_sps() { return false; }
uint32_t last_tx_tti() { return tti_last_tx; }
uint32_t get_nof_retx() { return current_tx_nb; }
int get_current_tbs() { return cur_grant.n_bytes*8; }
private:
mac_interface_phy::mac_grant_t cur_grant;
@ -118,17 +307,99 @@ private:
uint8_t *payload_buffer;
uint8_t *pdu_ptr;
void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
void generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
generate_retx(tti_tx, NULL, action);
}
// Retransmission with or w/o grant (Section 5.4.2.2)
void generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_new_tx(uint32_t tti_tx, bool is_msg3, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action);
void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action);
mac_interface_phy::tb_action_ul_t *action)
{
int irv_of_rv[4] = {0, 3, 1, 2};
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
}
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(CONTENTION_TIMER)->reset();
}
harq_entity->mux_unit->pusch_retx(tti_tx, pid);
}
// New transmission (Section 5.4.2.2)
void generate_new_tx(uint32_t tti_tx, bool is_msg3_, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
action->current_tx_nb = current_tx_nb;
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
}
};
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action);
void set_ack(uint32_t tti, bool ack);
// Implements Section 5.4.2.1
// Called with UL grant
void run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t tti_tx = (tti+4)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
void set_ack(uint32_t tti, bool ack)
{
int tti_harq = (int) tti - 4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) {
proc[pid_harq].set_harq_feedback(ack);
}
}
ul_sps ul_sps_assig;

@ -1,337 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "mac/mac.h"
#include "mac/dl_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
dl_harq_entity::dl_harq_entity()
{
pcap = NULL;
}
bool dl_harq_entity::init(srslte::log* log_h_, mac_interface_rrc::mac_cfg_t *mac_cfg_, srslte::timers* timers_, demux *demux_unit_)
{
timers_db = timers_;
demux_unit = demux_unit_;
mac_cfg = mac_cfg_;
si_window_start = 0;
log_h = log_h_;
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
void dl_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void dl_harq_entity::reset()
{
for (uint32_t i=0;i<NOF_HARQ_PROC+1;i++) {
proc[i].reset();
}
dl_sps_assig.clear();
}
uint32_t dl_harq_entity::get_harq_sps_pid(uint32_t tti) {
return 0;
}
void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.rnti_type != SRSLTE_RNTI_SPS) {
uint32_t harq_pid;
// Set BCCH PID for SI RNTI
if (grant.rnti_type == SRSLTE_RNTI_SI) {
harq_pid = HARQ_BCCH_PID;
} else {
harq_pid = grant.pid%NOF_HARQ_PROC;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%NOF_HARQ_PROC;
if (grant.ndi) {
grant.ndi = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
dl_sps_assig.clear();
if (timers_db->get(mac::TIME_ALIGNMENT)->is_running()) {
//phy_h->send_sps_ack();
Warning("PHY Send SPS ACK not implemented\n");
}
} else {
Error("SPS not implemented\n");
//dl_sps_assig.reset(grant.tti, grant);
//grant.ndi = true;
//procs[harq_pid].save_grant();
}
}
}
}
void dl_harq_entity::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[NOF_HARQ_PROC].tb_decoded(ack);
} else {
proc[harq_pid%NOF_HARQ_PROC].tb_decoded(ack);
}
}
int dl_harq_entity::get_current_tbs(uint32_t harq_pid)
{
return proc[harq_pid%NOF_HARQ_PROC].get_current_tbs();
}
bool dl_harq_entity::generate_ack_callback(void *arg)
{
demux *demux_unit = (demux*) arg;
return demux_unit->get_uecrid_successful();
}
void dl_harq_entity::set_si_window_start(int si_window_start_)
{
si_window_start = si_window_start_;
}
float dl_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
dl_harq_entity::dl_harq_process::dl_harq_process() {
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void dl_harq_entity::dl_harq_process::reset() {
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
bool dl_harq_entity::dl_harq_process::init(uint32_t pid_, dl_harq_entity *parent) {
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
bool dl_harq_entity::dl_harq_process::is_sps()
{
return false;
}
bool dl_harq_entity::dl_harq_process::calc_is_new_transmission(mac_interface_phy::mac_grant_t grant) {
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(mac_interface_phy::mac_grant_t));
// Fill action structure
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(mac::TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
}
int dl_harq_entity::dl_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void dl_harq_entity::dl_harq_process::tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
}

@ -1,394 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsUE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#define Error(fmt, ...) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Info(fmt, ...) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#include "srslte/common/log.h"
#include "mac/mac.h"
#include "mac/ul_harq.h"
namespace srsue {
/***********************************************************
*
* HARQ ENTITY
*
*********************************************************/
bool ul_harq_entity::init(srslte::log *log_h_,
mac_interface_rrc::ue_rnti_t *rntis_,
mac_interface_rrc::mac_cfg_t *mac_cfg_,
srslte::timers *timers_db_,
mux *mux_unit_) {
log_h = log_h_;
mux_unit = mux_unit_;
mac_cfg = mac_cfg_;
rntis = rntis_;
timers_db = timers_db_;
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
if (!proc[i].init(i, this)) {
return false;
}
}
return true;
}
uint32_t ul_harq_entity::pidof(uint32_t tti) {
return (uint32_t) tti%NOF_HARQ_PROC;
}
void ul_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
{
pcap = pcap_;
}
void ul_harq_entity::reset() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset();
}
ul_sps_assig.clear();
}
void ul_harq_entity::reset_ndi() {
for (uint32_t i=0;i<NOF_HARQ_PROC;i++) {
proc[i].reset_ndi();
}
}
int ul_harq_entity::get_current_tbs(uint32_t tti) {
int tti_harq = (int) tti-4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
return proc[pid_harq].get_current_tbs();
}
void ul_harq_entity::set_ack(uint32_t tti, bool ack) {
int tti_harq = (int) tti - 4;
if (tti_harq < 0) {
tti_harq += 10240;
}
uint32_t pid_harq = pidof(tti_harq);
if (proc[pid_harq].has_grant() && (proc[pid_harq].last_tx_tti() <= (uint32_t)tti_harq)) {
proc[pid_harq].set_harq_feedback(ack);
}
}
void ul_harq_entity::harq_recv(uint32_t tti, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(tti, ack);
run_tti(tti, NULL, action);
}
// Implements Section 5.4.1
void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_ul_t* action)
{
if (grant.rnti_type == SRSLTE_RNTI_USER ||
grant.rnti_type == SRSLTE_RNTI_TEMP ||
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
}
}
}
void ul_harq_entity::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action)
{
set_ack(grant.tti, ack);
new_grant_ul(grant, action);
}
// Implements Section 5.4.2.1
// Called with UL grant
void ul_harq_entity::run_tti(uint32_t tti, mac_interface_phy::mac_grant_t *grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t tti_tx = (tti+4)%10240;
proc[pidof(tti_tx)].run_tti(tti_tx, grant, action);
}
float ul_harq_entity::get_average_retx()
{
return average_retx;
}
/***********************************************************
*
* HARQ PROCESS
*
*********************************************************/
static int rv_of_irv[4] = {0, 2, 3, 1};
static int irv_of_rv[4] = {0, 3, 1, 2};
ul_harq_entity::ul_harq_process::ul_harq_process() {
current_tx_nb = 0;
current_irv = 0;
is_initiated = false;
is_grant_configured = false;
tti_last_tx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
void ul_harq_entity::ul_harq_process::reset() {
current_tx_nb = 0;
current_irv = 0;
tti_last_tx = 0;
is_grant_configured = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_t));
}
bool ul_harq_entity::ul_harq_process::has_grant() {
return is_grant_configured;
}
void ul_harq_entity::ul_harq_process::reset_ndi() {
ndi = false;
}
bool ul_harq_entity::ul_harq_process::get_ndi()
{
return ndi;
}
uint32_t ul_harq_entity::ul_harq_process::get_rv()
{
return rv_of_irv[current_irv%4];
}
void ul_harq_entity::ul_harq_process::set_harq_feedback(bool ack) {
harq_feedback = ack;
// UL packet successfully delivered
if (ack) {
Info("UL %d: HARQ = ACK for UL transmission. Discarting TB.\n", pid);
reset();
} else {
Info("UL %d: HARQ = NACK for UL transmission\n", pid);
}
}
bool ul_harq_entity::ul_harq_process::init(uint32_t pid_, ul_harq_entity* parent) {
if (srslte_softbuffer_tx_init(&softbuffer, 110)) {
fprintf(stderr, "Error initiating soft buffer\n");
return false;
} else {
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
pid = pid_;
payload_buffer = (uint8_t*) srslte_vec_malloc(payload_buffer_len*sizeof(uint8_t));
if (!payload_buffer) {
Error("Allocating memory\n");
return false;
}
pdu_ptr = payload_buffer;
return true;
}
}
void ul_harq_entity::ul_harq_process::run_tti(uint32_t tti_tx, mac_interface_phy::mac_grant_t* grant, mac_interface_phy::tb_action_ul_t* action)
{
uint32_t max_retx;
if (is_msg3) {
max_retx = harq_entity->mac_cfg->rach.max_harq_msg3_tx;
} else {
max_retx = liblte_rrc_max_harq_tx_num[harq_entity->mac_cfg->main.ulsch_cnfg.max_harq_tx];
}
// Receive and route HARQ feedbacks
if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
// New transmission
// Uplink grant in a RAR
if (grant->is_from_rar) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
Warning("UL RAR grant available but no Msg3 on buffer\n");
}
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
Warning("Uplink grant but no MAC PDU in Multiplex Unit buffer\n");
}
}
} else {
// Adaptive Re-TX
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, grant, action);
}
}
} else if (has_grant()) {
// Non-Adaptive Re-Tx
if (current_tx_nb >= max_retx) {
Info("UL %d: Maximum number of ReTX reached (%d). Discarting TB.\n", pid, max_retx);
reset();
action->expect_ack = false;
} else {
generate_retx(tti_tx, action);
}
}
if (harq_entity->pcap && grant) {
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
}
}
int ul_harq_entity::ul_harq_process::get_current_tbs()
{
return cur_grant.n_bytes*8;
}
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
generate_retx(tti_tx, NULL, action);
}
// Retransmission with or w/o grant (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_retx(uint32_t tti_tx, mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
}
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
}
}
// On every Msg3 retransmission, restart mac-ContentionResolutionTimer as defined in Section 5.1.5
if (is_msg3) {
harq_entity->timers_db->get(mac::CONTENTION_TIMER)->reset();
}
harq_entity->mux_unit->pusch_retx(tti_tx, pid);
}
// New transmission (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_new_tx(uint32_t tti_tx, bool is_msg3_,
mac_interface_phy::mac_grant_t *grant,
mac_interface_phy::tb_action_ul_t *action)
{
if (grant) {
// Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
memcpy(&cur_grant, grant, sizeof(mac_interface_phy::mac_grant_t));
harq_feedback = false;
is_grant_configured = true;
current_tx_nb = 0;
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
// Transmission of pending frame (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_tx(uint32_t tti_tx, mac_interface_phy::tb_action_ul_t *action)
{
action->current_tx_nb = current_tx_nb;
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(srslte_phy_grant_t));
current_irv = (current_irv+1)%4;
tti_last_tx = tti_tx;
}
bool ul_harq_entity::ul_harq_process::is_sps()
{
return false;
}
uint32_t ul_harq_entity::ul_harq_process::last_tx_tti()
{
return tti_last_tx;
}
uint32_t ul_harq_entity::ul_harq_process::get_nof_retx()
{
return current_tx_nb;
}
}
Loading…
Cancel
Save