Add 3GPP TS 25.415 IuUP encoder/decoder

Change-Id: Ie04438d8ec2b796e9e56b1937fa024a5299457dd
diff --git a/library/IuUP_Emulation.ttcn b/library/IuUP_Emulation.ttcn
new file mode 100644
index 0000000..ec25e49
--- /dev/null
+++ b/library/IuUP_Emulation.ttcn
@@ -0,0 +1,137 @@
+module IuUP_Emulation {
+
+import from Osmocom_Types all;
+import from IuUP_Types all;
+
+
+type record IuUP_RabFlowCombination {
+	IuUP_RFCI rfci,
+	/* number of bits per sub-flow */
+	RecOfU8	sub_flow_bits,
+	/* IPTI value in number of ITIs for the corresponding RFCI */
+	uint8_t ipti
+};
+
+template (value) IuUP_RabFlowCombination t_IuUP_RFC(IuUP_RFCI rfci, RecOfU8 subflow_bits, uint8_t ipti) := {
+	rfci := rfci,
+	sub_flow_bits := subflow_bits,
+	ipti := ipti
+}
+
+template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_12_2(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {81, 103, 60}, 1);
+template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_SID(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {34, 0, 0}, 7);
+
+type record IuUP_Config {
+	/* actively send INIT (true) or only passively respond (false) */
+	boolean active_init,
+	boolean data_pdu_type_0,
+	/* RAB Flow Combinations */
+	record of IuUP_RabFlowCombination rab_flow_combs
+};
+
+type enumerated IuUP_Em_State {
+	ST_INIT,
+	ST_DATA_TRANSFER_READY
+};
+
+
+
+type record IuUP_Entity {
+	IuUP_Config cfg,
+	IuUP_Em_State state,
+	IuUP_FrameNr tx_next_frame_nr,
+	IuUP_FrameNr rx_last_frame_nr optional,
+	IuUP_PDU pending_tx_pdu optional
+};
+
+template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := {
+	cfg := {
+		active_init := act_init,
+		data_pdu_type_0 := true,
+		rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1) }
+	},
+	state := ST_INIT,
+	tx_next_frame_nr := 0,
+	rx_last_frame_nr := omit,
+	pending_tx_pdu := omit
+}
+
+
+function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring {
+	var IuUP_PDU pdu := dec_IuUP_PDU(inp);
+	if (ischosen(pdu.type_0)) {
+		if (st.cfg.data_pdu_type_0) {
+			/* FIXME: check header / CRC */
+			st.rx_last_frame_nr := pdu.type_0.frame_nr;
+			return pdu.type_0.payload;
+		} else {
+			setverdict(fail, "PDU Type 0 received but 1 configured");
+		}
+	} else if (ischosen(pdu.type_1)) {
+		if (st.cfg.data_pdu_type_0 == false) {
+			/* FIXME: check header / CRC */
+			st.rx_last_frame_nr := pdu.type_1.frame_nr;
+			return pdu.type_1.payload;
+		} else {
+			setverdict(fail, "PDU Type 1 received but 0 configured");
+		}
+	} else if (ischosen(pdu.type_14)) {
+		if (match(pdu, tr_IuUP_INIT)) {
+			if (st.cfg.active_init == true) {
+				setverdict(fail, "INIT received in ACTIVE role");
+			} else {
+				/* store an INIT_ACK to be transmitted later */
+				st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr,
+									pdu.type_14.iuup_version));
+			}
+		} else if (match(pdu, tr_IuUP_INIT_ACK)) {
+			if (st.cfg.active_init == true) {
+				log("IuUP INIT_ACK Received");
+				st.state := ST_DATA_TRANSFER_READY;
+			} else {
+				setverdict(fail, "INIT_ACK received in PASSIVE role");
+			}
+		}
+		return ''O;
+	} else {
+		setverdict(fail, "Impossible IuUP PDU decoded from ", inp);
+	}
+	self.stop;
+}
+
+function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring {
+	var IuUP_PDU pdu;
+	select (st.state) {
+		case (ST_INIT) {
+			if (st.cfg.active_init) {
+				/* send INIT */
+				pdu := valueof(ts_IuUP_INIT('160051673C01270000820000001710000100'O));
+			} else {
+				/* wait for INIT */
+				if (isvalue(st.pending_tx_pdu)) {
+					/* we're waiting to transmit the INIT_ACK in response to an
+					 * init (passive) */
+					pdu := st.pending_tx_pdu;
+					st.pending_tx_pdu := omit;
+					st.state := ST_DATA_TRANSFER_READY;
+				}
+			}
+		}
+		case (ST_DATA_TRANSFER_READY) {
+			if (st.cfg.data_pdu_type_0) {
+				pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload));
+			} else {
+				pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload));
+			}
+			st.tx_next_frame_nr := st.tx_next_frame_nr + 1;
+		}
+	}
+	if (isvalue(pdu)) {
+		return f_enc_IuUP_PDU(pdu);
+	} else {
+		return ''O;
+	}
+}
+
+
+}