Add missing BSSGP_Emulation.ttcn file
diff --git a/gprs_gb/BSSGP_Emulation.ttcn b/gprs_gb/BSSGP_Emulation.ttcn
new file mode 100644
index 0000000..25b96cd
--- /dev/null
+++ b/gprs_gb/BSSGP_Emulation.ttcn
@@ -0,0 +1,220 @@
+module BSSGP_Emulation {
+	import from NS_Types all;
+	import from NS_Emulation all;
+	import from BSSGP_Types all;
+	import from BSSGP_Helper_Functions all;
+	import from IPL4asp_Types all;
+
+	type record BssgpStatusIndication {
+		Nsei		nsei,
+		BssgpBvci	bvci,
+		BvcState	state
+	}
+
+	template BssgpStatusIndication t_BssgpStsInd(Nsei nsei, BssgpBvci bvci, BvcState state) := {
+		nsei := nsei,
+		bvci := bvci,
+		state := state
+	}
+
+	type enumerated BvcState {
+		BVC_S_BLOCKED,
+		BVC_S_UNBLOCKED
+	};
+
+	/* port from our (internal) point of view */
+	type port BSSGP_SP_PT message {
+		in	BssgpPdu;
+		out	BssgpPdu,
+			NsStatusIndication,
+			BssgpStatusIndication,
+			ASP_Event;
+	} with { extension "internal" };
+
+	/* port from the user point of view */
+	type port BSSGP_PT message {
+		in	ASP_Event,
+			NsStatusIndication,
+			BssgpStatusIndication,
+			BssgpPdu;
+		out	BssgpPdu;
+	} with { extension "internal" };
+
+	function BssgpStart() runs on BSSGP_CT {
+		f_init();
+		f_ScanEvents();
+	}
+
+	private function f_init() runs on BSSGP_CT {
+		/* Connect the UDP socket */
+		f_change_state(BVC_S_BLOCKED);
+	}
+
+	type component BSSGP_CT {
+		/* UDP port towards the bottom (IUT) */
+		port NS_PT BSCP;
+		/* NS-User SAP towards the user */
+		port BSSGP_SP_PT BSSGP_SP;
+
+		var BvcState g_ptp_bvc_state := BVC_S_BLOCKED;
+		timer g_T1 := 15.0;
+		timer g_T2 := 60.0;
+	}
+
+	modulepar {
+		Nsvci mp_nsei := 2342;
+		Nsvci mp_bvci := 2342;
+		BssgpCellId mp_cellid := { ra_id := { lai := { mcc_mnc := '234F04'H, lac := 200}, rac := 0 }, cell_id := 20960 };
+	};
+
+	function f_BnsUdReq(template BssgpPdu pdu) return NsUnitdataRequest {
+		var NsUnitdataRequest udr := {
+			bvci := mp_bvci,
+			nsei := mp_nsei,
+			/* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an
+			 * unbound integer value." when trying to send the reocrd rather than the octetstring */
+			//sdu := omit,
+			//bssgp := valueof(pdu)
+			sdu := f_BSSGP_compact_len(enc_BssgpPdu(valueof(pdu))),
+			bssgp := omit
+		}
+		return udr;
+	}
+
+	function f_BnsUdInd(template BssgpPdu pdu) return template NsUnitdataIndication {
+		var template NsUnitdataIndication udi := {
+			bvci := mp_bvci,
+			nsei := mp_nsei,
+			sdu := *,
+			bssgp := pdu
+		}
+		return udi;
+	}
+
+	private function f_change_state(BvcState new_state) runs on BSSGP_CT {
+		log("BSSGP State Transition: ", g_ptp_bvc_state, " -> ", new_state);
+		g_ptp_bvc_state := new_state;
+		BSSGP_SP.send(t_BssgpStsInd(mp_nsei, mp_bvci, g_ptp_bvc_state));
+	}
+
+	private function f_sendReset() runs on BSSGP_CT {
+		var BssgpPdu pdu := valueof(t_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, mp_bvci, mp_cellid));
+		log("PDU: ", pdu);
+		log("ENC: ", enc_BssgpPdu(pdu));
+
+		BSCP.send(f_BnsUdReq(pdu));
+		g_T2.start;
+		//f_change_state(BVC_S_WAIT_RESET);
+	}
+
+	private function f_sendUnblock() runs on BSSGP_CT {
+		BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(mp_bvci)));
+		g_T1.start;
+	}
+
+	private function f_sendBlock(BssgpCause cause) runs on BSSGP_CT {
+		BSCP.send(f_BnsUdReq(t_BVC_BLOCK(mp_bvci, cause)));
+		g_T1.start;
+	}
+
+	altstep as_allstate() runs on BSSGP_CT {
+		var NsUnitdataIndication udi;
+		var NsStatusIndication nsi;
+		var ASP_Event evt;
+
+		/* Respond to BLOCK for wrong NSVCI */
+		[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?))) -> value udi {
+			log("Rx BVC-BLOCK for unknown BVCI");
+			/* FIXME */
+		}
+
+		/* Respond to RESET with correct NSEI/NSVCI */
+		[] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, mp_bvci, mp_cellid))) -> value udi {
+			f_change_state(BVC_S_UNBLOCKED);
+			BSCP.send(f_BnsUdReq(t_BVC_RESET_ACK(mp_bvci, mp_cellid)));
+		}
+
+		/* Respond to RESET with wrong NSEI/NSVCI */
+		[] BSCP.receive(f_BnsUdInd(t_BVC_RESET(?, ?, ?))) -> value udi {
+			log("Rx BVC-RESET for unknown BVCI");
+			/* FIXME */
+		}
+
+		/* default case of handling unknown PDUs */
+		[] BSCP.receive(f_BnsUdInd(?)) -> value udi {
+			log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state);
+			BSCP.send(f_BnsUdReq(t_BSSGP_STATUS({
+						t_BSSGP_IE_Cause(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE),
+						t_BSSGP_IE_Bvci(mp_bvci), t_BSSGP_IE_PDU(udi.bssgp)})));
+		}
+		/* Forwarding of ASP_Event and NsStatusIndication to user */
+		[] BSCP.receive(ASP_Event:?) -> value evt { BSSGP_SP.send(evt); }
+		[] BSCP.receive(NsStatusIndication:?) -> value nsi { 
+			/* if we just became NS-unblocked, send a BCC-RESET */
+			if (nsi.old_state != NSE_S_ALIVE_UNBLOCKED and nsi.new_state == NSE_S_ALIVE_UNBLOCKED) {
+				f_sendReset();
+			}
+			BSSGP_SP.send(nsi);
+		}
+	}
+
+	private function f_ScanEvents() runs on BSSGP_CT {
+		var NsUnitdataIndication udi;
+		var BssgpPdu bs_pdu;
+		var default d;
+
+		d := activate(as_allstate());
+
+		while (true) {
+		if (g_ptp_bvc_state == BVC_S_BLOCKED) {
+			alt {
+				[] g_T1.timeout {
+					f_sendUnblock();
+				}
+				[] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(mp_bvci))) {
+					g_T1.stop;
+					f_change_state(BVC_S_UNBLOCKED);
+				}
+			}
+		} else if (g_ptp_bvc_state == BVC_S_UNBLOCKED) {
+			alt {
+				/* bogus unblock, just respond with ACK */
+				[] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(mp_bvci))) -> value udi {
+					BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(mp_bvci)));
+				}
+				/* Respond to BLOCK with BLOCK-ACK + change state */
+				[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(mp_bvci, ?))) -> value udi {
+					BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(mp_bvci)));
+					g_T1.stop;
+					f_change_state(BVC_S_BLOCKED);
+				}
+				[] g_T1.timeout {
+					f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
+				}
+				[] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(mp_bvci))) -> value udi {
+					g_T1.stop;
+					f_change_state(BVC_S_BLOCKED);
+				}
+				[] BSCP.receive(f_BnsUdInd(t_BVC_RESET_ACK(mp_bvci, mp_cellid))) -> value udi {
+					g_T2.stop;
+					f_change_state(BVC_S_UNBLOCKED);
+				}
+				/* BSSGP-UNITDATA PDUs from network to NS-UNITDATA.ind to user */
+				[] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(DL_UNITDATA))) -> value udi {
+					BSSGP_SP.send(udi.bssgp);
+				}
+				[] BSCP.receive(f_BnsUdInd(tr_BSSGP_type(UL_UNITDATA))) -> value udi {
+					BSSGP_SP.send(udi.bssgp);
+				}
+				/* pass virtually any PDU from user to NS-UNITDATA PDU on network */
+				[] BSSGP_SP.receive(BssgpPdu:?) -> value bs_pdu {
+					BSCP.send(f_BnsUdReq(bs_pdu));
+				}
+
+			}
+		}
+
+		} /* while */
+		//deactivate(d);
+	}
+}