first steps towards a L1CTL / LAPD test

The idea here is to implement the L1CTL protocol in TTCN-3 so we can
speak it over a unix domain socket (test port) for simple tasks such as
activating dedicated mode.

This can then subsequently be used for LAPDm testing
diff --git a/lapd/L1CTL_Types.ttcn b/lapd/L1CTL_Types.ttcn
new file mode 100644
index 0000000..2a0aa4e
--- /dev/null
+++ b/lapd/L1CTL_Types.ttcn
@@ -0,0 +1,271 @@
+/* Data Types / Encoding / Decoding for OsmocomBB L1CTL interface */
+/* (C) 2017 by Harald Welte <laforge@gnumonks.org>, derived from l1ctl_proto.h
+ * (C) 2010 by Harald Welte + Holger Hans Peter Freyther */
+module L1CTL_Types {
+
+	import from General_Types all;
+	import from GSM_Types all;
+	import from Osmocom_Types all;
+
+	type enumerated L1ctlMsgType {
+		L1CTL_NONE,
+		L1CTL_FBSB_REQ,
+		L1CTL_FBSB_CONF,
+		L1CTL_DATA_IND,
+		L1CTL_RACH_REQ,
+		L1CTL_DM_EST_REQ,
+		L1CTL_DATA_REQ,
+		L1CTL_RESET_IND,
+		L1CTL_PM_REQ,		/* power measurement */
+		L1CTL_PM_CONF,		/* power measurement */
+		L1CTL_ECHO_REQ,
+		L1CTL_ECHO_CONF,
+		L1CTL_RACH_CONF,
+		L1CTL_RESET_REQ,
+		L1CTL_RESET_CONF,
+		L1CTL_DATA_CONF,
+		L1CTL_CCCH_MODE_REQ,
+		L1CTL_CCCH_MODE_CONF,
+		L1CTL_DM_REL_REQ,
+		L1CTL_PARAM_REQ,
+		L1CTL_DM_FREQ_REQ,
+		L1CTL_CRYPTO_REQ,
+		L1CTL_SIM_REQ,
+		L1CTL_SIM_CONF,
+		L1CTL_TCH_MODE_REQ,
+		L1CTL_TCH_MODE_CONF,
+		L1CTL_NEIGH_PM_REQ,
+		L1CTL_NEIGH_PM_IND,
+		L1CTL_TRAFFIC_REQ,
+		L1CTL_TRAFFIC_CONF,
+		L1CTL_TRAFFIC_IND
+	} with { variant "FIELDLENGTH(8)" };
+
+	type enumerated L1ctlCcchMode {
+		CCCH_MODE_NONE (0),
+		CCCH_MODE_NON_COMBINED,
+		CCCH_MODE_COMBINED
+	} with { variant "FIELDLENGTH(8)" };
+
+	type enumerated L1ctlNeighMode {
+		NEIGH_MODE_NONE (0),
+		NEIGH_MODE_PM,
+		NEIGH_MODE_SB
+	} with { variant "FIELDLENGTH(8)" };
+
+	type enumerated L1ctlResetType {
+		L1CTL_RES_T_BOOT (0),
+		L1CTL_RES_T_FULL,
+		L1CTL_RES_T_SCHED
+	} with { variant "FIELDLENGTH(8)" };
+
+	const integer TRAFFIC_DATA_LEN := 40;
+
+	type record L1ctlHdrFlags {
+		BIT7	padding,
+		boolean f_done
+	} with { variant "" };
+
+	type record L1ctlHeader {
+		L1ctlMsgType	msg_type,
+		L1ctlHdrFlags	flags,
+		OCT2		padding
+	} with { variant "" };
+
+	type uint8_t RslChanNr;
+	type uint8_t RslLinkId;
+
+	type record L1ctlDlInfo {
+		RslChanNr	chan_nr,
+		RslLinkId	link_id,
+		Arfcn		arfcn,
+		GsmFrameNumber	frame_nr,
+		GsmRxLev	rx_level,
+		uint8_t		snr,
+		uint8_t		num_biterr,
+		uint8_t		fire_crc
+	} with { variant "" };
+
+	type record L1ctlFbsbConf {
+		int16_t		initial_freq_err,
+		uint8_t		result,
+		uint8_t		bsic
+	} with { variant "" };
+
+	type record L1ctlCcchModeConf {
+		L1ctlCcchMode	ccch_mode,
+		OCT3		padding
+	} with { variant "" };
+
+	/* gsm48_chan_mode */
+	type uint8_t L1ctlTchMode;
+
+	type record L1ctlAudioMode {
+		BIT4		padding,
+		boolean		tx_microphone,
+		boolean		tx_traffic_req,
+		boolean		rx_speaker,
+		boolean		rx_traffic_ind
+	} with { variant "" };
+
+	type record L1ctlTchModeConf {
+		L1ctlTchMode	tch_mode,
+		L1ctlAudioMode	audio_mode,
+		OCT2		padding
+	} with { variant "" };
+
+	type record L1ctlDataInd {
+		octetstring	payload length(23)
+	} with { variant "" };
+
+	type union L1ctlDlPayload {
+		L1ctlFbsbConf		fbsb_conf,
+		L1ctlCcchModeConf	ccch_mode_conf,
+		L1ctlTchModeConf	tch_mode_conf,
+		L1ctlDataInd		data_ind,
+		L1ctlTrafficReq		traffic_ind,
+		octetstring		other
+	} with { variant "" };
+
+	type record L1ctlDlMessage {
+		L1ctlHeader	header,
+		L1ctlDlInfo	dl_info optional,
+		L1ctlDlPayload	payload
+	} with { variant (dl_info) "PRESENCE(header.msg_type = L1CTL_FBSB_CONF,
+					     header.msg_type = L1CTL_RACH_CONF,
+					     header.msg_type = L1CTL_DATA_IND,
+					     header.msg_type = L1CTL_DATA_CONF,
+					     header.msg_type = L1CTL_TRAFFIC_IND)"
+		 variant (payload) "CROSSTAG(fbsb_conf, header.msg_type = L1CTL_FBSB_CONF;
+					     ccch_mode_conf, header.msg_type = L1CTL_CCCH_MODE_CONF;
+					     tch_mode_conf, header.msg_type = L1CTL_TCH_MODE_CONF;
+					     data_ind, header.msg_type = L1CTL_DATA_IND;
+					     traffic_ind, header.msg_type = L1CTL_TRAFFIC_IND;
+					     other, OTHERWISE;
+				)" };
+
+	external function enc_L1ctlDlMessage(in L1ctlDlMessage msg) return octetstring
+		with { extension "prototype(convert) encode(RAW)" };
+	external function dec_L1ctlDlMessage(in octetstring stream) return L1ctlDlMessage
+		with { extension "prototype(convert) decode(RAW)" };
+
+
+	type record L1ctlUlInfo {
+		RslChanNr	chan_nr,
+		RslLinkId	link_id,
+		OCT2		padding
+	} with { variant "" };
+
+	type record L1ctlFbsbFlags {
+		BIT5		padding,
+		boolean		sb,
+		boolean		fb1,
+		boolean		fb0
+	} with { variant "" };
+
+	type record L1ctlFbsbReq {
+		Arfcn		arfcn,
+		uint16_t	timeout_tdma_frames,
+		uint16_t	freq_err_thresh1,
+		uint16_t	freq_err_thresh2,
+		uint8_t		num_freqerr_avg,
+		L1ctlFbsbFlags	flags,
+		uint8_t		sync_info_idx,
+		L1ctlCcchMode	ccch_mode,
+		GsmRxLev	rxlev_exp
+	} with { variant "" };
+
+	type record L1ctlCcchModeReq {
+		L1ctlTchMode	tch_mode,
+		L1ctlAudioMode	audio_mode,
+		OCT2		padding
+	} with { variant "" };
+
+	type record L1ctlTchModeReq {
+		L1ctlTchMode	tch_mode,
+		L1ctlAudioMode	audio_mode,
+		OCT2		padding
+	} with { variant "" };
+
+	type record L1ctlRachReq {
+		uint8_t		ra,
+		uint8_t		combined,
+		uint16_t	offset
+	} with { variant "" };
+
+	type record L1ctlParReq {
+		int8_t		ta,
+		uint8_t		tx_power,
+		OCT2		padding
+	} with { variant "" };
+
+	type record L1ctlH1 {
+		uint8_t		hsn,
+		uint8_t		maio,
+		uint8_t		n,
+		OCT1		padding,
+		bitstring	ma length(64)
+	} with { variant "" };
+
+	type record L1ctlDmEstReq {
+		GsmTsc		tsc,
+		uint8_t		h,
+		Arfcn		arfcn optional,
+		L1ctlH1		hopping optional,
+		L1ctlTchMode	tch_mode,
+		L1ctlAudioMode	audio_mode
+	} with { variant (arfcn) "PRESENCE(h = 0)"
+		 variant (hopping) "PRESENCE(h = 1)" };
+
+	type record L1ctlReset {
+		L1ctlResetType	reset_type,
+		OCT3		padding
+	} with { variant "" };
+
+
+	type record L1ctlTrafficReq {
+		octetstring	data length(TRAFFIC_DATA_LEN)
+	} with { variant "" };
+
+	type union L1ctlUlPayload {
+		L1ctlFbsbReq		fbsb_req,
+		L1ctlCcchModeReq	ccch_mode_req,
+		L1ctlTchModeReq		tch_mode_req,
+		L1ctlRachReq		rach_req,
+		L1ctlParReq		par_req,
+		L1ctlDmEstReq		dm_est_req,
+		L1ctlReset		reset_req,
+		//L1ctlNeighPmReq		neigh_pm_req,
+		L1ctlTrafficReq		traffic_req,
+		octetstring		other
+	} with { variant "" };
+
+	type record L1ctlUlMessage {
+		L1ctlHeader	header,
+		L1ctlUlInfo	ul_info optional,
+		L1ctlUlPayload	payload
+	} with { variant (ul_info) "PRESENCE(header.msg_type = L1CTL_RACH_REQ,
+					     header.msg_type = L1CTL_PARAM_REQ,
+					     header.msg_type = L1CTL_CRYPTO_REQ,
+					     header.msg_type = L1CTL_DATA_REQ,
+					     header.msg_type = L1CTL_DM_EST_REQ,
+					     header.msg_type = L1CTL_DM_FREQ_REQ,
+					     header.msg_type = L1CTL_DM_REL_REQ,
+					     header.msg_type = L1CTL_TRAFFIC_REQ)"
+		 variant (payload) "CROSSTAG(fbsb_req, header.msg_type = L1CTL_FBSB_REQ;
+					     ccch_mode_req, header.msg_type = L1CTL_CCCH_MODE_REQ;
+					     tch_mode_req, header.msg_type = L1CTL_TCH_MODE_REQ;
+					     rach_req, header.msg_type = L1CTL_RACH_REQ;
+					     par_req, header.msg_type = L1CTL_PARAM_REQ;
+					     dm_est_req, header.msg_type = L1CTL_DM_EST_REQ;
+					     reset_req, header.msg_type = L1CTL_RESET_REQ;
+					     traffic_req, header.msg_type = L1CTL_TRAFFIC_REQ;
+					     other, OTHERWISE;
+				)" };
+
+	external function enc_L1ctlUlMessage(in L1ctlUlMessage msg) return octetstring
+		with { extension "prototype(convert) encode(RAW)" };
+	external function dec_L1ctlUlMessage(in octetstring stream) return L1ctlUlMessage
+		with { extension "prototype(convert) decode(RAW)" };
+
+} with { encode "RAW" };