BSC_Tests: add support for per-TRX RSL connections

So far it was possible to communicate with multiple BTS instances,
however we were limited to only one IPA/RSL connection per BTS.
Communicating with additional TRX instances requires establishing
additional per-TRX IPA/RSL connections.  This patch extends the
testsuite infrastructure, so that it becomes possible to have
up to 4 individual TRX instances for each BTS.

* Introduce record 'BtsParams', store per-BTS params in an array.
* IPA_RSL_PT: test_CT.IPA_RSL[NUM_BTS] -> test_CT.IPA_RSL[NUM_BTS][NUM_TRX].
* BTS_State: test_CT.bts[NUM_BTS] -> test_CT.bts[NUM_BTS][NUM_TRX].
* f_init_bts_and_check_sysinfo() accepts number of TRX instances.
* f_init_bts() accepts number of TRX instances to configure.
* f_ipa_rsl_start() accepts a BtsTrxIdx param.

* Introduce record BtsTrxIdx allowing to specify BTS/TRX index values.
* f_ipa_tx(), f_exp_ipa_rx() accept a BtsTrxIdx param (default {0, 0}).
* f_est_dchan[_dyn]() accept a BtsTrxIdx param (default {0, 0}).
** and store the given BtsTrxIdx in returned DchanTuple.
* f_chreq_act_ack() accepts a BtsTrxIdx param (default {0, 0}).
* f_expect_chan_rel() accepts a BtsTrxIdx param (default {0, 0}).
* f_exp_ipa_rx_nonfatal() accepts BtsTrxIdx (default {0, 0}).
* f_exp_chan_rel_and_clear() uses BtsTrxIdx indicated in the given DchanTuple.

* Fix CTRL/statsd expectations in TC_stat_num_bts_connected_[123].
* Fix CTRL expectations in TC_ctrl_trx_rf_locked.

The major limitation is that MSC_ConnHdlr components still have no
access to additional TRX instances - this can be implemented later.

Change-Id: Ic0fd97234464ef624010a5f01189aa61f3393b84
Related: SYS#5460
diff --git a/bsc/BSC_Tests_CBSP.ttcn b/bsc/BSC_Tests_CBSP.ttcn
index bede026..a933b24 100644
--- a/bsc/BSC_Tests_CBSP.ttcn
+++ b/bsc/BSC_Tests_CBSP.ttcn
@@ -109,23 +109,23 @@
 }
 
 private altstep as_IgnRSL(template (present) RSL_Message tr) runs on cbsp_test_CT {
-[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) { repeat; }
-[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) { repeat; }
-[] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) { repeat; }
+[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr)) { repeat; }
+[] IPA_RSL[1][0].receive(tr_ASP_RSL_UD(tr)) { repeat; }
+[] IPA_RSL[2][0].receive(tr_ASP_RSL_UD(tr)) { repeat; }
 }
 
 private altstep as_FailRSL() runs on cbsp_test_CT {
 var template (present) RSL_Message tr := (tr_RSL_SMSCB_CMD);
 var ASP_RSL_Unitdata rx;
-[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr)) -> value rx {
 	setverdict(fail, "Received unexpected RSL ", rx);
 	mtc.stop;
 	}
-[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[1][0].receive(tr_ASP_RSL_UD(tr)) -> value rx {
 	setverdict(fail, "Received unexpected RSL ", rx);
 	mtc.stop;
 	}
-[] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[2][0].receive(tr_ASP_RSL_UD(tr)) -> value rx {
 	setverdict(fail, "Received unexpected RSL ", rx);
 	mtc.stop;
 	}
@@ -225,9 +225,9 @@
 
 function f_cbsp_reset_bss(integer idx) runs on cbsp_test_CT {
 	/* Make sure no CBSP ETWS commands from a previous CBSP test remain in the RSL queue */
-	IPA_RSL[0].clear;
-	IPA_RSL[1].clear;
-	IPA_RSL[2].clear;
+	IPA_RSL[0][0].clear;
+	IPA_RSL[1][0].clear;
+	IPA_RSL[2][0].clear;
 
 	var template (value) CBSP_PDU tx;
 	timer T := 3.0;
@@ -254,9 +254,9 @@
 {
 	var template ASP_RSL_Unitdata zero_payload := tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), ''O));
 	interleave {
-	[] IPA_RSL[0].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 0"); }
-	[] IPA_RSL[1].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 1"); }
-	[] IPA_RSL[2].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 2"); }
+	[] IPA_RSL[0][0].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 0"); }
+	[] IPA_RSL[1][0].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 1"); }
+	[] IPA_RSL[2][0].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 2"); }
 	}
 }
 
@@ -562,9 +562,9 @@
 	var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no, expect_blocks := expect_blocks);
 	log("RSL[0,1,2] EXPECTING ", tr_ASP_RSL_UD(tr));
 	interleave {
-	[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[0]"); }
-	[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[1]"); }
-	[] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[2]"); }
+	[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[0]"); }
+	[] IPA_RSL[1][0].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[1]"); }
+	[] IPA_RSL[2][0].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[2]"); }
 	}
 	setverdict(pass);
 
@@ -609,7 +609,7 @@
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
 		     success_list:=cell_list, fail_list:=omit);
 	var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr));
 	f_sleep(5.0);
 }
 
@@ -649,7 +649,7 @@
 	cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
 		     success_list:=?, fail_list:=omit);
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
 	f_sleep(5.0);
 }
 
@@ -663,7 +663,7 @@
 	cell_list := ts_BSSMAP_CIL_CI({bssmap_ci(mp_cgi_bts0)});
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
 		     success_list:=?, fail_list:=omit);
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
 	f_sleep(5.0);
 }
 
@@ -681,7 +681,7 @@
 	cell_list := ts_BSSMAP_CIL_LAI({bssmap_lai(mp_cgi_bts2)});
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
 		     success_list:=?, fail_list:=omit);
-	IPA_RSL[2].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+	IPA_RSL[2][0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
 	f_sleep(5.0);
 }
 
@@ -697,8 +697,8 @@
 		     success_list:=?, fail_list:=omit);
 	var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
 	interleave {
-	[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
-	[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr));
+	[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr));
+	[] IPA_RSL[1][0].receive(tr_ASP_RSL_UD(tr));
 	}
 	f_sleep(5.0);
 }
@@ -714,7 +714,7 @@
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, num_bcast_req:=10, content:=pages,
 		     success_list:=?, fail_list:=omit);
 
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
 
 	/* Replace: keep the same msg_id, use a new ser_no */
 	var uint16_t old_ser_no := g_cbsp_ser_no;
@@ -722,7 +722,7 @@
 	f_cbsp_replace(g_cbsp_msg_id, g_cbsp_ser_no, old_ser_no, cell_list, content:=pages,
 		       success_list:=?, fail_list:=omit);
 
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
 	f_sleep(1.0);
 	setverdict(pass);
 }
@@ -747,7 +747,7 @@
 	/* Count SMSCB messages during N=rep_number+2 repetition periods */
 	T.start(int2float(rep_period * (rep_number + 2)) * 1.883);
 	alt {
-	[] IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(page, g_cbsp_msg_id, g_cbsp_ser_no))) {
+	[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(f_page2rsl(page, g_cbsp_msg_id, g_cbsp_ser_no))) {
 		var float exp_period := int2float(rep_period) * 1.883;
 		var float calc_period := T.read - last_time;
 
@@ -829,7 +829,7 @@
 	f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, num_bcast_req := 5, content:=pages, success_list:=?, fail_list:=omit);
 	/* expect to receive it once on the BTS */
 	var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr));
 	/* kill it, expecting non-empty completion list; success must be empty in case of CBS! */
 	f_cbsp_kill(g_cbsp_msg_id, g_cbsp_ser_no, 0, cell_list, success_list:=omit, compl_list:=?, fail_list:=omit);
 }
@@ -874,7 +874,7 @@
 	timer T := 5.0;
 	T.start;
 	alt {
-	[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(dt.rsl_chan_nr, ?, ?))) -> value rx_rsl_ud {
+	[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(dt.rsl_chan_nr, ?, ?))) -> value rx_rsl_ud {
 		var RSL_IE_Body l3_ie;
 		if (f_rsl_find_ie(rx_rsl_ud.rsl, RSL_IE_L3_INFO, l3_ie) == false) {
 			setverdict(fail, "RSL DATA REQ without L3?");
@@ -891,7 +891,7 @@
 			setverdict(pass);
 			}
 		}
-	[] IPA_RSL[0].receive { repeat; }
+	[] IPA_RSL[0][0].receive { repeat; }
 	[] T.timeout {
 		setverdict(fail, "Waiting for APP INFO");
 		}
@@ -910,14 +910,14 @@
 	}
 
 	alt {
-	[] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), tr_apdu))) {
+	[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), tr_apdu))) {
 		setverdict(pass);
 		}
-	[] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(?,?))) {
+	[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(?,?))) {
 		setverdict(fail, "Received unexpected OSMO_ETWS_CMD");
 		mtc.stop;
 		}
-	[] IPA_RSL[rsl_idx].receive { repeat; }
+	[] IPA_RSL[rsl_idx][0].receive { repeat; }
 	[] T.timeout {
 		if (enabled) {
 			setverdict(fail, "Timeout waiting for RSL_OSMO_ETWS_CMD (enable)");
@@ -1055,7 +1055,7 @@
 		     success_list:=cell_list, fail_list:=omit);
 	var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
 	/* wait for first transmission */
-	IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
+	IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr));
 	var template (present) CBSP_IE_NumBcastComplList compl_list := {
 		len := ?,
 		spare1_4 := ?,