|
|
|
@ -26,6 +26,8 @@
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <boost/concept_check.hpp>
|
|
|
|
|
#include <srslte/interfaces/sched_interface.h>
|
|
|
|
|
#include <srslte/phy/phch/pucch.h>
|
|
|
|
|
|
|
|
|
|
#include "srslte/srslte.h"
|
|
|
|
|
#include "srslte/common/pdu.h"
|
|
|
|
@ -163,12 +165,17 @@ void sched_ue::phy_config_enabled(uint32_t tti, bool enabled)
|
|
|
|
|
phy_config_dedicated_enabled = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sched_ue::ul_buffer_state(uint8_t lc_id, uint32_t bsr)
|
|
|
|
|
void sched_ue::ul_buffer_state(uint8_t lc_id, uint32_t bsr, bool set_value)
|
|
|
|
|
{
|
|
|
|
|
if (lc_id < sched_interface::MAX_LC) {
|
|
|
|
|
lch[lc_id].bsr = bsr;
|
|
|
|
|
Debug("SCHED: UL lcid=%d buffer_state=%d\n", lc_id, bsr);
|
|
|
|
|
}
|
|
|
|
|
if (set_value) {
|
|
|
|
|
lch[lc_id].bsr = bsr;
|
|
|
|
|
} else {
|
|
|
|
|
lch[lc_id].bsr += bsr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Debug("SCHED: bsr=%d, lcid=%d, bsr={%d,%d,%d,%d}\n", bsr, lc_id,
|
|
|
|
|
lch[0].bsr, lch[1].bsr, lch[2].bsr, lch[3].bsr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sched_ue::ul_phr(int phr)
|
|
|
|
@ -230,7 +237,8 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
|
|
|
|
|
if (!phy_config_dedicated_enabled) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
srslte_pucch_sched_t pucch_sched;
|
|
|
|
|
srslte_pucch_sched_t pucch_sched;
|
|
|
|
|
pucch_sched.sps_enabled = false;
|
|
|
|
|
pucch_sched.n_pucch_sr = cfg.sr_N_pucch;
|
|
|
|
|
pucch_sched.n_pucch_2 = cfg.n_pucch_cqi;
|
|
|
|
|
pucch_sched.N_pucch_1 = cfg.pucch_cfg.n1_pucch_an;
|
|
|
|
@ -239,7 +247,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
|
|
|
|
|
|
|
|
|
|
// First check if it has pending ACKs
|
|
|
|
|
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
|
|
|
|
|
if (((dl_harq[i].get_tti()+8)%10240) == current_tti) {
|
|
|
|
|
if (((dl_harq[i].get_tti()+4)%10240) == current_tti) {
|
|
|
|
|
uint32_t n_pucch = srslte_pucch_get_npucch(dl_harq[i].get_n_cce(), SRSLTE_PUCCH_FORMAT_1A, has_sr, &pucch_sched);
|
|
|
|
|
if (prb_idx) {
|
|
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
@ -249,7 +257,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
|
|
|
|
|
if (L) {
|
|
|
|
|
*L = 1;
|
|
|
|
|
}
|
|
|
|
|
Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch);
|
|
|
|
|
Info("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -263,9 +271,24 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
|
|
|
|
|
if (L) {
|
|
|
|
|
*L = 1;
|
|
|
|
|
}
|
|
|
|
|
Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch);
|
|
|
|
|
Info("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Finally check Format2 (periodic CQI)
|
|
|
|
|
if (cfg.cqi_enabled && srslte_cqi_send(cfg.cqi_idx, current_tti)) {
|
|
|
|
|
if (prb_idx) {
|
|
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
|
prb_idx[i] = srslte_pucch_n_prb(&cfg.pucch_cfg, SRSLTE_PUCCH_FORMAT_2, cfg.cqi_pucch, cell.nof_prb, cell.cp, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(L) {
|
|
|
|
|
*L = 2;
|
|
|
|
|
}
|
|
|
|
|
Info("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n",
|
|
|
|
|
rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -297,6 +320,8 @@ void sched_ue::ul_recv_len(uint32_t lcid, uint32_t len)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Debug("SCHED: recv_len=%d, lcid=%d, bsr={%d,%d,%d,%d}\n", len, lcid,
|
|
|
|
|
lch[0].bsr, lch[1].bsr, lch[2].bsr, lch[3].bsr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sched_ue::set_ul_crc(uint32_t tti, bool crc_res)
|
|
|
|
@ -370,7 +395,7 @@ int sched_ue::generate_format1(dl_harq_proc *h,
|
|
|
|
|
uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0);
|
|
|
|
|
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols);
|
|
|
|
|
if (fixed_mcs_dl < 0) {
|
|
|
|
|
tbs = alloc_tbs(dl_cqi, nof_prb, nof_re, req_bytes, max_mcs_dl, &mcs);
|
|
|
|
|
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
|
|
|
|
|
} else {
|
|
|
|
|
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb);
|
|
|
|
|
mcs = fixed_mcs_dl;
|
|
|
|
@ -441,7 +466,7 @@ int sched_ue::generate_format0(ul_harq_proc *h,
|
|
|
|
|
uint32_t N_srs = 0;
|
|
|
|
|
uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*allocation.L*SRSLTE_NRE;
|
|
|
|
|
if (fixed_mcs_ul < 0) {
|
|
|
|
|
tbs = alloc_tbs(ul_cqi, allocation.L, nof_re, req_bytes, max_mcs_ul, &mcs);
|
|
|
|
|
tbs = alloc_tbs_ul(allocation.L, nof_re, req_bytes, &mcs);
|
|
|
|
|
} else {
|
|
|
|
|
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), allocation.L);
|
|
|
|
|
mcs = fixed_mcs_ul;
|
|
|
|
@ -554,6 +579,10 @@ uint32_t sched_ue::get_pending_ul_new_data(uint32_t tti)
|
|
|
|
|
} else {
|
|
|
|
|
pending_data = 0;
|
|
|
|
|
}
|
|
|
|
|
if (pending_data) {
|
|
|
|
|
Debug("SCHED: pending_data=%d, pending_ul_data=%d, bsr={%d,%d,%d,%d}\n", pending_data,pending_ul_data,
|
|
|
|
|
lch[0].bsr, lch[1].bsr, lch[2].bsr, lch[3].bsr);
|
|
|
|
|
}
|
|
|
|
|
return pending_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -581,7 +610,7 @@ uint32_t sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_sym
|
|
|
|
|
for (n=1;n<cell.nof_prb && nbytes < req_bytes;n++) {
|
|
|
|
|
nof_re = srslte_ra_dl_approx_nof_re(cell, n, nof_ctrl_symbols);
|
|
|
|
|
if (fixed_mcs_dl < 0) {
|
|
|
|
|
tbs = alloc_tbs(dl_cqi, n, nof_re, 0, max_mcs_dl, &mcs);
|
|
|
|
|
tbs = alloc_tbs_dl(n, nof_re, 0, &mcs);
|
|
|
|
|
} else {
|
|
|
|
|
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), n);
|
|
|
|
|
}
|
|
|
|
@ -610,7 +639,7 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes)
|
|
|
|
|
uint32_t nof_re = (2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs)*n*SRSLTE_NRE;
|
|
|
|
|
int tbs = 0;
|
|
|
|
|
if (fixed_mcs_ul < 0) {
|
|
|
|
|
tbs = alloc_tbs(ul_cqi, n, nof_re, 0, max_mcs_ul, &mcs);
|
|
|
|
|
tbs = alloc_tbs_ul(n, nof_re, 0, &mcs);
|
|
|
|
|
} else {
|
|
|
|
|
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_ul), n);
|
|
|
|
|
}
|
|
|
|
@ -731,36 +760,60 @@ uint32_t sched_ue::format1_count_prb(uint32_t bitmask, uint32_t cell_nof_prb) {
|
|
|
|
|
return nof_prb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sched_ue::cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t *mcs) {
|
|
|
|
|
int sched_ue::cqi_to_tbs(uint32_t cqi, uint32_t nof_prb, uint32_t nof_re, uint32_t max_mcs, uint32_t max_Qm, uint32_t *mcs) {
|
|
|
|
|
float max_coderate = srslte_cqi_to_coderate(cqi);
|
|
|
|
|
int sel_mcs = max_mcs+1;
|
|
|
|
|
float coderate = 99;
|
|
|
|
|
float coderate = 99;
|
|
|
|
|
float eff_coderate = 99;
|
|
|
|
|
uint32_t Qm = 1;
|
|
|
|
|
int tbs = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
sel_mcs--;
|
|
|
|
|
uint32_t tbs_idx = srslte_ra_tbs_idx_from_mcs(sel_mcs);
|
|
|
|
|
tbs = srslte_ra_tbs_from_idx(tbs_idx, nof_prb);
|
|
|
|
|
coderate = srslte_pdsch_coderate(tbs, nof_re);
|
|
|
|
|
} while(sel_mcs > 0 && coderate >= max_coderate);
|
|
|
|
|
coderate = srslte_coderate(tbs, nof_re);
|
|
|
|
|
Qm = SRSLTE_MIN(max_Qm, srslte_mod_bits_x_symbol(srslte_ra_mod_from_mcs(sel_mcs)));
|
|
|
|
|
eff_coderate = coderate/Qm;
|
|
|
|
|
} while((sel_mcs > 0 && coderate > max_coderate) || eff_coderate > 0.930);
|
|
|
|
|
if (mcs) {
|
|
|
|
|
*mcs = (uint32_t) sel_mcs;
|
|
|
|
|
}
|
|
|
|
|
return tbs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In this scheduler we tend to use all the available bandwidth and select the MCS
|
|
|
|
|
int sched_ue::alloc_tbs_dl(uint32_t nof_prb,
|
|
|
|
|
uint32_t nof_re,
|
|
|
|
|
uint32_t req_bytes,
|
|
|
|
|
int *mcs)
|
|
|
|
|
{
|
|
|
|
|
return alloc_tbs(nof_prb, nof_re, req_bytes, false, mcs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sched_ue::alloc_tbs_ul(uint32_t nof_prb,
|
|
|
|
|
uint32_t nof_re,
|
|
|
|
|
uint32_t req_bytes,
|
|
|
|
|
int *mcs)
|
|
|
|
|
{
|
|
|
|
|
return alloc_tbs(nof_prb, nof_re, req_bytes, true, mcs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In this scheduler we tend to use all the available bandwidth and select the MCS
|
|
|
|
|
* that approximates the minimum between the capacity and the requested rate
|
|
|
|
|
*/
|
|
|
|
|
int sched_ue::alloc_tbs(uint32_t cqi,
|
|
|
|
|
uint32_t nof_prb,
|
|
|
|
|
uint32_t nof_re,
|
|
|
|
|
uint32_t req_bytes,
|
|
|
|
|
uint32_t max_mcs,
|
|
|
|
|
int *mcs)
|
|
|
|
|
{
|
|
|
|
|
uint32_t sel_mcs = 0;
|
|
|
|
|
int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, &sel_mcs)/8;
|
|
|
|
|
int sched_ue::alloc_tbs(uint32_t nof_prb,
|
|
|
|
|
uint32_t nof_re,
|
|
|
|
|
uint32_t req_bytes,
|
|
|
|
|
bool is_ul,
|
|
|
|
|
int *mcs)
|
|
|
|
|
{
|
|
|
|
|
uint32_t sel_mcs = 0;
|
|
|
|
|
|
|
|
|
|
uint32_t cqi = is_ul?ul_cqi:dl_cqi;
|
|
|
|
|
uint32_t max_mcs = is_ul?max_mcs_ul:max_mcs_dl;
|
|
|
|
|
uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only
|
|
|
|
|
|
|
|
|
|
int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8;
|
|
|
|
|
|
|
|
|
|
/* If less bytes are requested, lower the MCS */
|
|
|
|
|
if (tbs > (int) req_bytes && req_bytes > 0) {
|
|
|
|
|