Get rid of tbf->first_ts

There's no big benefit in keeping it stored since it can be quickly
found. This makes the tbf data structure simplier and easier to
maintain, and discharges the alloc_algorithm functions from an extra
step.

Change-Id: I5d2f665f648f8637466bfdd3bf7b924cb61ede33
diff --git a/src/bts.cpp b/src/bts.cpp
index c6253f4..5ae0714 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -988,7 +988,8 @@
 			goto send_imm_ass_rej;
 		}
 		tbf->set_ta(ta);
-		pdch = &tbf->trx->pdch[tbf->first_ts];
+		/* Only single TS can be allocated through AGCH, hence first TS is the only one: */
+		pdch = tbf_get_first_ts(tbf);
 		usf = tbf->m_usf[pdch->ts_no];
 		bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_ONE_PHASE);
 	}
@@ -1076,12 +1077,15 @@
 
 void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, const struct gprs_rlcmac_dl_tbf *tbf)
 {
-	uint8_t trx_no = tbf->trx->trx_no;
-	uint8_t ts_no = tbf->first_ts;
 	uint16_t pgroup = ms_paging_group(tbf_ms(tbf));
 	int plen;
+	const struct gprs_rlcmac_pdch *pdch;
 
 	LOGPTBF(tbf, LOGL_INFO, "TX: START Immediate Assignment Downlink (PCH)\n");
+
+	/* Only one TS can be assigned through PCH, hence the first one is the only one: */
+	pdch = tbf_get_first_ts_const(tbf);
+
 	bitvec *immediate_assignment = bitvec_alloc(22, tall_pcu_ctx); /* without plen */
 	bitvec_unhex(immediate_assignment, DUMMY_VEC); /* standard '2B'O padding */
 	/* 3GPP TS 44.018, section 9.1.18.0d states that the network shall code the
@@ -1090,10 +1094,10 @@
 	 * message sent by a mobile station.  Use last_rts_fn + 21216 (16 TDMA
 	 * super-frame periods, or ~21.3 seconds) to achieve a decent distance. */
 	LOGP(DRLCMAC, LOGL_DEBUG, " - TRX=%d (%d) TS=%d TA=%d\n",
-		trx_no, tbf->trx->arfcn, ts_no, tbf->ta());
-	plen = Encoding::write_immediate_assignment(&bts->trx[trx_no].pdch[ts_no],
+	     tbf->trx->trx_no, tbf->trx->arfcn, pdch->ts_no, tbf->ta());
+	plen = Encoding::write_immediate_assignment(pdch,
 						    tbf, immediate_assignment, true, 125,
-						    GSM_TDMA_FN_SUM(tbf->pdch[ts_no]->last_rts_fn, 21216),
+						    GSM_TDMA_FN_SUM(pdch->last_rts_fn, 21216),
 						    tbf->ta(), 7, false, 0,
 						    bts_get_ms_pwr_alpha(bts), bts->pcu->vty.gamma, -1,
 						    GSM_L1_BURST_TYPE_ACCESS_0);
diff --git a/src/encoding.cpp b/src/encoding.cpp
index c5f4dd4..370dbe2 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -553,7 +553,7 @@
 	Direct_encoding_1_t fh_params;
 
 	/* Check one PDCH, if it's hopping then all other should too */
-	pdch = tbf->pdch[tbf->first_ts];
+	pdch = tbf_get_first_ts_const(tbf);
 	OSMO_ASSERT(pdch != NULL);
 
 	/* Training Sequence Code */
@@ -562,7 +562,7 @@
 	/* If frequency hopping is not in use, encode a single ARFCN */
 	if (!pdch->fh.enabled) {
 		freq_params->UnionType = 0x00;
-		freq_params->u.ARFCN = tbf->trx->arfcn;
+		freq_params->u.ARFCN = pdch->trx->arfcn;
 		return;
 	}
 
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 026ad6e..96098a9 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -411,7 +411,6 @@
 
 	tbf->trx = trx;
 	/* the only one TS is the common TS */
-	tbf->first_ts = ts;
 	ms_set_reserved_slots(ms, trx, 1 << ts, 1 << ts);
 	ms_set_first_common_ts(ms, ts);
 
@@ -865,7 +864,7 @@
 	int8_t first_common_ts;
 	uint8_t slotcount = 0;
 	uint8_t reserve_count = 0, trx_no;
-	int first_ts = -1;
+	int first_ts;
 	int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
 	int rc;
 	int tfi;
@@ -920,15 +919,14 @@
 	}
 
 	first_ts = ffs(rc) - 1;
-	first_common_ts = ffs(dl_slots & ul_slots) - 1;
-
-	if (first_common_ts < 0) {
-		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first common slot unavailable\n");
+	if (first_ts < 0) {
+		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first slot unavailable\n");
 		return -EINVAL;
 	}
 
-	if (first_ts < 0) {
-		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first slot unavailable\n");
+	first_common_ts = ffs(dl_slots & ul_slots) - 1;
+	if (first_common_ts < 0) {
+		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first common slot unavailable\n");
 		return -EINVAL;
 	}
 
@@ -948,7 +946,6 @@
 	update_ms_reserved_slots(trx, ms, reserved_ul_slots, reserved_dl_slots, ul_slots, dl_slots);
 	ms_set_first_common_ts(ms, first_common_ts);
 	tbf->trx = trx;
-	tbf->first_ts = first_ts;
 
 	if (tbf->direction == GPRS_RLCMAC_DL_TBF)
 		assign_dl_tbf_slots(tbf_as_dl_tbf(tbf), trx, dl_slots, tfi);
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index e35e817..17aa203 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -61,12 +61,11 @@
 		tbf->ta(),
 		tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
 		tbf->imsi(), VTY_NEWLINE);
-	vty_out(vty, " created=%lu state=%s flags=%08x [CCCH:%u, PACCH:%u] 1st_TS=%d 1st_cTS=%" PRId8 " ctrl_TS=%d MS_CLASS=%d/%d%s",
+	vty_out(vty, " created=%lu state=%s flags=%08x [CCCH:%u, PACCH:%u] 1st_cTS=%" PRId8 " ctrl_TS=%d MS_CLASS=%d/%d%s",
 		tbf->created_ts(), tbf->state_name(),
 		state_flags,
 		state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH),
 		state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH),
-		tbf->first_ts,
 		ms_first_common_ts(ms), tbf->control_ts,
 		tbf->ms_class(),
 		ms_egprs_ms_class(ms),
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 7483d49..8358b8f 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -90,7 +90,6 @@
 gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir) :
 	direction(dir),
 	trx(NULL),
-	first_ts(TBF_TS_UNSET),
 	control_ts(TBF_TS_UNSET),
 	fT(0),
 	num_fT_exp(0),
@@ -892,6 +891,32 @@
 	return tbf->update();
 }
 
+/* first TS used by TBF */
+struct gprs_rlcmac_pdch *tbf_get_first_ts(struct gprs_rlcmac_tbf *tbf)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tbf->pdch); i++) {
+		struct gprs_rlcmac_pdch *pdch;
+		pdch = tbf->pdch[i];
+		if (pdch)
+			return pdch;
+	}
+	return NULL;
+}
+const struct gprs_rlcmac_pdch *tbf_get_first_ts_const(const struct gprs_rlcmac_tbf *tbf)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tbf->pdch); i++) {
+		const struct gprs_rlcmac_pdch *pdch;
+		pdch = tbf->pdch[i];
+		if (pdch)
+			return pdch;
+	}
+	return NULL;
+}
+
 const char* tbf_rlcmac_diag(const struct gprs_rlcmac_tbf *tbf)
 {
 	static char buf[256];
diff --git a/src/tbf.h b/src/tbf.h
index d4d52f9..4a08da9 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -148,6 +148,8 @@
 bool tbf_is_control_ts(const struct gprs_rlcmac_tbf *tbf, const struct gprs_rlcmac_pdch *pdch);
 bool tbf_can_upgrade_to_multislot(const struct gprs_rlcmac_tbf *tbf);
 int tbf_update(struct gprs_rlcmac_tbf *tbf);
+struct gprs_rlcmac_pdch *tbf_get_first_ts(struct gprs_rlcmac_tbf *tbf);
+const struct gprs_rlcmac_pdch *tbf_get_first_ts_const(const struct gprs_rlcmac_tbf *tbf);
 struct gprs_rlcmac_trx *tbf_get_trx(struct gprs_rlcmac_tbf *tbf);
 void tbf_stop_timers(struct gprs_rlcmac_tbf *tbf, const char *reason);
 #ifdef __cplusplus
@@ -218,7 +220,6 @@
 
 	enum gprs_rlcmac_tbf_direction direction;
 	struct gprs_rlcmac_trx *trx;
-	uint8_t first_ts; /* first TS used by TBF */
 	uint8_t control_ts; /* timeslot control messages and polling */
 	struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */
 
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index e4e4f79..8333a2f 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -166,7 +166,6 @@
 
 	ul_tbf->trx = trx;
 	/* The only one TS is the common, control TS */
-	ul_tbf->first_ts = ts;
 	ms_set_first_common_ts(ms, ts);
 	tbf_assign_control_ts(ul_tbf);
 	ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, next_tbf_ctr_group_id++);