/* 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_Templates {
	import from General_Types all;
	import from Osmocom_Types all;
	import from GSM_Types all;
	import from MobileL3_GMM_SM_Types all;
	import from RLCMAC_CSN1_Types all;

	template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_CTRL_ACK(GprsTlli tlli,
						CtrlAck ack := MS_RCVD_TWO_RLC_SAME_RTI_DIFF_RBSN) := {
		msg_type := PACKET_CONTROL_ACK,
		u := {
			ctrl_ack := {
				tlli := tlli,
				ctrl_ack := ack
			}
		}
	}

	const ILevel iNone := {
		presence := '0'B,
		i_level := omit
	}
	const ChannelQualityReport c_ChQualRep_default := {
		c_value := 0,
		rxqual := 0,
		sign_var := 0,
		i_levels := { iNone, iNone, iNone, iNone, iNone, iNone, iNone, iNone }
	}
	template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_DL_ACK(uint5_t dl_tfi,
								    AckNackDescription andesc,
					ChannelQualityReport qual_rep := c_ChQualRep_default) := {
		msg_type := PACKET_DL_ACK_NACK,
		u := {
			dl_ack_nack := {
				dl_tfi := dl_tfi,
				ack_nack_desc := andesc,
				chreq_desc_presence := '0'B,
				chreq_desc := omit,
				ch_qual_rep := qual_rep
			}
		}
	}

	private function f_presence_bit_MultislotCap_GPRS(template (omit) MultislotCap_GPRS mscap_gprs) return BIT1 {
		if (istemplatekind(mscap_gprs, "omit")) {
			return '0'B;
		}
		return '1'B;
	}
	private function f_presence_bit_MultislotCap_EGPRS(template (omit) MultislotCap_EGPRS mscap_egprs) return BIT1 {
		if (istemplatekind(mscap_egprs, "omit")) {
			return '0'B;
		}
		return '1'B;
	}
	template (value) MSRACapabilityValuesRecord ts_RaCapRec(BIT4 att := '0001'B /* E-GSM */, template (omit) MultislotCap_GPRS mscap_gprs := omit, template (omit) MultislotCap_EGPRS mscap_egprs := omit) := {
		mSRACapabilityValues := {
			mSRACapabilityValuesExclude1111 := {
				accessTechnType := att, /* E-GSM */
				accessCapabilities := {
					lengthIndicator := 0, /* overwritten */
					accessCapabilities := {
						rfPowerCapability := '001'B, /* FIXME */
						presenceBitA5 := '0'B,
						a5bits := omit,
						esind := '1'B,
						psbit := '0'B,
						vgcs := '0'B,
						vbs := '0'B,
						presenceBitMultislot := '1'B,
						multislotcap := {
							presenceBitHscsd := '0'B,
							hscsdmultislotclass := omit,
							presenceBitGprs := f_presence_bit_MultislotCap_GPRS(mscap_gprs),
							gprsmultislot := mscap_gprs,
							presenceBitSms := '0'B,
							multislotCap_SMS := omit,
							multislotCapAdditionsAfterRel97 := {
									presenceBitEcsdmulti := '0'B,
									ecsdmultislotclass := omit,
									presenceBitEgprsmulti := f_presence_bit_MultislotCap_EGPRS(mscap_egprs),
									multislotCap_EGPRS := mscap_egprs,
									presenceBitDtmGprsmulti := '0'B,
									multislotCapdtmgprsmultislotsubclass := omit
							}
						},
						accessCapAdditionsAfterRel97 := omit
					},
					spare_bits := omit
				}
			}
		},
		presenceBitMSRACap := '0'B
	};

	private function f_presence_bit_MSRadioAccessCapabilityV(template (omit) MSRadioAccessCapabilityV ms_rac) return BIT1 {
		if (istemplatekind(ms_rac, "omit")) {
			return '0'B;
		}
		return '1'B;
	}

	private function f_template_MSRadioAccessCapabilityV_to_MSRadioAccCap2(template (omit) MSRadioAccessCapabilityV ms_rac) return template (omit) MSRadioAccCap2 {
		var template (omit) MSRadioAccCap2 ms_rac2 := omit;
		if (istemplatekind(ms_rac, "omit")) {
			return ms_rac2;
		}
		ms_rac2 := { msRadioAccessCapabilityV := ms_rac };
		return ms_rac2;
	}

	const ChannelReqDescription c_ChReqDesc_default := {
		peak_tput_class := 0,
		priority := 0,
		rlc_mode := RLC_MODE_ACKNOWLEDGED,
		llc_pdu_type := LLC_PDU_IS_NOT_SACK_OR_ACK,
		RlcOctetCount := 0
	}

	/* TS 44.060 sec 11.2.16 */
	template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_RES_REQ(GprsTlli tlli,
						     template (omit) MSRadioAccessCapabilityV ms_rac,
						     ChannelReqDescription ch_req_desc := c_ChReqDesc_default,
						     RlcAccessType acc_type := RLC_ACC_TYPE_TWO_PHASE)
	:= {
		msg_type := PACKET_RESOURCE_REQUEST,
		u := {
			resource_req := {
				acc_type_presence := '1'B,
				acc_type := acc_type,
				id_type := '1'B,
				id := { tlli := tlli },
				ms_rac2_presence := f_presence_bit_MSRadioAccessCapabilityV(ms_rac),
				ms_rac2 := f_template_MSRadioAccessCapabilityV_to_MSRadioAccCap2(ms_rac),
				ch_req_desc := ch_req_desc,
				change_mark_presence := '0'B,
				change_mark := omit,
				C_val := '000000'B,
				sign_var_presence := '0'B,
				sign_var := omit,
				I_levels := {
					iNone, iNone, iNone, iNone,
					iNone, iNone, iNone, iNone
				}
			}
		}
	};

	private function f_presence_bit_tfi(template uint5_t tfi) return BIT1 {
		if (istemplatekind(tfi, "omit")) {
			return '0'B;
		}
		return '1'B;
	}

	template DynamicAllocation tr_DynamicAllocation(template uint5_t tfi:= ?) := {
		extd_dyn_alloc := ?,
		p0_present := ?,
		p0 := *,
		pr_mode := *,
		usf_granularity := ?,
		ul_tfi_ass_present := f_presence_bit_tfi(tfi),
		ul_tfi_assignment := tfi,
		reserved := '0'B,
		tbf_starting_time_present := ?,
		tbf_starting_time := *,
		ts_allocation := ?
	};

	template PktUlAssGprs tr_PktUlAssGprsDynamic(template DynamicAllocation dyn_alloc := ?) := {
		ch_coding_cmd := ?,
		tlli_block_chan_coding := ?,
		pkt_ta := ?,
		freq_par_present := ?,
		freq_par := *,
		alloc_present := '01'B,
		dyn_block_alloc := dyn_alloc,
		sgl_block_alloc := omit
	};

	template PktUlAssEgprs tr_PktUlAssEgprsDynamic(template DynamicAllocation dyn_alloc := ?) := {
		dual_carrier := '00'B,
		tlli_present := ?,
		tlli := *,
		compact_reduced_ma_present := ?,
		compact_reduced_ma := *,
		chan_coding_cmd := ?,
		resegment := ?,
		window_size := ?,
		ats_present := ?,
		ats := *, /* ? */
		arac_retrans_req := ?,
		tlli_block_chan_coding := ?,
		bep_period2_present := ?,
		bep_period2 := *,
		pkt_ta := ?,
		pkt_ext_ta_present := ?,
		pkt_ext_ta := *,
		freq_par_present := ?,
		freq_par := *,
		alloc_present := ?,
		dyn_block_alloc := dyn_alloc,
		multi_block_alloc := omit
	};

	template AckNackDescription tr_AckNackDescription(template BIT1 final_ack := ?) := {
		final_ack := final_ack,
		starting_seq_nr := ?,
		receive_block_bitmap := ?
	};

	template UlAckNackGprsAdditionsRel99 tr_UlAckNackGprsAdditionsRel99(template boolean tbf_est := ?) := {
		ext_pkt_ta_present := ?,
		ext_pkt_ta := *,
		tbf_est := tbf_est
	};

	template UlAckNackGprs tr_UlAckNackGprs(template GprsTlli tlli := *,
						template AckNackDescription acknack_desc := ?,
						template UlAckNackGprsAdditionsRel99 rel99 := *) := {
		ch_coding_cmd := ?,
		ack_nack_desc := acknack_desc,
		cont_res_tlli_present := ?,
		cont_res_tlli := tlli,
		pkt_ta_present := ?,
		pkt_ta := *,
		pwr_ctrl_present := ?,
		pwr_ctrl := *,
		extension_bits_present := ?,
		extension_bits := *,
		not_used := '0'B,
		rel99_present := ?,
		rel99 := rel99
	};

	template UlAckNackEgprs tr_UlAckNackEgprs(template GprsTlli tlli := *) := {
		ch_coding_cmd := ?,
		resegment := ?,
		preemptive_tx := ?,
		prr_retrans_req := ?,
		arac_retrans_req := ?,
		cont_res_tlli_present := ?,
		cont_res_tlli := tlli,
		tbf_est := ?,
		pkt_ta_present := ?,
		pkt_ta := *,
		pkt_ext_ta_present := ?,
		pkt_ext_ta := *,
		pwr_ctrl_present := ?,
		pwr_ctrl := *
	};

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