<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/21971">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">hodec2: code dup / cosmetics<br><br>In handover_decision_2.c, instead of repeating a similar loop four<br>times, put that loop in a function and parameterize it.<br><br>Prepare for a fix of two problems in handover decision 2, see<br>I2704899c85c35dfd4eba43468452483f40016ca2.<br><br>Change-Id: I7c32d08e490a88a7f044b0a71dc4b07d748dd572<br>---<br>M src/osmo-bsc/handover_decision_2.c<br>1 file changed, 133 insertions(+), 194 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c</span><br><span>index 477f1eb..7854f09 100644</span><br><span>--- a/src/osmo-bsc/handover_decision_2.c</span><br><span>+++ b/src/osmo-bsc/handover_decision_2.c</span><br><span>@@ -24,6 +24,7 @@</span><br><span> </span><br><span> #include <stdbool.h></span><br><span> #include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span> </span><br><span> #include <osmocom/bsc/debug.h></span><br><span> #include <osmocom/bsc/gsm_data.h></span><br><span>@@ -1379,10 +1380,22 @@</span><br><span>         return count;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static bool is_intra_cell(const struct ho_candidate *c)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return c->bts && (c->lchan->ts->trx->bts == c->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool is_upgrade_to_tchf(const struct ho_candidate *c, uint8_t for_requirement)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return c->lchan</span><br><span style="color: hsl(120, 100%, 40%);">+            && (c->lchan->type == GSM_LCHAN_TCH_H)</span><br><span style="color: hsl(120, 100%, 40%);">+          && ((c->requirements & for_requirement) & (REQUIREMENT_B_TCHF | REQUIREMENT_C_TCHF));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Given two candidates, pick the one that should rather be moved during handover.</span><br><span>  * Return the better candidate in out-parameters best_cand and best_avg_db.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static void pick_better_lchan_to_move(bool want_highest_db,</span><br><span style="color: hsl(120, 100%, 40%);">+static bool pick_better_lchan_to_move(bool want_highest_db,</span><br><span>                                  struct ho_candidate **best_cand_p, unsigned int *best_avg_db_p,</span><br><span>                                      struct ho_candidate *other_cand, unsigned int other_avg_db)</span><br><span> {</span><br><span>@@ -1400,7 +1413,7 @@</span><br><span>               /* If both are dynamic, prefer one that completely (or to a higher degree) frees its timeslot. */</span><br><span>            if (lchan_is_on_dynamic_ts((*best_cand_p)->lchan)</span><br><span>                     && ts_usage_count((*best_cand_p)->lchan->ts) < ts_usage_count(other_cand->lchan->ts))</span><br><span style="color: hsl(0, 100%, 40%);">-                        return;</span><br><span style="color: hsl(120, 100%, 40%);">+                       return false;</span><br><span>                /* If both equally satisfy these preferences, it does not matter which one is picked.</span><br><span>                 * Give slight preference to moving later dyn TS, so that a free dyn TS may group with following static</span><br><span>               * PDCH, though this depends on how the user configured the TS -- not harmful to do so anyway. */</span><br><span>@@ -1408,11 +1421,76 @@</span><br><span>  }</span><br><span> </span><br><span>        /* keep the same candidate. */</span><br><span style="color: hsl(0, 100%, 40%);">-  return;</span><br><span style="color: hsl(120, 100%, 40%);">+       return false;</span><br><span> </span><br><span> return_other:</span><br><span>   *best_cand_p = other_cand;</span><br><span>   *best_avg_db_p = other_avg_db;</span><br><span style="color: hsl(120, 100%, 40%);">+        return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ho_candidate *pick_best_candidate(int *applied_afs_bias,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct ho_candidate *clist, int clist_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            bool want_highest_db,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         bool omit_intra_cell_upgrade_to_tchf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         bool only_intra_cell_upgrade_to_tchf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         uint8_t for_requirement)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ho_candidate *result = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int result_avg_rxlev;</span><br><span style="color: hsl(120, 100%, 40%);">+        int result_afs_bias = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (applied_afs_bias)</span><br><span style="color: hsl(120, 100%, 40%);">+         *applied_afs_bias = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      result_avg_rxlev = want_highest_db ? 0 : INT_MAX;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < clist_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ho_candidate *c = &clist[i];</span><br><span style="color: hsl(120, 100%, 40%);">+               bool intra_cell;</span><br><span style="color: hsl(120, 100%, 40%);">+              bool upgrade_to_tch_f;</span><br><span style="color: hsl(120, 100%, 40%);">+                int avg_rxlev;</span><br><span style="color: hsl(120, 100%, 40%);">+                int afs_bias;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* For multiple passes of congestion resolution, already handovered candidates are marked by lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+           * NULL. (though at the time of writing, multiple passes of congestion resolution are DISABLED.) */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!c->lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Omit remote BSS */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!c->bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!(c->requirements & for_requirement))</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           intra_cell = is_intra_cell(c);</span><br><span style="color: hsl(120, 100%, 40%);">+                upgrade_to_tch_f = is_upgrade_to_tchf(c, for_requirement);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (only_intra_cell_upgrade_to_tchf</span><br><span style="color: hsl(120, 100%, 40%);">+               && !(intra_cell && upgrade_to_tch_f))</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (omit_intra_cell_upgrade_to_tchf</span><br><span style="color: hsl(120, 100%, 40%);">+               && (intra_cell && upgrade_to_tch_f))</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           avg_rxlev = c->avg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* improve AHS */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (upgrade_to_tch_f)</span><br><span style="color: hsl(120, 100%, 40%);">+                 afs_bias = ho_get_hodec2_afs_bias_rxlev(c->bts->ho);</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  afs_bias = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+         avg_rxlev += afs_bias;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (pick_better_lchan_to_move(want_highest_db, &result, &result_avg_rxlev, c, avg_rxlev))</span><br><span style="color: hsl(120, 100%, 40%);">+                     result_afs_bias = afs_bias;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (applied_afs_bias)</span><br><span style="color: hsl(120, 100%, 40%);">+         *applied_afs_bias = result_afs_bias;</span><br><span style="color: hsl(120, 100%, 40%);">+  return result;</span><br><span> }</span><br><span> </span><br><span> /*</span><br><span>@@ -1472,10 +1550,7 @@</span><br><span>       int i, j;</span><br><span>    struct ho_candidate *clist;</span><br><span>  unsigned int candidates;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ho_candidate *best_cand = NULL, *worst_cand = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct gsm_lchan *delete_lchan = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned int best_avg_db, worst_avg_db;</span><br><span style="color: hsl(0, 100%, 40%);">- int avg;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ho_candidate *best_cand = NULL;</span><br><span>       int rc = 0;</span><br><span>  int any_ho = 0;</span><br><span>      int is_improved = 0;</span><br><span>@@ -1571,55 +1646,19 @@</span><br><span> #if 0</span><br><span> next_b1:</span><br><span> #endif</span><br><span style="color: hsl(0, 100%, 40%);">-   /* select best candidate that fulfills requirement B,</span><br><span style="color: hsl(0, 100%, 40%);">-    * omit change from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-       best_avg_db = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        for (i = 0; i < candidates; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* delete subscriber that just have handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan == delete_lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                     clist[i].lchan = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-          /* omit all subscribers that are handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!clist[i].lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Do not resolve congestion towards remote BSS, which would cause oscillation if the</span><br><span style="color: hsl(0, 100%, 40%);">-            * remote BSS is also congested. */</span><br><span style="color: hsl(0, 100%, 40%);">-             /* TODO: attempt inter-BSC HO if no local cells qualify, and rely on the remote BSS to</span><br><span style="color: hsl(0, 100%, 40%);">-           * deny receiving the handover if it also considers itself congested. Maybe do that only</span><br><span style="color: hsl(0, 100%, 40%);">-                 * when the cell is absolutely full, i.e. not only min-free-slots. (x) */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!clist[i].bts)</span><br><span style="color: hsl(0, 100%, 40%);">-                      continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!(clist[i].requirements & REQUIREMENT_B_MASK))</span><br><span style="color: hsl(0, 100%, 40%);">-                  continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* omit assignment from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (clist[i].lchan->ts->trx->bts == clist[i].bts</span><br><span style="color: hsl(0, 100%, 40%);">-                && clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && (clist[i].requirements & REQUIREMENT_B_TCHF))</span><br><span style="color: hsl(0, 100%, 40%);">-                   continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* omit candidates that will not solve/reduce congestion */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (clist[i].lchan->type == GSM_LCHAN_TCH_F</span><br><span style="color: hsl(0, 100%, 40%);">-           && tchf_congestion <= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && tchh_congestion <= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               avg = clist[i].avg;</span><br><span style="color: hsl(0, 100%, 40%);">-             /* improve AHS */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan->tch_mode == GSM48_CMODE_SPEECH_AMR</span><br><span style="color: hsl(0, 100%, 40%);">-                && clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && (clist[i].requirements & REQUIREMENT_B_TCHF)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 avg += ho_get_hodec2_afs_bias_rxlev(clist[i].bts->ho);</span><br><span style="color: hsl(0, 100%, 40%);">-                       is_improved = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                } else</span><br><span style="color: hsl(0, 100%, 40%);">-                  is_improved = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGPHOCAND(&clist[i], LOGL_DEBUG, "candidate %d: avg=%d best_avg_db=%d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                           i, avg, best_avg_db);</span><br><span style="color: hsl(0, 100%, 40%);">-                pick_better_lchan_to_move(true, &best_cand, &best_avg_db, &clist[i], avg);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* perform handover, if there is a candidate */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* select best candidate that does not cause congestion in the target.</span><br><span style="color: hsl(120, 100%, 40%);">+         * Do not resolve congestion towards remote BSS, which would cause oscillation if the remote BSS is also</span><br><span style="color: hsl(120, 100%, 40%);">+       * congested.</span><br><span style="color: hsl(120, 100%, 40%);">+  * Treating specially below: upgrading TCH/H to TCH/F within the same cell, so omit here.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: attempt inter-BSC HO if no local cells qualify, and rely on the remote BSS to</span><br><span style="color: hsl(120, 100%, 40%);">+         * deny receiving the handover if it also considers itself congested. Maybe do that only</span><br><span style="color: hsl(120, 100%, 40%);">+       * when the cell is absolutely full, i.e. not only min-free-slots. (x) */</span><br><span style="color: hsl(120, 100%, 40%);">+     best_cand = pick_best_candidate(&is_improved, clist, candidates,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  /* want_highest_db */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   /* omit_intra_cell_upgrade_to_tchf */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   /* only_intra_cell_upgrade_to_tchf */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  REQUIREMENT_B_MASK);</span><br><span>         if (best_cand) {</span><br><span>             any_ho = 1;</span><br><span>          LOGPHOCAND(best_cand, LOGL_DEBUG, "Best candidate: RX level %d%s\n",</span><br><span>@@ -1650,59 +1689,29 @@</span><br><span> #if 0</span><br><span> next_b2:</span><br><span> #endif</span><br><span style="color: hsl(0, 100%, 40%);">- /* select worst candidate that fulfills requirement B,</span><br><span style="color: hsl(0, 100%, 40%);">-   * select candidates that change from AHS to AFS only */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (tchh_congestion > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* since this will only check half rate channels, it will</span><br><span style="color: hsl(0, 100%, 40%);">-                * only need to be checked, if tchh is congested */</span><br><span style="color: hsl(0, 100%, 40%);">-             worst_avg_db = 999;</span><br><span style="color: hsl(0, 100%, 40%);">-             for (i = 0; i < candidates; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* delete subscriber that just have handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (clist[i].lchan == delete_lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                             clist[i].lchan = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* omit all subscribers that are handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (!clist[i].lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                            continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(0, 100%, 40%);">-                        * the remote BSS is also congested. */</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* TODO: see (x) above */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!clist[i].bts)</span><br><span style="color: hsl(0, 100%, 40%);">-                              continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!(clist[i].requirements & REQUIREMENT_B_MASK))</span><br><span style="color: hsl(0, 100%, 40%);">-                          continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* omit all but assignment from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (clist[i].lchan->ts->trx->bts != clist[i].bts</span><br><span style="color: hsl(0, 100%, 40%);">-                        || clist[i].lchan->type != GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-                   || !(clist[i].requirements & REQUIREMENT_B_TCHF))</span><br><span style="color: hsl(0, 100%, 40%);">-                          continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       avg = clist[i].avg;</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* improve AHS */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (clist[i].lchan->tch_mode == GSM48_CMODE_SPEECH_AMR</span><br><span style="color: hsl(0, 100%, 40%);">-                        && clist[i].lchan->type == GSM_LCHAN_TCH_H) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               avg += ho_get_hodec2_afs_bias_rxlev(clist[i].bts->ho);</span><br><span style="color: hsl(0, 100%, 40%);">-                               is_improved = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                        } else</span><br><span style="color: hsl(0, 100%, 40%);">-                          is_improved = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                        pick_better_lchan_to_move(false, &worst_cand, &worst_avg_db, &clist[i], avg);</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* perform handover, if there is a candidate */</span><br><span style="color: hsl(0, 100%, 40%);">- if (worst_cand) {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* For upgrading TCH/H to TCH/F within the same cell, we want to pick the *lowest* average rxlev: for staying</span><br><span style="color: hsl(120, 100%, 40%);">+  * within the same cell, give the MS with the worst service more bandwidth. When staying within the same cell,</span><br><span style="color: hsl(120, 100%, 40%);">+         * the target avg rxlev is identical to the source lchan rxlev, so it is fine to use the same avg rxlev value,</span><br><span style="color: hsl(120, 100%, 40%);">+         * but simply pick the lowest one.</span><br><span style="color: hsl(120, 100%, 40%);">+     * Upgrading TCH/H channels obviously only applies when TCH/H is actually congested. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tchh_congestion > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           best_cand = pick_best_candidate(&is_improved, clist, candidates,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* want_highest_db */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* omit_intra_cell_upgrade_to_tchf */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* only_intra_cell_upgrade_to_tchf */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           REQUIREMENT_B_MASK);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (best_cand) {</span><br><span>             any_ho = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPHOCAND(worst_cand, LOGL_INFO, "Worst candidate: RX level %d from TCH/H -> TCH/F%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     rxlev2dbm(worst_cand->avg),</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPHOCAND(best_cand, LOGL_INFO, "Worst candidate: RX level %d from TCH/H -> TCH/F%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    rxlev2dbm(best_cand->avg),</span><br><span>                        is_improved ? " (applied AHS -> AFS rxlev bias)" : "");</span><br><span style="color: hsl(0, 100%, 40%);">-               trigger_ho(worst_cand, worst_cand->requirements & REQUIREMENT_B_MASK);</span><br><span style="color: hsl(120, 100%, 40%);">+         trigger_ho(best_cand, best_cand->requirements & REQUIREMENT_B_MASK);</span><br><span> #if 0</span><br><span>                 /* if there is still congestion, mark lchan as deleted</span><br><span>                * and redo this process */</span><br><span>          tchh_congestion--;</span><br><span>           if (tchh_congestion > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   delete_lchan = worst_cand->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+                  delete_lchan = best_cand->lchan;</span><br><span>                  best_cand = NULL;</span><br><span>                    goto next_b2;</span><br><span>                }</span><br><span>@@ -1718,51 +1727,14 @@</span><br><span> #if 0</span><br><span> next_c1:</span><br><span> #endif</span><br><span style="color: hsl(0, 100%, 40%);">-      /* select best candidate that fulfills requirement C,</span><br><span style="color: hsl(0, 100%, 40%);">-    * omit change from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-       best_avg_db = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        for (i = 0; i < candidates; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* delete subscriber that just have handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan == delete_lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                     clist[i].lchan = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-          /* omit all subscribers that are handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!clist[i].lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(0, 100%, 40%);">-                * the remote BSS is also congested. */</span><br><span style="color: hsl(0, 100%, 40%);">-         /* TODO: see (x) above */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!clist[i].bts)</span><br><span style="color: hsl(0, 100%, 40%);">-                      continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!(clist[i].requirements & REQUIREMENT_C_MASK))</span><br><span style="color: hsl(0, 100%, 40%);">-                  continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* omit assignment from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (clist[i].lchan->ts->trx->bts == clist[i].bts</span><br><span style="color: hsl(0, 100%, 40%);">-                && clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && (clist[i].requirements & REQUIREMENT_C_TCHF))</span><br><span style="color: hsl(0, 100%, 40%);">-                   continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* omit candidates that will not solve/reduce congestion */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (clist[i].lchan->type == GSM_LCHAN_TCH_F</span><br><span style="color: hsl(0, 100%, 40%);">-           && tchf_congestion <= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && tchh_congestion <= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               avg = clist[i].avg;</span><br><span style="color: hsl(0, 100%, 40%);">-             /* improve AHS */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (clist[i].lchan->tch_mode == GSM48_CMODE_SPEECH_AMR</span><br><span style="color: hsl(0, 100%, 40%);">-                && clist[i].lchan->type == GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-           && (clist[i].requirements & REQUIREMENT_C_TCHF)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 avg += ho_get_hodec2_afs_bias_rxlev(clist[i].bts->ho);</span><br><span style="color: hsl(0, 100%, 40%);">-                       is_improved = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                } else</span><br><span style="color: hsl(0, 100%, 40%);">-                  is_improved = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                pick_better_lchan_to_move(true, &best_cand, &best_avg_db, &clist[i], avg);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* perform handover, if there is a candidate */</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Select best candidate that balances congestion.</span><br><span style="color: hsl(120, 100%, 40%);">+     * Again no remote BSS.</span><br><span style="color: hsl(120, 100%, 40%);">+        * Again no TCH/H -> F upgrades within the same cell. */</span><br><span style="color: hsl(120, 100%, 40%);">+   best_cand = pick_best_candidate(&is_improved, clist, candidates,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  /* want_highest_db */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   /* omit_intra_cell_upgrade_to_tchf */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   /* only_intra_cell_upgrade_to_tchf */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  REQUIREMENT_C_MASK);</span><br><span>         if (best_cand) {</span><br><span>             any_ho = 1;</span><br><span>          LOGPHOCAND(best_cand, LOGL_INFO, "Best candidate: RX level %d%s\n",</span><br><span>@@ -1796,62 +1768,29 @@</span><br><span> #if 0</span><br><span> next_c2:</span><br><span> #endif</span><br><span style="color: hsl(0, 100%, 40%);">-  /* select worst candidate that fulfills requirement C,</span><br><span style="color: hsl(0, 100%, 40%);">-   * select candidates that change from AHS to AFS only */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (tchh_congestion > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* since this will only check half rate channels, it will</span><br><span style="color: hsl(0, 100%, 40%);">-                * only need to be checked, if tchh is congested */</span><br><span style="color: hsl(0, 100%, 40%);">-             worst_avg_db = 999;</span><br><span style="color: hsl(0, 100%, 40%);">-             for (i = 0; i < candidates; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* delete subscriber that just have handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (clist[i].lchan == delete_lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                             clist[i].lchan = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-                  /* omit all subscribers that are handovered */</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (!clist[i].lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                            continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* Do not resolve congestion towards remote BSS, which would cause oscillation if</span><br><span style="color: hsl(0, 100%, 40%);">-                        * the remote BSS is also congested. */</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* TODO: see (x) above */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!clist[i].bts)</span><br><span style="color: hsl(0, 100%, 40%);">-                              continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (!(clist[i].requirements & REQUIREMENT_C_MASK))</span><br><span style="color: hsl(0, 100%, 40%);">-                          continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* omit all but assignment from AHS to AFS */</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (clist[i].lchan->ts->trx->bts != clist[i].bts</span><br><span style="color: hsl(0, 100%, 40%);">-                        || clist[i].lchan->type != GSM_LCHAN_TCH_H</span><br><span style="color: hsl(0, 100%, 40%);">-                   || !(clist[i].requirements & REQUIREMENT_C_TCHF))</span><br><span style="color: hsl(0, 100%, 40%);">-                          continue;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       avg = clist[i].avg;</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* improve AHS */</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (clist[i].lchan->tch_mode == GSM48_CMODE_SPEECH_AMR</span><br><span style="color: hsl(0, 100%, 40%);">-                        && clist[i].lchan->type == GSM_LCHAN_TCH_H) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               avg += ho_get_hodec2_afs_bias_rxlev(clist[i].bts->ho);</span><br><span style="color: hsl(0, 100%, 40%);">-                               is_improved = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                        } else</span><br><span style="color: hsl(0, 100%, 40%);">-                          is_improved = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGP(DHODEC, LOGL_DEBUG, "candidate %d: avg=%d worst_avg_db=%d\n", i, avg,</span><br><span style="color: hsl(0, 100%, 40%);">-                         worst_avg_db);</span><br><span style="color: hsl(0, 100%, 40%);">-                     pick_better_lchan_to_move(false, &worst_cand, &worst_avg_db, &clist[i], avg);</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Look for upgrading TCH/H to TCH/F within the same cell, which balances congestion, again upgrade the TCH/H</span><br><span style="color: hsl(120, 100%, 40%);">+  * lchan that has the worst reception: */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tchh_congestion > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           best_cand = pick_best_candidate(&is_improved, clist, candidates,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* want_highest_db */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* omit_intra_cell_upgrade_to_tchf */ false,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          /* only_intra_cell_upgrade_to_tchf */ true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           REQUIREMENT_C_MASK);</span><br><span> </span><br><span>     /* perform handover, if there is a candidate */</span><br><span style="color: hsl(0, 100%, 40%);">- if (worst_cand) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (best_cand) {</span><br><span>             any_ho = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPHOCAND(worst_cand, LOGL_INFO, "Worst candidate: RX level %d from TCH/H -> TCH/F%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     rxlev2dbm(worst_cand->avg),</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGPHOCAND(best_cand, LOGL_INFO, "Worst candidate: RX level %d from TCH/H -> TCH/F%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    rxlev2dbm(best_cand->avg),</span><br><span>                        is_improved ? " (applied AHS -> AFS rxlev bias)" : "");</span><br><span style="color: hsl(0, 100%, 40%);">-               trigger_ho(worst_cand, worst_cand->requirements & REQUIREMENT_C_MASK);</span><br><span style="color: hsl(120, 100%, 40%);">+         trigger_ho(best_cand, best_cand->requirements & REQUIREMENT_C_MASK);</span><br><span> #if 0</span><br><span>                 /* if there is still congestion, mark lchan as deleted</span><br><span>                * and redo this process */</span><br><span>          tchh_congestion--;</span><br><span>           if (tchh_congestion > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   delete_lchan = worst_cand->lchan;</span><br><span style="color: hsl(0, 100%, 40%);">-                    worst_cand = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                    delete_lchan = best_cand->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+                   best_cand = NULL;</span><br><span>                    goto next_c2;</span><br><span>                }</span><br><span> #else</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/21971">change 21971</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/21971"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I7c32d08e490a88a7f044b0a71dc4b07d748dd572 </div>
<div style="display:none"> Gerrit-Change-Number: 21971 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>