gprs_gb: working Uplink PACKET_CONTROL_ACK against OsmoPCU

Change-Id: I2c7d0eb9371911e28f328caeaed63cb8ec311ac1
diff --git a/library/L1CTL_Types.ttcn b/library/L1CTL_Types.ttcn
index f853057..33a01a8 100644
--- a/library/L1CTL_Types.ttcn
+++ b/library/L1CTL_Types.ttcn
@@ -8,6 +8,8 @@
 	import from GSM_RR_Types all;
 	import from Osmocom_Types all;
 
+	type uint32_t uint32_le with { variant "BYTEORDER(first)" };
+
 	type enumerated L1ctlMsgType {
 		L1CTL_NONE,
 		L1CTL_FBSB_REQ,
@@ -143,7 +145,9 @@
 
 	type record L1ctlDataInd {
 		octetstring	payload length(23)
-	} with { variant "" };
+	} with {
+		variant (payload) "BYTEORDER(first)"
+	};
 
 	type union L1ctlDlPayload {
 		L1ctlFbsbConf		fbsb_conf,
@@ -153,7 +157,9 @@
 		L1ctlTrafficReq		traffic_ind,
 		L1ctlTbfCfgReq		tbf_cfg_conf,
 		octetstring		other
-	} with { variant "" };
+	} with {
+		variant (other) "BYTEORDER(first)"
+	};
 
 	type record L1ctlDlMessage {
 		L1ctlHeader	header,
@@ -196,7 +202,7 @@
 		L1ctlGprsCs	cs,
 		uint8_t		ts_nr,
 		OCT1		padding,
-		uint32_t	fn,
+		uint32_le	fn,
 		Arfcn		arfcn,
 		OCT2		padding2
 	} with { variant "" };
@@ -277,7 +283,9 @@
 
 	type record L1ctlTrafficReq {
 		octetstring	data length(TRAFFIC_DATA_LEN)
-	} with { variant "" };
+	} with {
+		variant (data) "BYTEORDER(first)"
+	}
 
 	type record length(8) of uint8_t TfiUsfArr;
 
@@ -300,7 +308,9 @@
 		L1ctlTrafficReq		traffic_req,
 		L1ctlTbfCfgReq		tbf_cfg_req,
 		octetstring		other
-	} with { variant "" };
+	} with {
+		variant (other) "BYTEORDER(first)"
+	};
 
 	type record L1ctlUlMessage {
 		L1ctlHeader	header,
@@ -586,4 +596,6 @@
 
 	const octetstring c_DummyUI := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
 
+/* We use "BYTEORDER(last)" so we get little-endian integers.  Unfortuantely, this also
+   switches the byte ordering in octet strings, so we need to explicitly annotate them :/ */
 } with { encode "RAW" };
diff --git a/library/LAPDm_RAW_PT.ttcn b/library/LAPDm_RAW_PT.ttcn
index 229aff0..ab99538 100644
--- a/library/LAPDm_RAW_PT.ttcn
+++ b/library/LAPDm_RAW_PT.ttcn
@@ -47,13 +47,27 @@
 	/* PH-DATA.ind / PH-DATA.req */
 	type record RLCMAC_ph_data_ind {
 		GprsCodingScheme cs,
+		uint8_t ts_nr,
+		GsmFrameNumber fn,
 		RlcmacDlBlock block
 	}
-	type record RLCMAC_ph_data_req {
+	type record RLCMAC_ph_data_req_dyn {
 		uint8_t tbf_id,
 		GprsCodingScheme cs,
 		RlcmacUlBlock block
 	}
+	type record RLCMAC_ph_data_req_abs {
+		uint8_t tbf_id,
+		GprsCodingScheme cs,
+		uint8_t ts_nr,
+		GsmFrameNumber fn,
+		Arfcn arfcn,
+		RlcmacUlBlock block
+	}
+	type union RLCMAC_ph_data_req {
+		RLCMAC_ph_data_req_dyn	dyn,
+		RLCMAC_ph_data_req_abs	abs
+	}
 
 	/* port from our (internal) point of view */
 	type port LAPDm_SP_PT message {
@@ -223,6 +237,19 @@
 		}
 	};
 
+	template (value) RLCMAC_ph_data_req ts_PH_DATA_ABS(uint8_t tbf_id, GprsCodingScheme cs,
+							   uint8_t ts, uint32_t fn, Arfcn arfcn,
+							   RlcmacUlBlock block) := {
+		abs := {
+			tbf_id := tbf_id,
+			cs := CS1,	/* FIXME */
+			ts_nr := ts,
+			fn := fn,
+			arfcn := arfcn,
+			block := block
+		}
+	}
+
 	private function f_establish_tbf(uint8_t ra) runs on lapdm_CT {
 		var ImmediateAssignment imm_ass;
 		var GsmFrameNumber rach_fn;
@@ -377,6 +404,8 @@
 			/* decode + forward any blocks from L1 to L23*/
 			[] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
 				rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
+				rpdi.fn := dl.dl_info.frame_nr;
+				rpdi.ts_nr := dl.dl_info.chan_nr.tn;
 				rpdi.cs := CS1; /* FIXME */
 				log("RPDI: ", rpdi);
 				LAPDM_SP.send(rpdi);
@@ -387,9 +416,15 @@
 			/* encode + forward any blocks from L23 to L1 */
 			[] LAPDM_SP.receive(RLCMAC_ph_data_req:?) -> value rpdr {
 				var octetstring buf;
-
-				buf := enc_RlcmacUlBlock(rpdr.block);
-				L1CTL.send(t_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.tbf_id));
+				if (ischosen(rpdr.dyn)) {
+					buf := enc_RlcmacUlBlock(rpdr.dyn.block);
+					L1CTL.send(t_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.dyn.tbf_id));
+				} else {
+					buf := enc_RlcmacUlBlock(rpdr.abs.block);
+					L1CTL.send(t_L1CTL_DATA_ABS_REQ(buf, rpdr.abs.arfcn,
+									rpdr.abs.ts_nr, rpdr.abs.fn,
+									L1CTL_CS1, rpdr.abs.tbf_id));
+				}
 			}
 
 			/* FIXME: release TBF mode */
diff --git a/library/Osmocom_Gb_Types.ttcn b/library/Osmocom_Gb_Types.ttcn
index f943c9c..3de7427 100644
--- a/library/Osmocom_Gb_Types.ttcn
+++ b/library/Osmocom_Gb_Types.ttcn
@@ -301,8 +301,8 @@
 	}
 
 	template LLC_PDU tr_BSSGP_LLC_PDU(template octetstring pdu := ?) := {
-		iEI := '0D'O,
-		ext := '1'B,
+		iEI := '0E'O,
+		ext := ?,
 		lengthIndicator := ?,
 		lLC_PDU := pdu
 	}
diff --git a/library/RLCMAC_CSN1_Types.ttcn b/library/RLCMAC_CSN1_Types.ttcn
index 2335c29..95b5838 100644
--- a/library/RLCMAC_CSN1_Types.ttcn
+++ b/library/RLCMAC_CSN1_Types.ttcn
@@ -513,4 +513,16 @@
 		variant (relative_k) "PRESENCE(presence = '1'B)"
 	};
 
+	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
+			}
+		}
+	}
+
+
 } with { encode "RAW"; variant "FIELDORDER(msb)" variant "BYTEORDER(last)" };
diff --git a/library/RLCMAC_Types.ttcn b/library/RLCMAC_Types.ttcn
index a30a43c..937aa7b 100644
--- a/library/RLCMAC_Types.ttcn
+++ b/library/RLCMAC_Types.ttcn
@@ -226,4 +226,17 @@
 	external function enc_RlcmacDlBlock(in RlcmacDlBlock si) return octetstring;
 	external function dec_RlcmacDlBlock(in octetstring stream) return RlcmacDlBlock;
 
+	template (value) RlcmacUlBlock ts_RLC_UL_CTRL_ACK(RlcmacUlCtrlMsg ctrl,
+							MacPayloadType pt := MAC_PT_RLCMAC_NO_OPT,
+							boolean retry := false) := {
+		ctrl := {
+			mac_hdr := {
+				payload_type := pt,
+				spare := '00000'B,
+				retry := retry
+			},
+			payload := ctrl
+		}
+	}
+
 } with { encode "RAW"; variant "FIELDORDER(msb)" }