l1ctl/lapdm test infrastructure: Move helper functions out

moving all templates into L1CTL_Types as well as helper functions into
L1CTL_PortType allows us to have a clean L1CTL_Test.ttcn where we can
focus on actual test cases.  At the moment it's just a PoC that can
establish dedicated mode and send a SABM frame to the BTS, which is
properly echo'ed back in the UA, as expected for contention resolution.
diff --git a/lapd/L1CTL_Test.ttcn b/lapd/L1CTL_Test.ttcn
index f8c4fdc..3ff063d 100644
--- a/lapd/L1CTL_Test.ttcn
+++ b/lapd/L1CTL_Test.ttcn
@@ -3,6 +3,7 @@
 	import from Osmocom_Types all;
 	import from L1CTL_Types all;
 	import from L1CTL_PortType all;
+	import from LAPDm_Types all;
 
 	const octetstring c_ul_param_req := '1300000000000000001d0000'O;
 	const octetstring c_ul_data_req := '060a0128284018001d000103490615004001c0000000000000000000000000'O;
@@ -16,134 +17,7 @@
 	type component dummy_CT {
 		var charstring l1ctl_sock_path := "/tmp/osmocom_l2";
 		port L1CTL_PT L1CTL;
-	};
-
-	/* for generating RESET_REQ */
-	template L1ctlUlMessage t_L1ctlResetReq(template L1ctlResetType rst_type) := {
-		header := t_L1ctlHeader(L1CTL_RESET_REQ),
-		ul_info := omit,
-		payload := {
-			reset_req := {
-				reset_type := rst_type,
-				padding := '000000'O
-			}
-		}
-	};
-
-	/* for generating FBSB_REQ */
-	template L1ctlUlMessage t_L1CTL_FBSB_REQ(template Arfcn arfcn, template L1ctlFbsbFlags flags, uint8_t sync_info_idx, L1ctlCcchMode ccch_mode, GsmRxLev rxlev_exp) := {
-		header := t_L1ctlHeader(L1CTL_FBSB_REQ),
-		ul_info := omit,
-		payload := {
-			fbsb_req := {
-				arfcn := arfcn,
-				timeout_tdma_frames := 10,
-				freq_err_thresh1 := 10000,
-				freq_err_thresh2 := 800,
-				num_freqerr_avg := 3,
-				flags := flags,
-				sync_info_idx := sync_info_idx,
-				ccch_mode := ccch_mode,
-				rxlev_exp := rxlev_exp
-			}
-		}
-	};
-
-	/* for matching against incoming FBSB_CONF */
-	template L1ctlDlMessage t_L1CTL_FBSB_CONF(template uint8_t result) := {
-		header := t_L1ctlHeader(L1CTL_FBSB_CONF),
-		dl_info := ?,
-		payload := {
-			fbsb_conf := {
-				initial_freq_err := ?,
-				result := result,
-				bsic := ?
-			}
-		}
-	};
-
-	template L1ctlUlMessage t_L1CTL_RACH_REQ(uint8_t ra, uint8_t combined, uint16_t offset) := {
-		header := t_L1ctlHeader(L1CTL_RACH_REQ),
-		ul_info := {
-			chan_nr := t_RslChanNr_RACH(0),
-			link_id := ts_RslLinkID_DCCH(0),
-			padding := '0000'O
-		},
-		payload := {
-			rach_req := {
-				ra := ra,
-				combined := combined,
-				offset := offset
-			}
-		}
-	}
-
-	template L1ctlUlMessage t_L1CTL_DM_EST_REQ(Arfcn arfcn, RslChannelNr chan_nr, GsmTsc tsc) := {
-		header := t_L1ctlHeader(L1CTL_DM_EST_REQ),
-		ul_info := {
-			chan_nr := chan_nr,
-			link_id := ts_RslLinkID_DCCH(0),
-			padding := '0000'O
-		},
-		payload := {
-			dm_est_req := {
-				tsc := tsc,
-				h := 0,
-				arfcn := arfcn,
-				hopping := omit,
-				tch_mode := 0,
-				audio_mode := t_L1CTL_AudioModeNone
-			}
-		}
-	}
-
-	template L1ctlUlMessage t_L1CTL_DM_REL_REQ(RslChannelNr chan_nr) := {
-		header := t_L1ctlHeader(L1CTL_DM_EST_REQ),
-		ul_info := {
-			chan_nr := chan_nr,
-			link_id := ts_RslLinkID_DCCH(0),
-			padding := '0000'O
-		},
-		payload := {
-			other := ''O
-		}
-	}
-
-	template L1ctlUlMessage t_L1CTL_DATA_REQ(template RslChannelNr chan_nr, template RslLinkId link_id, octetstring l2_data) := {
-		header := t_L1ctlHeader(L1CTL_DATA_REQ),
-		ul_info := {
-			chan_nr := chan_nr,
-			link_id := link_id,
-			padding := '0000'O
-		},
-		payload := {
-			other := l2_data
-		}
-	}
-
-	/* for matching against incoming RACH_CONF */
-	template L1ctlDlMessage t_L1CTL_RACH_CONF := {
-		header := t_L1ctlHeader(L1CTL_RACH_CONF),
-		dl_info := ?,
-		payload := ?
-	};
-
-	/* for matching against incoming RACH_CONF */
-	template L1ctlDlMessage t_L1CTL_DATA_IND(template RslChannelNr chan_nr) := {
-		header := t_L1ctlHeader(L1CTL_DATA_IND),
-		dl_info := {
-			chan_nr := chan_nr,
-			link_id := ?,
-			arfcn := ?,
-			frame_nr := ?,
-			rx_level := ?,
-			snr := ?,
-			num_biterr := ?,
-			fire_crc := ?
-		},
-		payload := {
-			data_ind := ?
-		}
+		var ChannelDescription chan_desc;
 	};
 
 
@@ -156,7 +30,8 @@
 		L1CTL.receive;
 	}
 
-	testcase TC_si1() runs on dummy_CT {
+	/* a very ppor man's job to check if we can actually still decode the L1CTL binary messages */
+	testcase TC_selftest() runs on dummy_CT {
 		log("L1CTL_PARAM_REQ: ", dec_L1ctlUlMessage(c_ul_param_req));
 		log("L1CTL_DATA_REQ: ", dec_L1ctlUlMessage(c_ul_data_req));
 		log("L1CTL_CCCH_MODE_REQ: ", dec_L1ctlUlMessage(c_ul_ccch_mode_req));
@@ -167,79 +42,12 @@
 		setverdict(pass);
 	}
 
-	function f_L1CTL_FBSB(L1CTL_PT pt, Arfcn arfcn, L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED) {
-		timer T := 5.0;
-		pt.send(t_L1CTL_FBSB_REQ(arfcn, t_L1CTL_FBSB_F_ALL, 0, ccch_mode, 0));
-		T.start
-		alt {
-			[] pt.receive(t_L1CTL_FBSB_CONF(0)) {};
-			[] pt.receive { repeat; };
-			[] T.timeout { setverdict(fail, "Timeout in FBSB") };
-		}
-	}
-
-	function f_L1CTL_RACH(L1CTL_PT pt, uint8_t ra, uint8_t combined := 1, uint16_t offset := 0) return GsmFrameNumber {
-		var L1ctlDlMessage rc;
-		var GsmFrameNumber fn;
-		timer T := 2.0;
-		T.start
-		pt.send(t_L1CTL_RACH_REQ(ra, 0, 0))
-		alt {
-			[] pt.receive(t_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
-			[] pt.receive { repeat; };
-			[] T.timeout { setverdict(fail, "Timeout in RACH") };
-		}
-		return fn;
-	}
-
-	template GsmRrMessage t_RR_IMM_ASS(uint8_t ra, uint8_t fn) := {
-		header := t_RrHeader(IMMEDIATE_ASSIGNMENT, ?),
-		payload := {
-			imm_ass := {
-				ded_or_tbf := ?,
-				page_mode := ?,
-				chan_desc := ?,
-				pkt_chan_desc := omit,
-				req_ref := f_compute_ReqRef(ra, fn),
-				timing_advance := ?,
-				mobile_allocation := ?
-			}
-		}
-	};
-
-	function f_L1CTL_WAIT_IMM_ASS(L1CTL_PT pt, uint8_t ra, GsmFrameNumber rach_fn) return ImmediateAssignment {
-		var L1ctlDlMessage dl;
-		var GsmRrMessage rr;
-		timer T := 10.0;
-		T.start;
-		alt {
-			[] pt.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
-				rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
-				log("PCH/AGCN DL RR: ", rr);
-				if (match(rr, t_RR_IMM_ASS(ra, rach_fn))) {
-					log("Received IMM.ASS for our RACH!");
-				} else {
-					repeat;
-				}
-			};
-			[] pt.receive { repeat };
-			[] T.timeout { setverdict(fail, "Timeout waiting for IMM ASS") };
-		}
-		T.stop;
-		return rr.payload.imm_ass;
-	}
-
-	/* Send DM_EST_REQ from parameters derived from IMM ASS */
-	function f_L1CTL_DM_EST_REQ_IA(L1CTL_PT pt, ImmediateAssignment imm_ass) {
-		pt.send(t_L1CTL_DM_EST_REQ({ false, imm_ass.chan_desc.arfcn }, imm_ass.chan_desc.chan_nr, imm_ass.chan_desc.tsc));
-	}
-
-	testcase TC_l1ctl() runs on dummy_CT {
+	/* master function establishing a dedicated radio channel */
+	function f_establish_dcch() runs on dummy_CT {
+		var ImmediateAssignment imm_ass;
 		var GsmFrameNumber rach_fn;
 		var uint8_t ra := 23;
-		var ImmediateAssignment imm_ass;
 
-		f_init();
 		/* send FB/SB req to sync to cell */
 		f_L1CTL_FBSB(L1CTL, { false, 871 }, CCCH_MODE_COMBINED);
 		/* send RACH request and obtain FN at which it was sent */
@@ -249,17 +57,63 @@
 		/* send DM_EST_REQ */
 		f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
 
-		L1CTL.send(t_L1CTL_DATA_REQ(imm_ass.chan_desc.chan_nr, ts_RslLinkID_DCCH(0), '000102030405060708090a0b0c0d0e0f10111213141516'O));
-		L1CTL.send(t_L1CTL_DATA_REQ(imm_ass.chan_desc.chan_nr, ts_RslLinkID_DCCH(0), '000102030405060708090a0b0c0d0e0f10111213141516'O));
-		L1CTL.send(t_L1CTL_DATA_REQ(imm_ass.chan_desc.chan_nr, ts_RslLinkID_DCCH(0), '000102030405060708090a0b0c0d0e0f10111213141516'O));
+		chan_desc := imm_ass.chan_desc;
+	}
 
-		L1CTL.send(t_L1CTL_DM_REL_REQ(imm_ass.chan_desc.chan_nr));
+	/* send some data over an established dedicated radio channel */
+	function f_send_l2(template RslLinkId link_id, octetstring l2_data) runs on dummy_CT { 
+		L1CTL.send(t_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, l2_data));
+	}
+
+	/* send some data over an established dedicated radio channel */
+	function f_send_l2_lapdm_b(template RslLinkId link_id, template LapdmFrameB b) runs on dummy_CT { 
+		var octetstring l2_data := enc_LapdmFrameB(valueof(b));
+		L1CTL.send(t_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, l2_data));
+	}
+
+
+	function f_recv_l2() runs on dummy_CT return octetstring {
+		var L1ctlDlMessage dl;
+		var octetstring l2_data;
+		timer T := 5.0;
+		T.start
+		alt {
+			[] L1CTL.receive(t_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl { l2_data := dl.payload.data_ind.payload };
+			[] L1CTL.receive { repeat; };
+			[] T.timeout { setverdict(fail, "Timeout waiting for DL data"); };
+		}
+		return l2_data;
+	}
+
+	/* release the dedicated radio channel */
+	function f_release_dcch() runs on dummy_CT {
+		L1CTL.send(t_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
+	}
+
+	template LapdmFrameB LAPDm_SABM(template GsmSapi sapi, template octetstring payload)  := {
+		addr := tr_LapdmAddr(sapi, false),
+		ctrl := t_LapdmCtrlSABM(true),
+		len := t_LapdmLengthIndicator(lengthof(payload)),
+		payload := payload
+	}
+
+	testcase TC_l1ctl() runs on dummy_CT {
+		f_init();
+
+		f_establish_dcch();
+
+		f_send_l2_lapdm_b(ts_RslLinkID_DCCH(0), LAPDm_SABM(0, 'FEFE'O));
+		f_recv_l2();
+
+		//f_send_l2(ts_RslLinkID_DCCH(0), '000102030405060708090a0b0c0d0e0f10111213141516'O);
+
+		f_release_dcch();
 
 		setverdict(pass);
 	}
 
 	control {
-		execute(TC_si1());
+		execute(TC_selftest());
 		execute(TC_l1ctl());
 	}
 }