move lapdm/L1CTL_Test.ttcn to bts/BTS_Tests_LAPDm.ttcn

Change-Id: Ibbc967f0bd9a19ab4bbd17f612654d72cb32d571
diff --git a/bts/BTS_Tests_LAPDm.ttcn b/bts/BTS_Tests_LAPDm.ttcn
new file mode 100644
index 0000000..d6c605d
--- /dev/null
+++ b/bts/BTS_Tests_LAPDm.ttcn
@@ -0,0 +1,252 @@
+module BTS_Tests_LAPDm {
+	import from GSM_Types all;
+	import from Osmocom_Types all;
+	import from LAPDm_RAW_PT all;
+	import from LAPDm_Types all;
+
+	type component lapdm_test_CT {
+		port LAPDm_PT LAPDM;
+		var lapdm_CT lapdm_component;
+	};
+
+	function f_init() runs on lapdm_test_CT {
+		/* create the LAPDm component */
+		lapdm_component := lapdm_CT.create;
+		/* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */
+		connect(self:LAPDM, lapdm_component:LAPDM_SP);
+		/* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally
+		 * connected to the Unix Domain Socket test port */
+		map(lapdm_component:L1CTL, system:L1CTL);
+
+		/* start the LAPDm parallel component calling it's local function LAPDmStart */
+		lapdm_component.start(LAPDmStart());
+	}
+
+	/* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */
+	function f_establish_dcch() runs on lapdm_test_CT {
+		var BCCH_tune_req tune_req := { arfcn := { false, 871 }, combined_ccch := true };
+		var DCCH_establish_req est_req := { ra := 23 };
+
+		LAPDM.send(tune_req);
+		LAPDM.send(est_req);
+		LAPDM.receive(DCCH_establish_res:?);
+	}
+
+	/* helper function releasing dedicated radio channel physically (no Um signaling!) */
+	function f_release_dcch() runs on lapdm_test_CT {
+		var DCCH_release_req rel_req := {};
+		LAPDM.send(rel_req);
+	}
+
+	template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
+		sacch := sacch,
+		sapi := sapi,
+		lapdm := frame
+	}
+	/* template for a valid SABM frame */
+	template LapdmFrame LAPDm_B_SABM(template GsmSapi sapi, octetstring payload)  := {
+		ab := {
+			addr := tr_LapdmAddr(sapi, false),
+			ctrl := tr_LapdmCtrlSABM(true),
+			len := lengthof(payload),
+			m := false,
+			el := 1,
+			payload := payload
+		}
+	}
+
+	/* template for a valid UA frame */
+	template LapdmFrame tr_LAPDm_B_UA(template GsmSapi sapi, template octetstring payload)  := {
+		ab := {
+			addr := tr_LapdmAddr(sapi, false),
+			ctrl := tr_LapdmCtrlUA(true),
+			len := ?,
+			m := false,
+			el := 1,
+			payload := payload
+		}
+	}
+
+	/* template for a valid UA frame */
+	template LapdmFrame LAPDm_B_UA(template GsmSapi sapi, octetstring payload)  := {
+		ab := {
+			addr := tr_LapdmAddr(sapi, false),
+			ctrl := tr_LapdmCtrlUA(true),
+			len := lengthof(payload),
+			m := false,
+			el := 1,
+			payload := payload
+		}
+	}
+
+	/* template for a valid UI frame */
+	template LapdmFrame LAPDm_B_UI(template GsmSapi sapi, octetstring payload)  := {
+		ab := {
+			addr := tr_LapdmAddr(sapi, true),
+			ctrl := tr_LapdmCtrlUI(false),
+			len := lengthof(payload),
+			m := false,
+			el := 1,
+			payload := payload
+		}
+	}
+
+	template LapdmFrame t_nopayload(template GsmSapi sapi) := {
+		ab := {
+			addr := tr_LapdmAddr(sapi, true),
+			ctrl := ?,
+			len := 0,
+			m := false,
+			el := 1,
+			payload := ''O
+		}
+	}
+
+	template LapdmFrame LAPDm_B_DISC(template GsmSapi sapi) modifies t_nopayload := {
+		ab := {
+			ctrl := tr_LapdmCtrlDISC(true)
+		}
+	}
+
+	template LapdmFrame LAPDm_B_RR(template GsmSapi sapi, template uint3_t nr) modifies t_nopayload := {
+		ab := {
+			ctrl := tr_LapdmCtrlRR(nr, false)
+		}
+	}
+
+
+	function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on lapdm_test_CT return boolean {
+		var LAPDm_ph_data phd;
+		var boolean result := false;
+		timer T := 5.0;
+
+		f_establish_dcch();
+		LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
+		log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
+		T.start
+		alt {
+			[] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { result := true; }
+			[] LAPDM.receive(t_PH_DATA(?, use_sacch, ?)) -> value phd { log("Other msg on DCH: ", phd); repeat; }
+			[] LAPDM.receive(t_PH_DATA(?, ?, ?)) -> value phd { log("Other PH-DATA: ", phd); repeat; }
+			[] T.timeout { }
+		}
+		LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_RR(sapi, 0)));
+		f_release_dcch();
+		return result;
+	}
+
+	testcase TC_sabm_ua_dcch_sapi0() runs on lapdm_test_CT {
+		f_init();
+		if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
+			setverdict(fail);
+		}
+		setverdict(pass);
+	}
+
+	testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on lapdm_test_CT {
+		f_init();
+		if (f_test_sabm_results_in_ua(0, false, ''O)) {
+			setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
+		}
+		setverdict(pass);
+	}
+
+	testcase TC_sabm_ua_dcch_sapi3() runs on lapdm_test_CT {
+		f_init();
+		if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
+			setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
+		}
+		setverdict(pass);
+	}
+
+	testcase TC_sabm_ua_dcch_sapi4() runs on lapdm_test_CT {
+		f_init();
+		if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
+			setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
+		}
+		setverdict(pass);
+	}
+
+	testcase TC_sabm_contention() runs on lapdm_test_CT {
+		var LAPDm_ph_data phd;
+		const octetstring payload := '0102030405'O;
+		const GsmSapi sapi := 0;
+		const boolean use_sacch := false;
+		timer T := 5.0;
+
+		f_init();
+
+		f_establish_dcch();
+		/* first frame is our real SABM */
+		LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
+		/* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */
+		LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, 'ABCDEF'O)));
+		log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
+		T.start
+		alt {
+			[] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { setverdict(pass); repeat; }
+			[] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_B_UA(sapi, ?))) {
+				setverdict(fail, "Second SABM was responded to during contention resolution");
+			}
+			[] LAPDM.receive { repeat };
+			[] T.timeout { }
+		}
+		f_release_dcch();
+	}
+
+	/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
+	  * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
+	testcase TC_sabm_retransmit() runs on lapdm_test_CT {
+		const octetstring payload := '00FEFEDEADBEEF'O;
+		f_init();
+		if (not f_test_sabm_results_in_ua(0, false, payload)) {
+			setverdict(fail, "UA not received for first SABM");
+		}
+		if (not f_test_sabm_results_in_ua(0, false, payload)) {
+			setverdict(fail, "UA not received for second SABM");
+		}
+		setverdict(pass);
+	}
+
+	testcase TC_foo() runs on lapdm_test_CT {
+		var LapdmFrame lf;
+/*
+		var LapdmFrame lf := valueof(LAPDm_B_UA(0, ''O));
+		log("ENC UA: ", enc_LapdmFrame(lf));
+		lf := valueof(LAPDm_B_UI(0, ''O));
+		log("ENC UI B: ", enc_LapdmFrame(lf));
+		log("ENC UI B: ", enc_LapdmFrameB(lf.b));
+
+		log("DEC UI AF: ", dec_LapdmAddressField('03'O));
+*/
+
+		lf := valueof(LAPDm_B_RR(0, 0));
+		log("ENC RR: ", enc_LapdmFrame(lf));
+
+		lf := valueof(LAPDm_B_UA(0, ''O));
+		log("ENC UA: ", enc_LapdmFrame(lf));
+
+		lf := valueof(LAPDm_B_UI(0, ''O));
+		log("ENC UI: ", enc_LapdmFrame(lf));
+
+		log("DEC UI CU: ", dec_LapdmCtrlU('03'O));
+		log("DEC UI CT: ", dec_LapdmCtrl('03'O));
+
+		log("DEC UA: ", dec_LapdmFrameAB('017301'O));
+		log("DEC UI: ", dec_LapdmFrameAB('030301'O));
+		log("DEC I: ", dec_LapdmFrameAB('030001'O));
+		log("DEC S: ", dec_LapdmFrameAB('030101'O));
+		log("DEC: ", dec_LapdmFrameAB('030301'O));
+		log("DEC: ", dec_LapdmFrameAB('0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O));
+	}
+
+	control {
+		execute(TC_foo());
+		execute(TC_sabm_ua_dcch_sapi0());
+		execute(TC_sabm_ua_dcch_sapi0_nopayload());
+		execute(TC_sabm_ua_dcch_sapi3());
+		execute(TC_sabm_ua_dcch_sapi4());
+		execute(TC_sabm_contention());
+		execute(TC_sabm_retransmit());
+	}
+}