Change in osmo-bsc[master]: refactor lchan counting

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

neels gerrit-no-reply at lists.osmocom.org
Tue Oct 26 22:27:06 UTC 2021


neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bsc/+/25972 )


Change subject: refactor lchan counting
......................................................................

refactor lchan counting

Add trx_count_lchans() and bts_count_lchans(). Drop bts_count_free_ts()
and trx_count_free_ts().

Rationale:

The bts_count_free_ts() and trx_count_free_ts() always returned the
number of free lchans, not timeslots. Hence, passing the pchan type as
argument never really matched the semantics.

Especially, when looking for free SDCCH, there is no clear match on a
gsm_phys_chan_config enum value: SDCCH8_SACCH8C, CCCH_SDCCH4,
CCCH_SDCCH4_CBCH, SDCCH8_SACCH8C_CBCH? -- GSM_LCHAN_SDCCH is clear.

==> Rather count free lchans by enum gsm_chan_t.

Counting lchans of distinct types required separate iterations for each
lchan type.

==> Rather compose an array of counts for all types, in one go.

I need to count the amount of free SDCCH lchans in an upcoming patch to
implement the performance indicator allAvailableAllocatedSDCCH (cumulate
time for which no SDCCH are available).

To implement allAvailableAllocated{SDCCH,TCH}, I need a count of both
the used as well as the total lchans for a type: it does not make sense
to flag "all available allocated" if none are ever available.

To properly count dynamic ts, I need the maximum total that can be
possible at any time. And to count currently free lchans, I need the
current total. This may seem counter intuitive, but consider, e.g.:

- Obviously, if a cell has only static TCH/F timeslots, it does not make
  sense to flag that all available TCH/H are occupied, because no TCH/H
  are available ever. Just stating this as contrast to dyn TS.

- If a cell has OSMO_DYN timeslots, I *do* want to flag that all TCH/H
  are occupied when all dyn timeslots are fully occupied.

- If those OSMO_DYN however are all used as TCH/F, the current total of
  TCH/H becomes zero, and it seems like TCH/H should not be considered.

- To count the nr of currently free lchans, I need the currently
  possible total of lchans and the nr of occupied lchans.

So return both a maximum total and a current total of lchans. In above
example, the maximum total shows that there would be TCH/H possible.

BTW, it would be nice to keep a chan_counts array on trx, bts and bsc
level and update as channels are allocated and released, instead of
counting them all over periodically. But it's less error prone this way.

Related: SYS#4878
Change-Id: I2fb48c549186db812b1e9d6b735a92e80f27b8d3
---
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/bts_trx.h
M include/osmocom/bsc/gsm_data.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/bts.c
M src/osmo-bsc/bts_trx.c
M src/osmo-bsc/gsm_data.c
M src/osmo-bsc/handover_decision_2.c
8 files changed, 265 insertions(+), 50 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/72/25972/1

diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index 68654f2..700033c 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -712,7 +712,7 @@
 
 void gsm_bts_all_ts_dispatch(struct gsm_bts *bts, uint32_t ts_ev, void *data);
 
-int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan);
+void bts_count_lchans(chan_counts_t bts_counts, struct gsm_bts *bts);
 
 int gsm_bts_set_system_infos(struct gsm_bts *bts);
 
diff --git a/include/osmocom/bsc/bts_trx.h b/include/osmocom/bsc/bts_trx.h
index 4d705d0..ca6e8b5 100644
--- a/include/osmocom/bsc/bts_trx.h
+++ b/include/osmocom/bsc/bts_trx.h
@@ -95,7 +95,7 @@
 bool trx_is_usable(const struct gsm_bts_trx *trx);
 
 void gsm_trx_all_ts_dispatch(struct gsm_bts_trx *trx, uint32_t ts_ev, void *data);
-int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan);
+void trx_count_lchans(chan_counts_t counts, const struct gsm_bts_trx *trx);
 bool trx_has_valid_pchan_config(const struct gsm_bts_trx *trx);
 
 int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index cb56028..3d2c901 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -1135,6 +1135,7 @@
 
 uint8_t pchan_subslots(enum gsm_phys_chan_config pchan);
 uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan);
+int pchan_subslots_for_lchant(enum gsm_phys_chan_config pchan, enum gsm_chan_t type);
 bool ts_is_tch(struct gsm_bts_trx_ts *ts);
 
 struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos);
@@ -1410,4 +1411,73 @@
 
 enum rsl_cmod_spd chan_mode_to_rsl_cmod_spd(enum gsm48_chan_mode chan_mode);
 
+/* First array index to typedef chan_counts_t. */
+enum chan_counts_dim1 {
+	CHAN_COUNTS1_ALL = 0,
+	CHAN_COUNTS1_STATIC = 1,
+	CHAN_COUNTS1_DYNAMIC = 2,
+	CHAN_COUNTS1_N
+};
+
+extern const struct value_string chan_count1_strs[];
+static inline const char *chan_count1_str(enum chan_counts_dim1 val)
+{ return get_value_string(chan_count1_strs, val); }
+
+/* Second array index to typedef chan_counts_t. */
+enum chan_counts_dim2 {
+	/* The maximum possible nr of lchans of this type. Counts all dynamic timeslots as if they are fully available
+	 * for this type, regardless of the current pchan mode. (For CHAN_COUNTS1_STATIC, of course no dyn TS are counted
+	 * at all.) */
+	CHAN_COUNTS2_MAX_TOTAL = 0,
+	/* Like MAX_TOTAL, but as soon as dynamic timeslots are switched to a specific pchan kind, current_total shrinks
+	 * to count only currently present lchans (used and unused). */
+	CHAN_COUNTS2_CURRENT_TOTAL = 1,
+	/* Currently used lchans of this type. To get currently free lchans, calculate CURRENT_TOTAL - ALLOCATED. */
+	CHAN_COUNTS2_ALLOCATED = 2,
+	/* Currently assignable lchans of this type, same as CURRENT_TOTAL - ALLOCATED. */
+	CHAN_COUNTS2_FREE = 3,
+	CHAN_COUNTS2_N
+};
+
+extern const struct value_string chan_count2_strs[];
+static inline const char *chan_count2_str(enum chan_counts_dim2 val)
+{ return get_value_string(chan_count2_strs, val); }
+
+typedef unsigned int chan_counts_dim3 [_GSM_LCHAN_MAX];
+typedef unsigned int chan_counts_dim2 [CHAN_COUNTS2_N][_GSM_LCHAN_MAX];
+typedef unsigned int chan_counts_t [CHAN_COUNTS1_N][CHAN_COUNTS2_N][_GSM_LCHAN_MAX];
+
+static inline void chan_counts_zero(chan_counts_t counts)
+{
+	memset(counts, 0, sizeof(chan_counts_t));
+}
+
+static inline void chan_counts_dim3_add(chan_counts_dim3 dst, const chan_counts_dim3 add)
+{
+	int i;
+	for (i = 0; i < _GSM_LCHAN_MAX; i++)
+		dst[i] += add[i];
+}
+
+static inline void chan_counts_dim3_sub(chan_counts_dim3 dst, const chan_counts_dim3 sub)
+{
+	int i;
+	for (i = 0; i < _GSM_LCHAN_MAX; i++)
+		dst[i] = (sub[i] < dst[i]) ? dst[i] - sub[i] : 0;
+}
+
+static inline void chan_counts_dim2_add(chan_counts_dim2 dst, const chan_counts_dim2 add)
+{
+	int i;
+	for (i = 0; i < CHAN_COUNTS2_N; i++)
+		chan_counts_dim3_add(dst[i], add[i]);
+}
+
+static inline void chan_counts_add(chan_counts_t dst, const chan_counts_t add)
+{
+	int i;
+	for (i = 0; i < CHAN_COUNTS1_N; i++)
+		chan_counts_dim2_add(dst[i], add[i]);
+}
+
 #endif /* _GSM_DATA_H */
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 0e2ffc6..f539b07 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1958,6 +1958,7 @@
 
 struct gsm_lchan *_select_sdcch_for_call(struct gsm_bts *bts, const struct chan_rqd *rqd, enum gsm_chan_t lctype)
 {
+	chan_counts_t bts_counts;
 	struct gsm_lchan *lchan = NULL;
 	int free_tchf, free_tchh;
 	bool needs_dyn_switch;
@@ -1969,8 +1970,9 @@
 	needs_dyn_switch = lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN &&
 					lchan->ts->pchan_is != GSM_PCHAN_SDCCH8_SACCH8C;
 
-	free_tchf = bts_count_free_ts(bts, GSM_PCHAN_TCH_F);
-	free_tchh = bts_count_free_ts(bts, GSM_PCHAN_TCH_H);
+	bts_count_lchans(bts_counts, bts);
+	free_tchf = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
+	free_tchh = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
 	if (free_tchf == 0 && free_tchh == 0) {
 		LOG_BTS(bts, DRSL, LOGL_INFO,
 			"CHAN RQD: 0x%x Requesting %s reason=call but no TCH available\n",
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index 21ee01a..2e4b520 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -719,17 +719,16 @@
 		gsm_trx_all_ts_dispatch(trx, ts_ev, data);
 }
 
-
-/* Count number of free TS of given pchan type */
-int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
+void bts_count_lchans(chan_counts_t bts_counts, struct gsm_bts *bts)
 {
 	struct gsm_bts_trx *trx;
-	int count = 0;
+	chan_counts_zero(bts_counts);
 
-	llist_for_each_entry(trx, &bts->trx_list, list)
-		count += trx_count_free_ts(trx, pchan);
-
-	return count;
+	llist_for_each_entry(trx, &bts->trx_list, list) {
+		chan_counts_t trx_counts;
+		trx_count_lchans(trx_counts, trx);
+		chan_counts_add(bts_counts, trx_counts);
+	}
 }
 
 /* set all system information types for a BTS */
diff --git a/src/osmo-bsc/bts_trx.c b/src/osmo-bsc/bts_trx.c
index f30c748..523a7c4 100644
--- a/src/osmo-bsc/bts_trx.c
+++ b/src/osmo-bsc/bts_trx.c
@@ -292,52 +292,94 @@
 	}
 }
 
-int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
+static const unsigned int lchans_per_pchan[_GSM_PCHAN_MAX][_GSM_LCHAN_MAX] = {
+	[GSM_PCHAN_NONE] = {0},
+	[GSM_PCHAN_CCCH] = { [GSM_LCHAN_CCCH] = 1, },
+	[GSM_PCHAN_PDCH] = { [GSM_LCHAN_PDTCH] = 1, },
+	[GSM_PCHAN_CCCH_SDCCH4] = {
+		[GSM_LCHAN_CCCH] = 1,
+		[GSM_LCHAN_SDCCH] = 3,
+	},
+	[GSM_PCHAN_TCH_F] = { [GSM_LCHAN_TCH_F] = 1, },
+	[GSM_PCHAN_TCH_H] = { [GSM_LCHAN_TCH_H] = 2, },
+	[GSM_PCHAN_SDCCH8_SACCH8C] = { [GSM_LCHAN_SDCCH] = 8, },
+	[GSM_PCHAN_CCCH_SDCCH4_CBCH] = {
+		[GSM_LCHAN_CCCH] = 1,
+		[GSM_LCHAN_SDCCH] = 3,
+		[GSM_LCHAN_CBCH] = 1,
+	},
+	[GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = {
+		[GSM_LCHAN_SDCCH] = 8,
+		[GSM_LCHAN_CBCH] = 1,
+	},
+	[GSM_PCHAN_OSMO_DYN] = {
+		[GSM_LCHAN_TCH_F] = 1,
+		[GSM_LCHAN_TCH_H] = 2,
+		[GSM_LCHAN_SDCCH] = 8,
+		[GSM_LCHAN_PDTCH] = 1,
+	},
+	[GSM_PCHAN_TCH_F_PDCH] = {
+		[GSM_LCHAN_TCH_F] = 1,
+		[GSM_LCHAN_PDTCH] = 1,
+	},
+};
+
+void trx_count_lchans(chan_counts_t ret, const struct gsm_bts_trx *trx)
 {
-	struct gsm_bts_trx_ts *ts;
-	struct gsm_lchan *lchan;
-	int j;
-	int count = 0;
+	const struct gsm_bts_trx_ts *ts;
+	const struct gsm_lchan *lchan;
+	int i;
+
+	chan_counts_zero(ret);
 
 	if (!trx_is_usable(trx))
-		return 0;
+		return;
 
-	for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
-		ts = &trx->ts[j];
+	for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
+		bool ts_is_dynamic;
+		chan_counts_dim2 ts_count = {0};
+		ts = &trx->ts[i];
 		if (!ts_is_usable(ts))
 			continue;
 
-		if (ts->pchan_is == GSM_PCHAN_PDCH) {
-			/* Dynamic timeslots in PDCH mode will become TCH if needed. */
-			switch (ts->pchan_on_init) {
-			case GSM_PCHAN_TCH_F_PDCH:
-				if (pchan == GSM_PCHAN_TCH_F)
-					count++;
-				continue;
+		/* Count the full potential nr of lchans for dynamic TS */
+		chan_counts_dim3_add(ts_count[CHAN_COUNTS2_MAX_TOTAL], lchans_per_pchan[ts->pchan_on_init]);
 
-			case GSM_PCHAN_OSMO_DYN:
-				if (pchan == GSM_PCHAN_TCH_F)
-					count++;
-				else if (pchan == GSM_PCHAN_TCH_H)
-					count += 2;
-				continue;
-
-			default:
-				/* Not dynamic, not applicable. */
-				continue;
-			}
+		switch (ts->pchan_on_init) {
+		case GSM_PCHAN_TCH_F_PDCH:
+		case GSM_PCHAN_OSMO_DYN:
+			ts_is_dynamic = true;
+			break;
+		default:
+			ts_is_dynamic = false;
+			break;
 		}
 
-		if (ts->pchan_is != pchan)
-			continue;
+		if (ts_is_dynamic && ts->pchan_is == GSM_PCHAN_PDCH) {
+			/* Dynamic timeslots in PDCH mode can become TCH or SDCCH immediately,
+			 * so set CURRENT_TOTAL = MAX_TOTAL. */
+			chan_counts_dim3_add(ts_count[CHAN_COUNTS2_CURRENT_TOTAL], ts_count[CHAN_COUNTS2_MAX_TOTAL]);
+		} else {
+			/* Static TS, or dyn TS that are currently fixed on a specific pchan: count lchans for the
+			 * current pchan mode. */
+			chan_counts_dim3_add(ts_count[CHAN_COUNTS2_CURRENT_TOTAL], lchans_per_pchan[ts->pchan_is]);
+		}
 
+		/* Count currently allocated lchans */
 		ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
-			if (lchan_state_is(lchan, LCHAN_ST_UNUSED))
-				count++;
+			if (!lchan_state_is(lchan, LCHAN_ST_UNUSED))
+				ts_count[CHAN_COUNTS2_ALLOCATED][lchan->type]++;
 		}
-	}
 
-	return count;
+		chan_counts_dim3_add(ts_count[CHAN_COUNTS2_FREE], ts_count[CHAN_COUNTS2_CURRENT_TOTAL]);
+		chan_counts_dim3_sub(ts_count[CHAN_COUNTS2_FREE], ts_count[CHAN_COUNTS2_ALLOCATED]);
+
+		if (ts_is_dynamic)
+			chan_counts_dim2_add(ret[CHAN_COUNTS1_DYNAMIC], ts_count);
+		else
+			chan_counts_dim2_add(ret[CHAN_COUNTS1_STATIC], ts_count);
+		chan_counts_dim2_add(ret[CHAN_COUNTS1_ALL], ts_count);
+	}
 }
 
 bool trx_has_valid_pchan_config(const struct gsm_bts_trx *trx)
diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c
index 0134e34..9a5128a 100644
--- a/src/osmo-bsc/gsm_data.c
+++ b/src/osmo-bsc/gsm_data.c
@@ -646,6 +646,102 @@
 	return subslots_per_pchan_vamos[pchan];
 }
 
+/*! Return the maximum nr of lchans of the given type possible in the given pchan config.
+ * TODO: include possible VAMOS secondary lchans? */
+int pchan_subslots_for_lchant(enum gsm_phys_chan_config pchan, enum gsm_chan_t type)
+{
+	switch (pchan) {
+	default:
+	case GSM_PCHAN_UNKNOWN:
+	case GSM_PCHAN_NONE:
+		return 0;
+	case GSM_PCHAN_CCCH:
+		switch (type) {
+		case GSM_LCHAN_CCCH:
+			return 1;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_CCCH_SDCCH4:
+		switch (type) {
+		case GSM_LCHAN_CCCH:
+			return 1;
+		case GSM_LCHAN_SDCCH:
+			return 4;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_TCH_F:
+		switch (type) {
+		case GSM_LCHAN_TCH_F:
+			return 1;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_TCH_H:
+		switch (type) {
+		case GSM_LCHAN_TCH_H:
+			return 2;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_SDCCH8_SACCH8C:
+		switch (type) {
+		case GSM_LCHAN_SDCCH:
+			return 8;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_PDCH:
+		switch (type) {
+		case GSM_LCHAN_PDTCH:
+			return 1;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_TCH_F_PDCH:
+		switch (type) {
+		case GSM_LCHAN_PDTCH:
+		case GSM_LCHAN_TCH_F:
+			return 1;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_CCCH_SDCCH4_CBCH:
+		switch (type) {
+		case GSM_LCHAN_CCCH:
+		case GSM_LCHAN_CBCH:
+			return 1;
+		case GSM_LCHAN_SDCCH:
+			return 4;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
+		switch (type) {
+		case GSM_LCHAN_SDCCH:
+			return 8;
+		case GSM_LCHAN_CBCH:
+			return 1;
+		default:
+			return 0;
+		}
+	case GSM_PCHAN_OSMO_DYN:
+		switch (type) {
+		case GSM_LCHAN_SDCCH:
+			return 8;
+		case GSM_LCHAN_TCH_F:
+			return 1;
+		case GSM_LCHAN_TCH_H:
+			return 2;
+		case GSM_LCHAN_PDTCH:
+			return 1;
+		default:
+			return 0;
+		}
+	}
+}
+
 static bool pchan_is_tch(enum gsm_phys_chan_config pchan)
 {
 	switch (pchan) {
diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c
index d08173c..387561c 100644
--- a/src/osmo-bsc/handover_decision_2.c
+++ b/src/osmo-bsc/handover_decision_2.c
@@ -990,12 +990,15 @@
 
 static void candidate_set_free_tch(struct ho_candidate *c)
 {
+	chan_counts_t bts_counts;
 	struct gsm_lchan *next_lchan;
 
-	c->current.free_tchf = bts_count_free_ts(c->current.bts, GSM_PCHAN_TCH_F);
+	bts_count_lchans(bts_counts, c->current.bts);
+	c->current.free_tchf = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
 	c->current.min_free_tchf = ho_get_hodec2_tchf_min_slots(c->current.bts->ho);
-	c->current.free_tchh = bts_count_free_ts(c->current.bts, GSM_PCHAN_TCH_H);
+	c->current.free_tchh = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
 	c->current.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->current.bts->ho);
+
 	switch (c->current.lchan->ts->pchan_is) {
 	case GSM_PCHAN_TCH_F:
 		c->current.free_tch = c->current.free_tchf;
@@ -1023,9 +1026,10 @@
 		break;
 	}
 
-	c->target.free_tchf = bts_count_free_ts(c->target.bts, GSM_PCHAN_TCH_F);
+	bts_count_lchans(bts_counts, c->target.bts);
+	c->target.free_tchf = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
 	c->target.min_free_tchf = ho_get_hodec2_tchf_min_slots(c->target.bts->ho);
-	c->target.free_tchh = bts_count_free_ts(c->target.bts, GSM_PCHAN_TCH_H);
+	c->target.free_tchh = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
 	c->target.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->target.bts->ho);
 
 	/* Would the next TCH/F lchan occupy a dynamic timeslot that currently counts for free TCH/H timeslots? */
@@ -1928,6 +1932,7 @@
 
 static void bts_congestion_check(struct gsm_bts *bts)
 {
+	chan_counts_t bts_counts;
 	int min_free_tchf, min_free_tchh;
 	int free_tchf, free_tchh;
 
@@ -1955,8 +1960,9 @@
 		return;
 	}
 
-	free_tchf = bts_count_free_ts(bts, GSM_PCHAN_TCH_F);
-	free_tchh = bts_count_free_ts(bts, GSM_PCHAN_TCH_H);
+	bts_count_lchans(bts_counts, bts);
+	free_tchf = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_F];
+	free_tchh = bts_counts[CHAN_COUNTS1_ALL][CHAN_COUNTS2_FREE][GSM_LCHAN_TCH_H];
 	LOGPHOBTS(bts, LOGL_INFO, "Congestion check: (free/want-free) TCH/F=%d/%d TCH/H=%d/%d\n",
 		  free_tchf, min_free_tchf, free_tchh, min_free_tchh);
 

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/25972
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I2fb48c549186db812b1e9d6b735a92e80f27b8d3
Gerrit-Change-Number: 25972
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211026/225c5f8f/attachment.htm>


More information about the gerrit-log mailing list