BTS_Tests: Verify RSL MS POWER CONTROL and SACCH MS POWER LEVEL

Usually the MS power is controlled by the BTS and there is no continous
supervison by the BSC needed. However, a scheme where the BSC takes care
of the power control loop exists. The power is then set via RSL using an
RSL MS POWER CONTROL message.

This tests establishes a dchan and then sends MS POWER CONTROL messages
with differen power levels and then checks the presence of the power
level set in the MS POWER LEVEL field of the SACCH L1 header.

Change-Id: I82b04a3bf94d355175f7f6ff3fdc43672e8080a2
Related: OS#1622
diff --git a/bts/BTS_Tests.ttcn b/bts/BTS_Tests.ttcn
index 753d89b..0de787a 100644
--- a/bts/BTS_Tests.ttcn
+++ b/bts/BTS_Tests.ttcn
@@ -1502,6 +1502,76 @@
 	Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
 }
 
+/* establish DChan, and send MS POWER CONTROL messages via RSL, verify that
+ * the BTS is forwarding those values to the MS via the SACCH L1 header. */
+function f_tc_rsl_ms_pwr_ctrl(charstring id) runs on ConnHdlr {
+	var L1ctlDlMessage l1_dl;
+	var RSL_IE_MS_Power ms_power;
+	var RSL_Message rsl;
+	var uint5_t power_level := 0;
+
+	f_l1_tune(L1CTL);
+	RSL.clear;
+
+	f_est_dchan();
+
+	ms_power.reserved := 0;
+	ms_power.fpc_epc := false;
+
+	/* Send the first power control command. This will disable any BTS/TRX
+	 * internal power control and switch the MS (which is not in scope of
+	 * this test) to a constant power level. We start with a power level
+	 * of 0 */
+	ms_power.power_level := power_level;
+	rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
+	RSL.send(rsl);
+
+	alt {
+
+	/* Pick all SACCH blocks for checking */
+	[] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
+
+		/* The first byte of the L1 header contains the power level.
+		 * The reserved bits and the fpc bit is set to 0, so we may
+		 * compare directly. */
+		if (not (l1_dl.payload.data_ind.payload[0] == int2oct(power_level, 1))) {
+			setverdict(fail, "Power level in L1 header does not match the signaled (RSL) power level.");
+		}
+
+		/* Signal a new power level via RSL for the next turn. */
+		if (power_level < 31) {
+			power_level := power_level + 1;
+			ms_power.power_level := power_level;
+			rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
+			RSL.send(rsl);
+			repeat;
+		}
+
+		}
+
+	/* Ignore all other blocks */
+	[] L1CTL.receive { repeat; }
+
+	}
+
+	f_rsl_chan_deact();
+	f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+
+	setverdict(pass);
+}
+
+testcase TC_rsl_ms_pwr_ctrl() runs on test_CT {
+	var ConnHdlr vc_conn;
+	var ConnHdlrPars pars;
+	f_init(testcasename());
+
+	for (var integer tn := 1; tn <= 4; tn := tn+1) {
+		pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
+		vc_conn := f_start_handler(refers(f_tc_rsl_ms_pwr_ctrl), pars);
+		vc_conn.done;
+	}
+	Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+}
 
 /* Test if a channel without valid uplink bursts generates RSL CONN FAIL IND (TS 48.058 4.10) */
 private function f_TC_conn_fail_crit(charstring id) runs on ConnHdlr {
@@ -4128,7 +4198,6 @@
 * check DEACTIVATE SACCH
 ** unsupported algorithm
 * handover detection
-* MS Power Control
 * BS Power Control
 * Physical Context
 * CCCH Load Indication for RACH
@@ -4164,6 +4233,7 @@
 	execute( TC_meas_res_sign_sdcch4() );
 	execute( TC_meas_res_sign_sdcch8() );
 	execute( TC_meas_res_sign_tchh_toa256() );
+	execute( TC_rsl_ms_pwr_ctrl() );
 	execute( TC_conn_fail_crit() );
 	execute( TC_paging_imsi_80percent() );
 	execute( TC_paging_tmsi_80percent() );