mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
408 lines
12 KiB
C++
408 lines
12 KiB
C++
6 years ago
|
/*
|
||
|
* Copyright 2013-2019 Software Radio Systems Limited
|
||
|
*
|
||
|
* This file is part of srsLTE.
|
||
|
*
|
||
|
* srsLTE 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.
|
||
|
*
|
||
|
* srsLTE 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(fmt, ##__VA_ARGS__)
|
||
|
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)
|
||
|
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
|
||
|
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
|
||
|
|
||
6 years ago
|
#include "srsue/hdr/stack/mac/dl_harq.h"
|
||
6 years ago
|
#include "srslte/common/log.h"
|
||
|
#include "srslte/common/mac_pcap.h"
|
||
|
#include "srslte/common/timers.h"
|
||
|
#include "srslte/interfaces/ue_interfaces.h"
|
||
|
|
||
|
namespace srsue {
|
||
|
|
||
|
dl_harq_entity::dl_harq_entity() : proc(SRSLTE_MAX_HARQ_PROC)
|
||
|
{
|
||
|
pcap = NULL;
|
||
|
demux_unit = NULL;
|
||
|
log_h = NULL;
|
||
|
timer_aligment_timer = NULL;
|
||
|
si_window_start = 0;
|
||
|
last_temporal_crnti = 0;
|
||
|
average_retx = 0;
|
||
6 years ago
|
nof_pkts = 0;
|
||
6 years ago
|
}
|
||
|
|
||
|
bool dl_harq_entity::init(srslte::log* log_h,
|
||
|
mac_interface_rrc::ue_rnti_t* rntis,
|
||
|
srslte::timers::timer* timer_aligment_timer,
|
||
|
demux* demux_unit)
|
||
|
{
|
||
|
this->timer_aligment_timer = timer_aligment_timer;
|
||
|
this->demux_unit = demux_unit;
|
||
|
this->log_h = log_h;
|
||
|
this->rntis = rntis;
|
||
|
|
||
|
for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) {
|
||
|
if (!proc[i].init(i, this)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
bcch_proc.init(-1, this);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/***************** PHY->MAC interface for DL processes **************************/
|
||
6 years ago
|
void dl_harq_entity::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
|
||
|
mac_interface_phy_lte::tb_action_dl_t* action)
|
||
6 years ago
|
{
|
||
6 years ago
|
bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
|
||
6 years ago
|
|
||
|
if (grant.rnti != rntis->sps_rnti) {
|
||
|
// Set BCCH PID for SI RNTI
|
||
|
dl_harq_process* proc_ptr = NULL;
|
||
|
if (grant.rnti == SRSLTE_SIRNTI) {
|
||
|
proc_ptr = &bcch_proc;
|
||
|
} else {
|
||
|
if (grant.pid >= SRSLTE_MAX_HARQ_PROC) {
|
||
|
Error("Invalid PID: %d\n", grant.pid);
|
||
|
return;
|
||
|
}
|
||
|
proc_ptr = &proc[grant.pid];
|
||
|
}
|
||
|
if (grant.rnti == rntis->temp_rnti && last_temporal_crnti != rntis->temp_rnti) {
|
||
|
grant.tb[0].ndi = true;
|
||
|
last_temporal_crnti = rntis->temp_rnti;
|
||
|
Info("Set NDI=1 for Temp-RNTI DL dci\n");
|
||
|
}
|
||
|
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);
|
||
|
} else {
|
||
|
Error("SPS not supported\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
void dl_harq_entity::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS])
|
||
6 years ago
|
{
|
||
|
if (grant.rnti == SRSLTE_SIRNTI) {
|
||
|
bcch_proc.tb_decoded(grant, ack);
|
||
|
} else {
|
||
|
if (grant.pid >= SRSLTE_MAX_HARQ_PROC) {
|
||
|
Error("Invalid PID: %d\n", grant.pid);
|
||
|
return;
|
||
|
}
|
||
|
proc[grant.pid].tb_decoded(grant, ack);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void dl_harq_entity::reset()
|
||
|
{
|
||
|
for (uint32_t i = 0; i < SRSLTE_MAX_HARQ_PROC; i++) {
|
||
|
proc[i].reset();
|
||
|
}
|
||
|
bcch_proc.reset();
|
||
|
dl_sps_assig.clear();
|
||
|
}
|
||
|
|
||
|
void dl_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
|
||
|
{
|
||
|
pcap = pcap_;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
dl_harq_entity::dl_harq_process::dl_harq_process() : subproc(SRSLTE_MAX_TB) {}
|
||
|
|
||
|
bool dl_harq_entity::dl_harq_process::init(int pid, dl_harq_entity* parent)
|
||
|
{
|
||
|
bool ret = true;
|
||
|
|
||
|
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||
|
ret &= subproc[tb].init(pid, parent, tb);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void dl_harq_entity::dl_harq_process::reset(void)
|
||
|
{
|
||
|
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
|
||
|
subproc[tb].reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
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)
|
||
6 years ago
|
{
|
||
6 years ago
|
bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
|
||
6 years ago
|
/* For each subprocess... */
|
||
|
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
|
||
|
if (grant.tb[i].tbs) {
|
||
|
subproc[i].new_grant_dl(grant, action);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
void dl_harq_entity::dl_harq_process::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant,
|
||
|
bool ack[SRSLTE_MAX_CODEWORDS])
|
||
6 years ago
|
{
|
||
|
/* For each subprocess... */
|
||
|
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
|
||
|
subproc[i].tb_decoded(grant, &ack[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool dl_harq_entity::dl_harq_process::is_sps()
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
dl_harq_entity::dl_harq_process::dl_tb_process::dl_tb_process()
|
||
|
{
|
||
|
is_initiated = false;
|
||
|
ack = false;
|
||
6 years ago
|
n_retx = 0;
|
||
6 years ago
|
bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_dl_t));
|
||
6 years ago
|
payload_buffer_ptr = NULL;
|
||
|
pthread_mutex_init(&mutex, NULL);
|
||
|
}
|
||
|
|
||
|
dl_harq_entity::dl_harq_process::dl_tb_process::~dl_tb_process()
|
||
|
{
|
||
|
if (is_initiated) {
|
||
|
srslte_softbuffer_rx_free(&softbuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool dl_harq_entity::dl_harq_process::dl_tb_process::init(int pid, dl_harq_entity* parent, uint32_t tb_idx)
|
||
|
{
|
||
|
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
|
||
|
Error("Error initiating soft buffer\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (pid < 0) {
|
||
|
is_bcch = true;
|
||
|
this->pid = 0;
|
||
|
} else {
|
||
|
this->pid = (uint32_t)pid;
|
||
|
is_bcch = false;
|
||
|
}
|
||
|
|
||
|
tid = tb_idx;
|
||
|
is_first_tb = true;
|
||
|
is_initiated = true;
|
||
|
harq_entity = parent;
|
||
|
log_h = harq_entity->log_h;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock)
|
||
|
{
|
||
|
if (lock) {
|
||
|
pthread_mutex_lock(&mutex);
|
||
|
}
|
||
|
|
||
6 years ago
|
bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_dl_t));
|
||
6 years ago
|
is_first_tb = true;
|
||
|
ack = false;
|
||
|
n_retx = 0;
|
||
|
|
||
|
if (payload_buffer_ptr) {
|
||
|
if (!is_bcch) {
|
||
|
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
|
||
|
}
|
||
|
payload_buffer_ptr = NULL;
|
||
|
}
|
||
|
|
||
|
if (is_initiated && lock) {
|
||
|
srslte_softbuffer_rx_reset(&softbuffer);
|
||
|
}
|
||
|
|
||
|
if (lock) {
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
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)
|
||
6 years ago
|
{
|
||
|
|
||
|
pthread_mutex_lock(&mutex);
|
||
|
|
||
|
// Compute RV for BCCH when not specified in PDCCH format
|
||
|
if (is_bcch && grant.tb[tid].rv == -1) {
|
||
|
uint32_t k;
|
||
|
if ((grant.pid / 10) % 2 == 0 && grant.pid % 10 == 5) { // This is SIB1, k is different
|
||
|
k = (grant.pid / 20) % 4;
|
||
|
grant.tb[tid].rv = ((uint32_t)ceilf((float)1.5 * k)) % 4;
|
||
|
} else {
|
||
|
k = (grant.pid - harq_entity->si_window_start) % 4;
|
||
|
grant.tb[tid].rv = ((uint32_t)ceilf((float)1.5 * k)) % 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
calc_is_new_transmission(grant);
|
||
|
|
||
|
// If this is a new transmission or the size of the TB has changed
|
||
|
if (is_new_transmission || (cur_grant.tb[tid].tbs != grant.tb[tid].tbs)) {
|
||
|
if (!is_new_transmission) {
|
||
|
Warning("DL PID %d: Size of dci changed during a retransmission %d!=%d\n",
|
||
|
pid,
|
||
|
cur_grant.tb[tid].tbs,
|
||
|
grant.tb[tid].tbs);
|
||
|
}
|
||
|
ack = false;
|
||
|
n_retx = 0;
|
||
|
srslte_softbuffer_rx_reset_tbs(&softbuffer, grant.tb[tid].tbs * 8);
|
||
|
}
|
||
|
|
||
|
n_retx++;
|
||
|
|
||
|
// If data has not yet been successfully decoded
|
||
|
if (!ack) {
|
||
|
|
||
|
// Save dci
|
||
|
cur_grant = grant;
|
||
|
|
||
|
if (payload_buffer_ptr) {
|
||
|
Warning("DL PID %d: Allocating buffer already allocated. Deallocating.\n", pid);
|
||
|
if (!is_bcch) {
|
||
|
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Instruct the PHY To combine the received data and attempt to decode it
|
||
|
if (is_bcch) {
|
||
|
payload_buffer_ptr = harq_entity->demux_unit->request_buffer_bcch(cur_grant.tb[tid].tbs);
|
||
|
} else {
|
||
|
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(cur_grant.tb[tid].tbs);
|
||
|
}
|
||
|
|
||
|
action->tb[tid].payload = payload_buffer_ptr;
|
||
|
if (!action->tb[tid].payload) {
|
||
|
Error("Can't get a buffer for TBS=%d\n", cur_grant.tb[tid].tbs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
action->tb[tid].enabled = true;
|
||
|
action->tb[tid].rv = cur_grant.tb[tid].rv;
|
||
|
action->tb[tid].softbuffer.rx = &softbuffer;
|
||
|
} else {
|
||
|
Warning("DL PID %d: Received duplicate TB%d. Discarting and retransmitting ACK (n_retx=%d, reset=%s)\n",
|
||
|
pid,
|
||
|
tid,
|
||
|
n_retx,
|
||
|
n_retx > RESET_DUPLICATE_TIMEOUT ? "yes" : "no");
|
||
|
if (n_retx > RESET_DUPLICATE_TIMEOUT) {
|
||
|
reset(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (is_bcch || harq_entity->timer_aligment_timer->is_expired()) {
|
||
|
// Do not generate ACK
|
||
|
action->generate_ack = false;
|
||
|
} else {
|
||
|
action->generate_ack = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant,
|
||
|
bool* ack_ptr)
|
||
6 years ago
|
{
|
||
|
if (payload_buffer_ptr) {
|
||
|
this->ack = *ack_ptr;
|
||
|
if (ack) {
|
||
|
if (is_bcch) {
|
||
|
if (harq_entity->pcap) {
|
||
|
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.tb[tid].tbs, ack, 0);
|
||
|
}
|
||
|
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.tb[tid].tbs);
|
||
|
harq_entity->demux_unit->push_pdu_bcch(payload_buffer_ptr, cur_grant.tb[tid].tbs);
|
||
|
} else {
|
||
|
if (harq_entity->pcap) {
|
||
|
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.tb[tid].tbs, cur_grant.rnti, ack, 0);
|
||
|
}
|
||
|
if (cur_grant.rnti == harq_entity->rntis->temp_rnti) {
|
||
|
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.tb[tid].tbs);
|
||
|
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.tb[tid].tbs);
|
||
|
|
||
|
// If T-CRNTI, update ack value with result from contention resolution
|
||
|
*ack_ptr = harq_entity->demux_unit->get_uecrid_successful();
|
||
|
|
||
|
} else {
|
||
|
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.tb[tid].tbs);
|
||
|
harq_entity->demux_unit->push_pdu(payload_buffer_ptr, cur_grant.tb[tid].tbs);
|
||
|
|
||
|
// 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 if (!is_bcch) {
|
||
|
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
|
||
|
}
|
||
|
|
||
|
payload_buffer_ptr = NULL;
|
||
|
|
||
|
Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d\n",
|
||
|
pid,
|
||
|
tid,
|
||
|
is_new_transmission ? "newTX" : "reTX ",
|
||
|
cur_grant.tb[tid].tbs,
|
||
|
cur_grant.tb[tid].rv,
|
||
|
ack ? "OK" : "KO",
|
||
|
cur_grant.tb[tid].ndi);
|
||
|
}
|
||
|
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
|
||
|
if (ack && is_bcch) {
|
||
|
reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Determine if it's a new transmission 5.3.2.2
|
||
6 years ago
|
bool dl_harq_entity::dl_harq_process::dl_tb_process::calc_is_new_transmission(
|
||
|
mac_interface_phy_lte::mac_grant_dl_t grant)
|
||
6 years ago
|
{
|
||
|
|
||
|
if (((grant.tb[tid].ndi_present &&
|
||
|
grant.tb[tid].ndi != cur_grant.tb[tid].ndi) || // 1st condition (NDI provided and has changed)
|
||
|
(is_bcch && grant.tb[tid].rv == 0) || // 2nd condition (Broadcast and 1st transmission)
|
||
|
is_first_tb)) // 3rd condition (is first tx for this tb)
|
||
|
{
|
||
|
is_first_tb = false;
|
||
|
is_new_transmission = true;
|
||
|
} else {
|
||
|
is_new_transmission = false;
|
||
|
}
|
||
|
|
||
|
Debug("Set HARQ for %stransmission\n", is_new_transmission ? "new " : "re");
|
||
|
|
||
|
return is_new_transmission;
|
||
|
}
|
||
|
|
||
|
} // namespace srsue
|