diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index e64e204c6..3b9c25e28 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -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;iMAC 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;ilog_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; }; diff --git a/srsue/hdr/mac/mac_common.h b/srsue/hdr/mac/mac_common.h new file mode 100644 index 000000000..d40d179eb --- /dev/null +++ b/srsue/hdr/mac/mac_common.h @@ -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 diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index cea469e33..38046b099 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.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;iMAC 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; diff --git a/srsue/src/mac/dl_harq.cc b/srsue/src/mac/dl_harq.cc deleted file mode 100644 index 685224786..000000000 --- a/srsue/src/mac/dl_harq.cc +++ /dev/null @@ -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;iget(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(); - } -} - - - -} diff --git a/srsue/src/mac/ul_harq.cc b/srsue/src/mac/ul_harq.cc deleted file mode 100644 index da28d62b3..000000000 --- a/srsue/src/mac/ul_harq.cc +++ /dev/null @@ -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;ilog_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; -} - -}