/* GPRS RLC/MAC Control Messages as per 3GPP TS 44.060 manually transcribed from the CSN.1 syntax, as no CSN.1
 * tool for Eclipse TITAN could be found.  Implements only the minimum necessary messages for Osmocom teseting
 * purposes. */

/* (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
 * contributions by sysmocom - s.f.m.c. GmbH
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

module RLCMAC_CSN1_Types {
	import from General_Types all;
	import from Osmocom_Types all;
	import from GSM_Types all;
	import from MobileL3_GMM_SM_Types all;

	/* TS 44.060 11.2.0.1 */
	type enumerated RlcmacDlCtrlMsgType {
		PACKET_ACCESS_REJECT		('100001'B),
		PACKET_CELL_CHANGE_ORDER	('000001'B),
		PACKET_DL_ASSIGNMENT		('000010'B),
		PACKET_MEASUREMENT_ORDER	('000011'B),
		PACKET_PAGING_REQUEST		('100010'B),
		PACKET_PDCH_RELEASE		('100011'B),
		PACKET_POLLING_REQUEST		('000100'B),
		PACKET_PWR_CONTROL_TA		('000101'B),
		/* TODO */
		PACKET_TBF_RELEASE		('001000'B),
		PACKET_UL_ACK_NACK		('001001'B),
		PACKET_UL_ASSIGNMENT		('001010'B),
		PACKET_DL_DUMMY_CTRL		('100101'B)
	} with { variant "FIELDLENGTH(6)" };

	/* TS 44.060 11.2.0.2 */
	type enumerated RlcmacUlCtrlMsgType {
		PACKET_CELL_CHANGE_FEATURE	('000000'B),
		PACKET_CONTROL_ACK		('000001'B),
		PACKET_DL_ACK_NACK		('000010'B),
		PACKET_UL_DUMMY_CTRL		('000011'B),
		PACKET_MEASUREMENT_REPORT	('000100'B),
		PACKET_ENH_MEASUREMENT_REPORT	('001010'B),
		PACKET_RESOURCE_REQUEST		('000101'B),
		PACKET_MOBILE_TBF_STATUS	('000110'B),
		PACKET_PSI_STATUS		('000111'B),
		PACKET_EGPRS_DL_ACK_NACK	('001000'B),
		PACKET_PAUSE			('001001'B),
		ADDITIONAL_MS_RA_CAPABILITIES	('001011'B),
		PACKET_CELL_CANGE_NOTIFICATION	('001100'B),
		PACKET_SI_STATUS		('001101'B),
		PACKET_CS_REQUEST		('001110'B),
		MBMS_SERVICE_REQUEST		('001111'B),
		MBMS_DL_ACK_NACK		('010000'B)
	} with { variant "FIELDLENGTH(6)" };

	type enumerated EgprsChCodingCommand {
		CH_CODING_MCS1		('0000'B),
		CH_CODING_MCS2		('0001'B),
		CH_CODING_MCS3		('0010'B),
		CH_CODING_MCS4		('0011'B),
		CH_CODING_MCS5		('0100'B),
		CH_CODING_MCS6		('0101'B),
		CH_CODING_MCS7		('0110'B),
		CH_CODING_MCS8		('0111'B),
		CH_CODING_MCS9		('1000'B),
		CH_CODING_MCS5_7	('1001'B),
		CH_CODING_MCS6_9	('1010'B)
	} with { variant "FIELDLENGTH(4)" };

	/* TS 44.060 Table 12.5.2.1 */
	type enumerated EgprsWindowSize { /* This probably needs to be moved to RLCMAC_CSN1_Types.ttcn */
		EGPRS_WS_64		('00000'B),
		EGPRS_WS_96		('00001'B),
		EGPRS_WS_128		('00010'B),
		EGPRS_WS_160		('00011'B),
		EGPRS_WS_192		('00100'B),
		EGPRS_WS_224		('00101'B),
		EGPRS_WS_256		('00110'B),
		EGPRS_WS_288		('00111'B),
		EGPRS_WS_320		('01000'B),
		EGPRS_WS_352		('01001'B),
		EGPRS_WS_384		('01010'B),
		EGPRS_WS_416		('01011'B),
		EGPRS_WS_448		('01100'B),
		EGPRS_WS_480		('01101'B),
		EGPRS_WS_512		('01110'B),
		EGPRS_WS_544		('01111'B),
		EGPRS_WS_576		('10000'B),
		EGPRS_WS_608		('10001'B),
		EGPRS_WS_640		('10010'B),
		EGPRS_WS_672		('10011'B),
		EGPRS_WS_704		('10100'B),
		EGPRS_WS_736		('10101'B),
		EGPRS_WS_768		('10110'B),
		EGPRS_WS_800		('10111'B),
		EGPRS_WS_832		('11000'B),
		EGPRS_WS_864		('11001'B),
		EGPRS_WS_896		('11010'B),
		EGPRS_WS_928		('11011'B),
		EGPRS_WS_960		('11100'B),
		EGPRS_WS_992		('11101'B),
		EGPRS_WS_1024		('11110'B)
	} with { variant "FIELDLENGTH(5)" };

	type record NullGlobalTfi {
		BIT1			presence ('0'B),
		GlobalTfi		global_tfi
	} with { variant "" };

	type record TenTlli {
		BIT2			presence ('10'B),
		GprsTlli		tlli
	} with { variant ""
		variant (tlli) "BYTEORDER(first)"
	};

	type union GlobalTfiOrTlli {
		NullGlobalTfi		global_tfi,
		TenTlli			tlli
	};

	/* 11.2.7 Packet Downlink Assignment */
	type record PacketDlAssignment {
		PageMode		page_mode,
		BIT1			pres1,
		PersistenceLevels	persistence_levels optional,
		GlobalTfiOrTlli		tfi_or_tlli,
		BIT1			egprs2('0'B), /* TODO: implement union with egprs2 */
		BIT2			mac_mode,
		BIT1			rlc_mode,
		BIT1			control_ack,
		BIT8			timeslot_alloc,
		PacketTimingAdvance	pkt_ta,
		BIT1			p0_present,
		uint4_t			p0 optional,
		BIT1			reserved('0'B) optional,
		BIT1			pr_mode optional,
		BIT1			freq_par_present,
		FrequencyParameters	freq_par optional,
		BIT1			dl_tfi_ass_present,
		uint5_t			dl_tfi_assignment optional,
		BIT1			pwr_ctrl_present,
		PowerControlParameters	pwr_ctrl optional,
		BIT1			tbf_starting_time_present,
		StartingFnDesc		tbf_starting_time optional,
		/* The value '1' was allocated in an earlier version of the protocol */
		BIT1			spare ('0'B),
		/* Rel-{99,5,6,7,9,10,12,14} Additions (Matrioshka) */
		PktDlAssRelAdditions	rel_additions optional
	} with {
		variant (persistence_levels) "PRESENCE(pres1 = '1'B)"
		variant (p0) "PRESENCE(p0_present = '1'B)"
		variant (reserved) "PRESENCE(p0_present = '1'B)"
		variant (pr_mode) "PRESENCE(p0_present = '1'B)"
		variant (freq_par) "PRESENCE(freq_par_present = '1'B)"
		variant (dl_tfi_assignment) "PRESENCE(dl_tfi_ass_present = '1'B)"
		variant (pwr_ctrl) "PRESENCE(pwr_ctrl_present = '1'B)"
		variant (tbf_starting_time) "PRESENCE(tbf_starting_time_present = '1'B)"
	};

	private type record PktDlAssRelAdditions {
		BIT1			rel99_presence, // 0/1
		PktDlAssR99Additions	rel99 optional
	} with {
		variant (rel99) "PRESENCE(rel99_presence = '1'B)"
	};

	private type record PktDlAssR99Additions {
		BIT1			egprs_present,
		PktDlAssR99EGPRS	egprs optional,
		BIT1			pkt_ext_ta_present,
		BIT2			pkt_ext_ta optional,
		BIT1			compact_reduced_ma_present,
		COMPACTreducedMA	compact_reduced_ma optional
		/* TODO: Additions for REL-5 */
	} with {
		variant (egprs) "PRESENCE(egprs_present = '1'B)"
		variant (pkt_ext_ta) "PRESENCE(pkt_ext_ta_present = '1'B)"
		variant (compact_reduced_ma) "PRESENCE(compact_reduced_ma_present = '1'B)"
	};

	private type record PktDlAssR99EGPRS {
		EgprsWindowSize		window_size,
		BIT2			link_quality_meas_mode,
		BIT1			bep_period2_present,
		BIT4			bep_period2 optional
	} with {
		variant (bep_period2) "PRESENCE(bep_period2_present = '1'B)"
	};

	/* 11.2.29 Packet Uplink Assignment */
	type record O_Gtfi {
		BIT1			presence ('0'B),
		GlobalTfi		global_tfi
	} with { variant "" };
	type record IO_Tlli {
		BIT2			presence ('10'B),
		GprsTlli		tlli
	} with { variant ""
		variant (tlli) "BYTEORDER(first)"
	};
	type record IIO_Tqi {
		BIT3			presence ('110'B),
		PacketRequestReference	pkt_req_ref
	} with { variant "" };
	type union PktUlAssUnion {
		O_Gtfi			global_tfi,
		IO_Tlli			tlli,
		IIO_Tqi			tqi
	} with {
		variant "TAG(global_tfi, presence = '0'B;
			     tlli, presence = '10'B;
			     tqi, presence = '110'B)"
	};
	type record DynamicAllocation {
		BIT1			extd_dyn_alloc,
		BIT1			p0_present,
		uint4_t			p0 optional,
		BIT1			pr_mode optional,
		BIT1			usf_granularity,
		BIT1			ul_tfi_ass_present,
		uint5_t			ul_tfi_assignment optional,
		BIT1			reserved ('0'B),
		BIT1			tbf_starting_time_present,
		StartingFnDesc		tbf_starting_time optional,
		TsAllocationUnion	ts_allocation
	} with {
		variant (p0)		"PRESENCE(p0_present = '1'B)"
		variant (pr_mode)	"PRESENCE(p0_present = '1'B)"
		variant (ul_tfi_assignment) "PRESENCE(ul_tfi_ass_present = '1'B)"
		variant (tbf_starting_time) "PRESENCE(tbf_starting_time_present = '1'B)"
	};
	type record TsAllocationTs {
		BIT1			presence,
		uint3_t			usf_tn optional
	} with {
		variant (usf_tn) "PRESENCE(presence = '1'B)"
	};
	type record length(8) of TsAllocationTs TsAllocationTsArr;
	type record TnGamma {
		BIT1			presence,
		uint3_t			usf_tn optional,
		uint5_t			gamma_tn optional
	} with {
		variant (usf_tn)	"PRESENCE(presence = '1'B)"
		variant (gamma_tn)	"PRESENCE(presence = '1'B)"
	};
	type record length(8) of TnGamma TnGamma8;
	type record TsAllocationPwr {
		uint4_t			alpha,
		TnGamma			tn_gamma
	} with { variant "" };
	type record TsAllocationUnion {
		BIT1			presence,
		TsAllocationTsArr	ts optional,
		TsAllocationPwr	ts_with_pwr optional
	} with {
		variant (ts)		"PRESENCE(presence = '0'B)"
		variant (ts_with_pwr)	"PRESENCE(presence = '1'B)"
	};
	type record SingleBlockAllocation {
		uint3_t			timeslot_nr,
		BIT1			alpha_present,
		uint4_t			alpha optional,
		uint5_t			gamma_tn,
		BIT1			p0_present,
		uint4_t			p0 optional,
		BIT1			reserved ('0'B) optional,
		BIT1			pr_mode optional,
		StartingFnDesc		tbf_starting_time
	} with {
		variant (alpha)		"PRESENCE(alpha_present = '1'B)"
		variant (p0)		"PRESENCE(p0_present = '1'B)"
		variant (reserved)	"PRESENCE(p0_present = '1'B)"
		variant (pr_mode)	"PRESENCE(p0_present = '1'B)"
	};
	type record PktUlAssGprs {
		ChCodingCommand		ch_coding_cmd,
		BIT1			tlli_block_chan_coding,
		PacketTimingAdvance	pkt_ta,
		BIT1			freq_par_present,
		FrequencyParameters	freq_par optional,
		BIT2			alloc_present,
		DynamicAllocation	dyn_block_alloc optional,
		SingleBlockAllocation	sgl_block_alloc optional
	} with {
		variant (freq_par) "PRESENCE(freq_par_present = '1'B)"
		variant (dyn_block_alloc) "PRESENCE(alloc_present = '01'B)"
		variant (sgl_block_alloc) "PRESENCE(alloc_present = '10'B)"
	};
	type record COMPACTreducedMA {
		uint7_t		ma_bitmap_length,
		bitstring	ma_bitmap,
		BIT1		maio_2_present,
		BIT6		maio_2 optional
	} with {
		variant (ma_bitmap_length) "LENGTHTO (ma_bitmap)"
		variant (ma_bitmap_length) "UNIT(bits)"
		variant (maio_2) "PRESENCE(maio_2_present = '1'B)"
	};
	type record of AccessTechnologiesRequest AccessTechnologiesRequestRepetition
	with { variant "EXTENSION_BIT(reverse)" };
	type record AccessTechnologiesRequest
	{
		BIT4	accessTechnType,
		BIT1    extensionBit
	} with { variant "FIELDORDER(msb)" };
	type record MultiBlockAllocation {
		uint3_t			timeslot_nr,
		BIT1			alpha_gamma_present,
		uint4_t			alpha optional,
		uint5_t			gamma_tn optional,
		BIT1			p0_present,
		uint4_t			p0 optional,
		BIT1			reserved ('0'B) optional,
		BIT1			pr_mode optional,
		StartingFnDesc		tbf_starting_time,
		uint2_t			num_radio_blocks_alloc
	} with {
		variant (alpha)		"PRESENCE(alpha_gamma_present = '1'B)"
		variant (gamma_tn)	"PRESENCE(alpha_gamma_present = '1'B)"
		variant (p0)		"PRESENCE(p0_present = '1'B)"
		variant (reserved)	"PRESENCE(p0_present = '1'B)"
		variant (pr_mode)	"PRESENCE(p0_present = '1'B)"
	};
	type record PktUlAssEgprs {
		BIT2			dual_carrier('00'B), /*TODO 01       -- Message escape for dual carrier, RTTI, BTTI with FANR activated, EGPRS2 */
		BIT1			tlli_present,
		GprsTlli		tlli optional,
		BIT1			compact_reduced_ma_present,
		COMPACTreducedMA	compact_reduced_ma optional,
		EgprsChCodingCommand	chan_coding_cmd,
		BIT1			resegment,
		EgprsWindowSize		window_size,
		BIT1			ats_present,
		AccessTechnologiesRequestRepetition ats optional, /* ? */
		BIT1			arac_retrans_req,
		BIT1			tlli_block_chan_coding,
		BIT1			bep_period2_present,
		BIT4			bep_period2 optional,
		PacketTimingAdvance	pkt_ta,
		BIT1			pkt_ext_ta_present,
		BIT2			pkt_ext_ta optional,
		BIT1			freq_par_present,
		FrequencyParameters	freq_par optional,
		BIT2			alloc_present,
		DynamicAllocation	dyn_block_alloc optional,
		MultiBlockAllocation	multi_block_alloc optional
		/* TODO: Additions for Rel-5  and more */
	} with {
		variant (tlli) "PRESENCE(tlli_present = '1'B)"
		variant (compact_reduced_ma) "PRESENCE(compact_reduced_ma_present = '1'B)"
		variant (ats) "PRESENCE(ats_present = '1'B)"
		variant (bep_period2) "PRESENCE(bep_period2_present = '1'B)"
		variant (pkt_ext_ta) "PRESENCE(pkt_ext_ta_present = '1'B)"
		variant (freq_par) "PRESENCE(freq_par_present = '1'B)"
		variant (dyn_block_alloc) "PRESENCE(alloc_present = '01'B)"
		variant (multi_block_alloc) "PRESENCE(alloc_present = '10'B)"
	};
	type record PacketUlAssignment {
		PageMode		page_mode,
		BIT1			persistence_levels_present,
		PersistenceLevels	persistence_levels optional,
		PktUlAssUnion		identity,
		BIT1			is_egprs,	/* msg escape */
		PktUlAssGprs		gprs optional,
		PktUlAssEgprs		egprs optional
		/* TODO: Table 11.2.29.1: PACKET UPLINK ASSIGNMENT information elements
			https://www.etsi.org/deliver/etsi_ts/144000_144099/144060/09.03.00_60/ts_144060v090300p.pdf */
	} with {
		variant (persistence_levels) "PRESENCE(persistence_levels_present = '1'B)"
		variant (gprs) "PRESENCE(is_egprs = '0'B)"
		variant (egprs) "PRESENCE(is_egprs = '1'B)"
	};

	/* 11.2.10 Packet Paging Request */
	type record MobileIdentityLV_Paging {
		/* Note that the size of 'len' differs from that of the Mobile Identify IE
		 * as defined in 3GPP TS 24.008 10.5.1.4 "Mobile Identity"; Paging Requests
		 * use only 4 bit to encode the length of a mobile identity, whereas the IE
		 * uses a byte. */
		uint4_t			len,
		octetstring		mobile_id
	} with {
		variant (len) "LENGTHTO(mobile_id)"
		variant (mobile_id) "BYTEORDER(first)"
	};
	type record PageInfoPs {
		BIT1			presence ('0'B),
		BIT1			ptmsi_or_mobile_id,
		GsmTmsi			ptmsi optional,
		MobileIdentityLV_Paging	mobile_identity optional
	} with {
		variant (ptmsi) "PRESENCE(ptmsi_or_mobile_id = '0'B)"
		variant (mobile_identity) "PRESENCE(ptmsi_or_mobile_id = '1'B)"
	};
	type record PageInfoCs {
		BIT1			presence ('1'B),
		BIT1			tmsi_or_mobile_id,
		GsmTmsi			tmsi optional,
		MobileIdentityLV_Paging	mobile_identity optional,
		ChannelNeeded		chan_needed,
		BIT1			emlpp_prio_present,
		uint3_t			emlpp_prio optional
	} with {
		variant (tmsi) "PRESENCE(tmsi_or_mobile_id = '0'B)"
		variant (mobile_identity) "PRESENCE(tmsi_or_mobile_id = '1'B)"
		variant (emlpp_prio) "PRESENCE(emlpp_prio_present = '1'B)"
	};
	type union PageInfo {
		PageInfoPs		ps,
		PageInfoCs		cs
	} with {
		variant "TAG(ps, presence = '0'B; cs, presence = '1'B)"
	};
	type record PacketPagingReq {
		PageMode		page_mode,
		BIT1			persistence_levels_present,
		PersistenceLevels	persistence_levels optional,
		BIT1			nln_present,
		uint2_t			nln optional,
		BIT1			repeated_pageinfo_present,
		PageInfo		repeated_pageinfo optional
	} with {
		variant (persistence_levels) "PRESENCE(persistence_levels_present = '1'B)"
		variant (nln) "PRESENCE(nln_present = '1'B)"
		variant (repeated_pageinfo) "PRESENCE(repeated_pageinfo_present = '1'B)"
	};

	/* 12.26 Extension Bits IE  */
	type record ExtensionBits {
		uint6_t		extension_length,
		bitstring	spare_bits
	} with {
		variant (extension_length) "LENGTHTO(spare_bits) - 1"
		variant (extension_length) "UNIT(bits)"
	};

	/* 11.2.28 Uplink Ack/Nack */
	type enumerated ChCodingCommand {
		CH_CODING_CS1		('00'B),
		CH_CODING_CS2		('01'B),
		CH_CODING_CS3		('10'B),
		CH_CODING_CS4		('11'B)
	} with { variant "FIELDLENGTH(2)" };
	type record UlAckNackGprsAdditionsRel99 {
		BIT1			ext_pkt_ta_present,
		BIT2			ext_pkt_ta optional,
		boolean			tbf_est
		/* TODO: Rel5 ,... */
	} with {
		variant (ext_pkt_ta)	"PRESENCE(ext_pkt_ta_present = '1'B)"
		variant (tbf_est) 	"FIELDLENGTH(1)"
	};
	type record UlAckNackGprs {
		ChCodingCommand		ch_coding_cmd,
		AckNackDescription	ack_nack_desc,
		BIT1			cont_res_tlli_present,
		GprsTlli		cont_res_tlli optional,
		BIT1			pkt_ta_present,
		PacketTimingAdvance	pkt_ta optional,
		BIT1			pwr_ctrl_present,
		PowerControlParameters	pwr_ctrl optional,
		BIT1			extension_bits_present,
		ExtensionBits		extension_bits optional,
		BIT1			not_used ('0'B),
		BIT1				rel99_present,
		UlAckNackGprsAdditionsRel99	rel99 optional
	} with {
		variant (cont_res_tlli)	"PRESENCE(cont_res_tlli_present = '1'B)"
		variant (pkt_ta)	"PRESENCE(pkt_ta_present = '1'B)"
		variant (pwr_ctrl)	"PRESENCE(pwr_ctrl_present = '1'B)"
		variant (extension_bits) "PRESENCE(extension_bits_present = '1'B)"
		variant (rel99)		"PRESENCE(rel99_present = '1'B)"
		variant (cont_res_tlli) "BYTEORDER(first)"
	};
	type record UlAckNackEgprs {
		EgprsChCodingCommand	ch_coding_cmd,
		BIT1			resegment,
		BIT1			preemptive_tx,
		BIT1			prr_retrans_req,
		BIT1			arac_retrans_req,
		BIT1			cont_res_tlli_present,
		GprsTlli		cont_res_tlli optional,
		BIT1			tbf_est,
		BIT1			pkt_ta_present,
		PacketTimingAdvance	pkt_ta optional,
		BIT1			pkt_ext_ta_present,
		BIT2			pkt_ext_ta optional,
		BIT1			pwr_ctrl_present,
		PowerControlParameters	pwr_ctrl optional
		/* TODO: TS 44.060 12.3.1  EGPRS Ack/Nack Description */
		/* EgprsAckNackDescription	ack_nack_desc, */
		/* BIT1			not_used('0'B) */
		/* TODO: Extension Bits, Rel5 ,... */
	} with {
		variant (cont_res_tlli)	"PRESENCE(cont_res_tlli_present = '1'B)"
		variant (pkt_ta)	"PRESENCE(pkt_ta_present = '1'B)"
		variant (pkt_ext_ta)	"PRESENCE(pkt_ext_ta_present = '1'B)"
		variant (pwr_ctrl)	"PRESENCE(pwr_ctrl_present = '1'B)"
		variant (cont_res_tlli) "BYTEORDER(first)"
	};
	type record PacketUlAckNack {
		PageMode		page_mode,
		BIT2			msg_excape ('00'B),
		uint5_t			uplink_tfi,
		BIT1			is_egprs,
		UlAckNackGprs		gprs optional,
		UlAckNackEgprs		egprs optional
		/* TODO: EGPRS */
	} with {
		variant (gprs) "PRESENCE(is_egprs = '0'B)"
		variant (egprs) "PRESENCE(is_egprs = '1'B)"
	};

	/* 11.2.8 Packet Downlink Dummy Control Block */
	type record PacketDlDummy {
		PageMode		page_mode,
		BIT1			persistence_levels_present,
		PersistenceLevels	persistence_levels optional
	} with {
		variant (persistence_levels) "PRESENCE(persistence_levels_present = '1'B)"
	};

	/* 11.9 Global Power Control Parameters */
	type record GlobalPwrCtrlParams {
		uint4_t			alpha,
		uint5_t			t_avg_v,
		uint5_t			t_avg_t,
		uint4_t			pb,
		BIT1			pc_meas_chan,
		BIT1			spare ('0'B),
		uint4_t			n_avg_i
	};

	/* 12.12a Global Packet Timing Advance */
	type record TimingAdvanceIdxTN {
		uint4_t			ta_idx,
		uint3_t			ts_num
	};
	type record GlobalPacketTA {
		BIT1			ta_val_presence,
		uint4_t			ta_val optional,
		BIT1			ul_presence,
		TimingAdvanceIdxTN	ul optional,
		BIT1			dl_presence,
		TimingAdvanceIdxTN	dl optional
	} with {
		variant (ta_val) "PRESENCE(ta_val_presence = '1'B)"
		variant (ul) "PRESENCE(ul_presence = '1'B)"
		variant (dl) "PRESENCE(dl_presence = '1'B)"
	};

	/* 11.2.13 Packet Power Control/Timing Advance */
	type record PacketPwrControlTAMsg {
		BIT1			g_pwr_ctrl_presence,
		GlobalPwrCtrlParams	g_pwr_ctrl optional,
		BIT1			split,
		BIT1			split_desc optional,
		GlobalPacketTA		g_pkt_ta optional,
		PowerControlParameters	pwr_ctrl optional
		/* TODO: additions for R99, REL-7, REL-12 */
	} with {
		variant (g_pwr_ctrl) "PRESENCE(g_pwr_ctrl_presence = '1'B)"
		variant (split_desc) "PRESENCE(split = '1'B)"
		/* FIXME: Fancy coding: either both IEs together, or one of them */
		variant (g_pkt_ta) "PRESENCE(split = '0'B, split_desc = '0'B)"
		variant (pwr_ctrl) "PRESENCE(split = '0'B, split_desc = '1'B)"
	};
	type record PacketPwrControlTA {
		PageMode		page_mode,
		NullGlobalTfi		global_tfi,
		/* See 11.1.3.3 'Message escape' error label
		 * 0 < Message body > ! < Message escape : 1 bit (*) = <no string> > */
		BIT1			msg_escape,
		PacketPwrControlTAMsg	msg optional
	} with {
		variant (msg) "PRESENCE(msg_escape = '0'B)"
	};

	/* 11.2.0.1 */
	type union RlcmacDlCtrlUnion {
		PacketDlAssignment	dl_assignment,
		PacketUlAssignment	ul_assignment,
		PacketPagingReq		paging,
		PacketUlAckNack		ul_ack_nack,
		PacketDlDummy		dl_dummy,
		PacketPwrControlTA	pwr_ta,
		octetstring		other
	} with { variant "" };

	type record RlcmacDlCtrlMsg {
		RlcmacDlCtrlMsgType	msg_type,
		RlcmacDlCtrlUnion	u
	} with {
		variant (u) "CROSSTAG(dl_assignment,	msg_type = PACKET_DL_ASSIGNMENT;
				      ul_assignment,	msg_type = PACKET_UL_ASSIGNMENT;
				      paging,		msg_type = PACKET_PAGING_REQUEST;
				      ul_ack_nack,	msg_type = PACKET_UL_ACK_NACK;
				      dl_dummy,		msg_type = PACKET_DL_DUMMY_CTRL;
				      pwr_ta,		msg_type = PACKET_PWR_CONTROL_TA;
				      other,		OTHERWISE
			)"
	};

	external function enc_RlcmacDlCtrlMsg(in RlcmacDlCtrlMsg si) return octetstring
		with { extension "prototype(convert) encode(RAW)" };
	external function dec_RlcmacDlCtrlMsg(in octetstring stream) return RlcmacDlCtrlMsg
		with { extension "prototype(convert) decode(RAW)" };


	/* 11.2.6 Packet Downlikn Ack/Nack */
	type record ILevel {
		BIT1	presence,
		uint4_t	i_level optional
	} with { variant (i_level) "PRESENCE(presence = '1'B)" };
	type record length(8) of ILevel ILevels;
	type record ChannelQualityReport {
		uint6_t			c_value,
		uint3_t			rxqual,
		uint6_t			sign_var,
		ILevels			i_levels
	} with { variant "" };
	type record PacketDlAckNack {
		uint5_t			dl_tfi,
		AckNackDescription	ack_nack_desc,
		BIT1			chreq_desc_presence,
		ChannelReqDescription	chreq_desc optional,
		ChannelQualityReport	ch_qual_rep
	} with { variant "" };

	/* 11.2.2 Packet Control Acknowledgement */
	type enumerated CtrlAck {
		MS_RCVD_TWO_RLC_SAME_RTI_DIFF_RBSN_NEW_TFI	('00'B),
		MS_RCVD_RBSN1_NO_RBSN0				('01'B),
		MS_RCVD_RBSN0_NO_RBSN1				('10'B),
		MS_RCVD_TWO_RLC_SAME_RTI_DIFF_RBSN		('11'B)
	} with { variant "FIELDLENGTH(2)" };
	type record PacketCtrlAck {
		GprsTlli		tlli,
		CtrlAck			ctrl_ack
		/* TODO: Rel5 additions */
	} with { variant ""
		variant (tlli) "BYTEORDER(first)"
	};

	/* 1.2.8b Packet Uplink Dummy Control Block */
	type record PacketUlDummy {
		GprsTlli		tlli
	} with { variant ""
		variant (tlli) "BYTEORDER(first)"
	};

	/* TS 44.060 sec 12.30 MS Radio Access Capability 2
	 * (for value part, see 3GPP TS 24.008 sec 10.5.5.12a and table 10.5.146) */
	type union MSRadioAccCap2 {
		MSRadioAccessCapabilityV     msRadioAccessCapabilityV
	};

	/* Table 11.2.16.2 Access Type */
	type enumerated RlcAccessType {
		RLC_ACC_TYPE_TWO_PHASE		('00'B),
		RLC_ACC_TYPE_PAG_RESPONSE	('01'B),
		RLC_ACC_TYPE_CELL_UPDATE	('10'B),
		RLC_ACC_TYPE_MM			('11'B)
	} with { variant "FIELDLENGTH(2)" };

	type union PacketResourceReqID {
		GlobalTfi gtfi,
		GprsTlli tlli
	} with { variant (tlli) "BYTEORDER(first)" };

	/* 11.2.16 Packet Resource Request */
	type record PacketResourceReq {
		BIT1			acc_type_presence,
		RlcAccessType		acc_type optional,
		BIT1			id_type,
		PacketResourceReqID	id,
		BIT1			ms_rac2_presence,
		MSRadioAccCap2		ms_rac2 optional,
		ChannelReqDescription	ch_req_desc,
		BIT1			change_mark_presence,
		BIT2			change_mark optional,
		BIT6			C_val,
		BIT1			sign_var_presence,
		BIT6			sign_var optional,
		ILevels			I_levels
		/* TODO: additional contents for further Releases (starting from 1999) */
	} with {
		variant (acc_type) "PRESENCE(acc_type_presence = '1'B)"
		variant (id) "CROSSTAG(gtfi, id_type = '0'B; tlli, id_type = '1'B)"
		variant (ms_rac2) "PRESENCE(ms_rac2_presence = '1'B)"
		variant (change_mark) "PRESENCE(change_mark_presence = '1'B)"
		variant (sign_var) "PRESENCE(sign_var_presence = '1'B)"
	};

	/* 11.2.0.2 */
	type union RlcmacUlCtrlUnion {
		PacketCtrlAck		ctrl_ack,
		PacketDlAckNack		dl_ack_nack,
		PacketUlDummy		ul_dummy,
		PacketResourceReq	resource_req,
		octetstring		other
	} with { variant "" };

	type record RlcmacUlCtrlMsg {
		RlcmacUlCtrlMsgType	msg_type,
		RlcmacUlCtrlUnion	u
	} with {
		variant (u) "CROSSTAG(ctrl_ack,		msg_type = PACKET_CONTROL_ACK;
				      dl_ack_nack,	msg_type = PACKET_DL_ACK_NACK;
				      ul_dummy,		msg_type = PACKET_UL_DUMMY_CTRL;
				      resource_req,	msg_type = PACKET_RESOURCE_REQUEST;
				      other,		OTHERWISE
			)"
	};

	external function enc_RlcmacUlCtrlMsg(in RlcmacUlCtrlMsg si) return octetstring
		with { extension "prototype(convert) encode(RAW)" };
	external function dec_RlcmacUlCtrlMsg(in octetstring stream) return RlcmacUlCtrlMsg
		with { extension "prototype(convert) decode(RAW)" };

	type bitstring ReceivedBlockBitmap length(64) with { variant "BYTEORDER(last)" };

	/* 12.3 Ack/Nack Description */
	type record AckNackDescription {
		BIT1			final_ack,
		uint7_t			starting_seq_nr,
		ReceivedBlockBitmap	receive_block_bitmap
	} with { variant "" };

	/* 12.7 Channel Request Description */
	type enumerated RlcMode {
		RLC_MODE_ACKNOWLEDGED	(0),
		RLC_MODE_UNACKNOWLEDGED	(1)
	} with { variant "FIELDLENGTH(1)" };
	type enumerated LlcPduType {
		LLC_PDU_IS_SACK_OR_ACK	(0),
		LLC_PDU_IS_NOT_SACK_OR_ACK (1)
	} with { variant "FIELDLENGTH(1)" };
	type record ChannelReqDescription {
		uint4_t			peak_tput_class,
		uint2_t			priority,
		RlcMode			rlc_mode,
		LlcPduType		llc_pdu_type,
		uint16_t		RlcOctetCount
	} with { variant "" };

	/* 12.8 Frequency Parameters */
	type record FreqIndirect {
		uint6_t			maio,
		uint4_t			ma_number,
		BIT1			change_mark1_present,
		uint2_t			change_mark1 optional,
		BIT1			change_mark2_present,
		uint2_t			change_mark2 optional
	} with {
		variant (change_mark1) "PRESENCE(change_mark1_present = '1'B)"
		variant (change_mark2) "PRESENCE(change_mark2_present = '1'B)"
	};
	type record FreqDirect1 {
		uint6_t			maio,
		GprsMobileAllication	mobile_allocation
	}
	type record FreqDirect2 {
		uint6_t			maio,
		uint6_t			hsn,
		uint4_t			ma_freq_len,
		octetstring		m1_freq_list
	} with {
		variant (ma_freq_len) "LENGTHTO(m1_freq_list)+3"
	};
	type record FrequencyParameters {
		uint3_t			tsc,
		BIT2			presence,
		uint10_t		arfcn optional,
		FreqIndirect		indirect optional,
		FreqDirect1		direct1 optional,
		FreqDirect2		direct2 optional
	} with {
		variant (arfcn) "PRESENCE(presence = '00'B)"
		variant (indirect) "PRESENCE(presence = '01'B)"
		variant (direct1) "PRESENCE(presence = '10'B)"
		variant (direct2) "PRESENCE(presence = '11'B)"
	};

	/* 12.10 Global TFI */
	type record GlobalTfi {
		boolean			is_dl_tfi,
		uint5_t			tfi
	} with { variant (is_dl_tfi) "FIELDLENGTH(1)" };

	/* 12.10a GPRS Mobile Allocation */
	type record RflNumberList {
		uint4_t			rfl_number,
		BIT1			presence,
		RflNumberList		rfl_number_list optional
	} with {
		variant (rfl_number_list) "PRESENCE(presence = '1'B)"
	};
	type record GprsMobileAllication {
		uint6_t			hsn,
		BIT1			rfl_number_list_present,
		RflNumberList		rfl_number_list optional,
		BIT1			ma_present,
		uint6_t			ma_length optional,
		bitstring		ma_bitmap length(1..64) optional
		/* TODO: ARFCN index list */
	} with {
		variant (rfl_number_list) "PRESENCE(rfl_number_list_present = '1'B)"
		variant (ma_length) "PRESENCE(ma_present = '0'B)"
		variant (ma_bitmap) "PRESENCE(ma_present = '0'B)"
		variant (ma_length) "LENGTHTO(ma_bitmap)-1, UNIT(bits)"
		variant (ma_bitmap) "BYTEORDER(first), BITORDER(msb)"
	};

	/* 12.11 Packet Request Reference */
	type record PacketRequestReference {
		uint11_t		ra_info,
		uint16_t		frame_nr
	} with { variant "" };

	/* 12.12 Packet Timing Advance */
	type record PacketTimingAdvance {
		BIT1		val_present,
		uint6_t		val optional,
		BIT1		idx_present,
		uint4_t		idx optional,
		uint3_t		timeslot_nr optional
	} with {
		variant (val) "PRESENCE(val_present = '1'B)"
		variant (idx) "PRESENCE(idx_present = '1'B)"
		variant (timeslot_nr) "PRESENCE(idx_present = '1'B)"
	};

	/* 12.13 Power Control Parameters */
	type record ZeroOneGamma {
		BIT1		gamma_present,
		uint5_t		gamma optional
	} with {
		variant (gamma) "PRESENCE (gamma_present = '1'B)"
	};
	type record length(8) of ZeroOneGamma ZeroOneGammas;
	type record PowerControlParameters {
		uint4_t		alpha,
		ZeroOneGammas	gamma
	} with { variant "" };

	/* 12.14 Persistence Level */
	type record length(4) of uint4_t PersistenceLevels;

	/* 12.20 Page Mode */
	type enumerated PageMode {
		PAGE_MODE_NORMAL	('00'B),
		PAGE_MODE_EXTENDED	('01'B),
		PAGE_MODE_REORG		('10'B),
		PAGE_MODE_SAME		('11'B)
	} with { variant "FIELDLENGTH(2)" };

	/* 12.21 Starting Frame Number */
	type record StartingFnDesc {
		BIT1		presence,
		uint16_t	absolute_starting_time optional,
		uint13_t	relative_k optional
	} with {
		variant (absolute_starting_time) "PRESENCE(presence = '0'B)"
		variant (relative_k) "PRESENCE(presence = '1'B)"
	};

	/* 3GPP TS 44.060, table 11.2.5a.2 "EGPRS PACKET CHANNEL REQUEST" */
	type union EGPRSPktChRequest {
		EGPRSPktChRequest_MC5P2RB3		one_phase,
		EGPRSPktChRequest_NOB3P2RB3		short, // deprecated
		EGPRSPktChRequest_MCG3P2RB3		one_phase_red,
		EGPRSPktChRequest_P2RB3			two_phase,
		EGPRSPktChRequest_RB5			signalling,
		EGPRSPktChRequest_RB5			one_phase_unack,
		EGPRSPktChRequest_RB5			dedicated,
		EGPRSPktChRequest_RB5			emergency,
		EGPRSPktChRequest_P2RB3			two_phase_ipa,
		EGPRSPktChRequest_RB5			signalling_ipa
	} with {
		variant "TAG (
			one_phase,		tag = '0'B;
			short,			tag = '100'B;
			one_phase_red,		tag = '101'B;
			two_phase,		tag = '110000'B;
			signalling,		tag = '110011'B;
			one_phase_unack,	tag = '110101'B;
			dedicated,		tag = '110110'B;
			emergency,		tag = '110111'B;
			two_phase_ipa,		tag = '111000'B;
			signalling_ipa,		tag = '111001'B;
		)"
	};

	private type record EGPRSPktChRequest_MC5P2RB3 {
		BIT1		tag,
		BIT5		multislot_class,
		BIT2		priority,
		BIT3		random_bits
	};

	private type record EGPRSPktChRequest_NOB3P2RB3 {
		BIT3		tag,
		BIT3		nr_of_blocks,
		BIT2		priority,
		BIT3		random_bits
	};

	private type record EGPRSPktChRequest_MCG3P2RB3 {
		BIT3		tag,
		BIT3		multislot_class_group,
		BIT2		priority,
		BIT3		random_bits
	};

	private type record EGPRSPktChRequest_P2RB3 {
		BIT6		tag,
		BIT2		priority,
		BIT3		random_bits
	};

	private type record EGPRSPktChRequest_RB5 {
		BIT6		tag,
		BIT5		random_bits
	};

	/* TITAN violates length restrictions on returned type, so we cannot do '... return BIT11'.
	 * Keep this function private as it returns octet-aligned bitstring (+5 padding bits). */
	private external function enc_EGPRSPktChRequestInternal(in EGPRSPktChRequest req) return bitstring
		with { extension "prototype(convert) encode(RAW)" };

	function enc_EGPRSPktChRequest2bits(in EGPRSPktChRequest req) return BIT11
	{
		var bitstring ra11_pad := enc_EGPRSPktChRequestInternal(req);
		return substr(ra11_pad, 0, 11); /* TITAN adds 5 padding bits */
	}

	function enc_EGPRSPktChRequest2uint(in EGPRSPktChRequest req) return uint16_t
	{
		var BIT11 ra11 := enc_EGPRSPktChRequest2bits(req);
		return bit2int(ra11);
	}


} with { encode "RAW"; variant "FIELDORDER(msb)" variant "BYTEORDER(last)" };
