diff --git a/src/bts.h b/src/bts.h index 8233b637..0c5b47a0 100644 --- a/src/bts.h +++ b/src/bts.h @@ -148,6 +148,7 @@ struct gprs_rlcmac_bts { uint8_t cs_adj_enabled; uint8_t cs_adj_upper_limit; uint8_t cs_adj_lower_limit; + struct {int16_t low; int16_t high;} cs_lqual_ranges[4]; /* TBF handling, make private or move into TBFController */ /* list of uplink TBFs */ diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp index 189e4bd2..cc211713 100644 --- a/src/gprs_ms.cpp +++ b/src/gprs_ms.cpp @@ -367,7 +367,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate) { struct gprs_rlcmac_bts *bts_data; int64_t now; - uint8_t max_cs_ul = 4, max_cs_dl = 4; + uint8_t max_cs_dl = 4; OSMO_ASSERT(m_bts != NULL); bts_data = m_bts->bts_data(); @@ -377,18 +377,15 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate) now = now_msec(); - if (bts_data->max_cs_ul) - max_cs_ul = bts_data->max_cs_ul; - if (bts_data->max_cs_dl) max_cs_dl = bts_data->max_cs_dl; + /* TODO: Check for TBF direction */ /* TODO: Support different CS values for UL and DL */ if (error_rate > bts_data->cs_adj_upper_limit) { if (m_current_cs_dl > 1) { m_current_cs_dl -= 1; - m_current_cs_ul = m_current_cs_dl; LOGP(DRLCMACDL, LOGL_INFO, "MS (IMSI %s): High error rate %d%%, " "reducing CS level to %d\n", @@ -399,12 +396,10 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate) if (m_current_cs_dl < max_cs_dl) { if (now - m_last_cs_not_low > 1000) { m_current_cs_dl += 1; - if (m_current_cs_dl <= max_cs_ul) - m_current_cs_ul = m_current_cs_dl; LOGP(DRLCMACDL, LOGL_INFO, "MS (IMSI %s): Low error rate %d%%, " - "increasing CS level to %d\n", + "increasing DL CS level to %d\n", imsi(), error_rate, m_current_cs_dl); m_last_cs_not_low = now; } else { @@ -424,6 +419,43 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate) void GprsMs::update_l1_meas(const pcu_l1_meas *meas) { + struct gprs_rlcmac_bts *bts_data; + uint8_t max_cs_ul = 4; + + OSMO_ASSERT(m_bts != NULL); + bts_data = m_bts->bts_data(); + + if (bts_data->max_cs_ul) + max_cs_ul = bts_data->max_cs_ul; + + if (meas->have_link_qual) { + int old_link_qual = meas->link_qual; + int low = bts_data->cs_lqual_ranges[current_cs_ul()-1].low; + int high = bts_data->cs_lqual_ranges[current_cs_ul()-1].high; + uint8_t new_cs_ul = m_current_cs_ul; + + if (m_l1_meas.have_link_qual) + old_link_qual = m_l1_meas.link_qual; + + if (meas->link_qual < low && old_link_qual < low) + new_cs_ul = m_current_cs_ul - 1; + else if (meas->link_qual > high && old_link_qual > high && + m_current_cs_ul < max_cs_ul) + new_cs_ul = m_current_cs_ul + 1; + + if (m_current_cs_ul != new_cs_ul) { + LOGP(DRLCMACDL, LOGL_INFO, + "MS (IMSI %s): " + "Link quality %ddB (%ddB) left window [%d, %d], " + "modifying uplink CS level: %d -> %d\n", + imsi(), meas->link_qual, old_link_qual, + low, high, + m_current_cs_ul, new_cs_ul); + + m_current_cs_ul = new_cs_ul; + } + } + if (meas->have_rssi) m_l1_meas.set_rssi(meas->rssi); if (meas->have_bto) diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index cecf786e..416e48f3 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -178,6 +178,15 @@ int main(int argc, char *argv[]) bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */ bts->max_cs_ul = 4; bts->max_cs_dl = 4; + /* CS-1 to CS-4 */ + bts->cs_lqual_ranges[0].low = -256; + bts->cs_lqual_ranges[0].high = 6; + bts->cs_lqual_ranges[1].low = 5; + bts->cs_lqual_ranges[1].high = 8; + bts->cs_lqual_ranges[2].low = 7; + bts->cs_lqual_ranges[2].high = 13; + bts->cs_lqual_ranges[3].low = 12; + bts->cs_lqual_ranges[3].high = 256; msgb_set_talloc_ctx(tall_pcu_ctx); diff --git a/src/pcu_vty.c b/src/pcu_vty.c index 355f5440..8db025e6 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -90,6 +90,15 @@ static int config_write_pcu(struct vty *vty) else vty_out(vty, " no cs threshold%s", VTY_NEWLINE); + vty_out(vty, " cs link-quality-ranges cs1 %d cs2 %d %d cs3 %d %d cs4 %d%s", + bts->cs_lqual_ranges[0].high, + bts->cs_lqual_ranges[1].low, + bts->cs_lqual_ranges[1].high, + bts->cs_lqual_ranges[2].low, + bts->cs_lqual_ranges[2].high, + bts->cs_lqual_ranges[3].low, + VTY_NEWLINE); + if (bts->force_llc_lifetime == 0xffff) vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE); else if (bts->force_llc_lifetime) @@ -600,6 +609,41 @@ DEFUN(cfg_pcu_no_cs_err_limits, return CMD_SUCCESS; } +DEFUN(cfg_pcu_cs_lqual_ranges, + cfg_pcu_cs_lqual_ranges_cmd, + "cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35> cs3 <0-35> <0-35> cs4 <0-35>", + CS_STR "Set link quality ranges\n" + "Set quality range for CS-1 (high value only)\n" + "CS-1 high (dB)\n" + "Set quality range for CS-2\n" + "CS-2 low (dB)\n" + "CS-2 high (dB)\n" + "Set quality range for CS-3\n" + "CS-3 low (dB)\n" + "CS-3 high (dB)\n" + "Set quality range for CS-4 (low value only)\n" + "CS-4 low (dB)\n") +{ + struct gprs_rlcmac_bts *bts = bts_main_data(); + + uint8_t cs1_high = atoi(argv[0]); + uint8_t cs2_low = atoi(argv[1]); + uint8_t cs2_high = atoi(argv[2]); + uint8_t cs3_low = atoi(argv[3]); + uint8_t cs3_high = atoi(argv[4]); + uint8_t cs4_low = atoi(argv[5]); + + bts->cs_lqual_ranges[0].high = cs1_high; + bts->cs_lqual_ranges[1].low = cs2_low; + bts->cs_lqual_ranges[1].high = cs2_high; + bts->cs_lqual_ranges[2].low = cs3_low; + bts->cs_lqual_ranges[2].high = cs3_high; + bts->cs_lqual_ranges[3].low = cs4_low; + + return CMD_SUCCESS; +} + + DEFUN(show_tbf, show_tbf_cmd, "show tbf all", @@ -685,6 +729,7 @@ int pcu_vty_init(const struct log_info *cat) install_element(PCU_NODE, &cfg_pcu_no_cs_max_cmd); install_element(PCU_NODE, &cfg_pcu_cs_err_limits_cmd); install_element(PCU_NODE, &cfg_pcu_no_cs_err_limits_cmd); + install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd); install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd); install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);