pcu: Specify (M)CS to use when sending UL rlcmac data blocks

Apply padding and spare bits in the encoder according to CS/MCS format.

Change-Id: I918acac81f550077daeda3374b3de9b426ff3572
diff --git a/library/RLCMAC_EncDec.cc b/library/RLCMAC_EncDec.cc
index 4dba35a..ea93de4 100644
--- a/library/RLCMAC_EncDec.cc
+++ b/library/RLCMAC_EncDec.cc
@@ -438,6 +438,28 @@
 	dst_ttcn_buffer.increase_length(length_bytes);
 }
 
+/* Append padding bytes and spare bits at the end of ttcn_buffer, based on requested CS */
+static void encode_trailing_padding_spb(TTCN_Buffer& ttcn_buffer, CodingScheme cs)
+{
+	uint8_t buf[256]; /* enough to fit any RLCMAC buffer*/
+	uint32_t blk_len = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len(cs);
+	uint32_t blk_len_no_spb = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len__no__spare__bits(cs);
+	uint32_t data_len = ttcn_buffer.get_len();
+
+	if (data_len > blk_len_no_spb) {
+		fprintf(stderr, "Buffer too large for requested CS! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
+		// TODO: throw exception?
+	}
+
+	for (int i = 0; i < blk_len_no_spb - data_len; i++)
+		buf[i] = 0x2b; /* Padding bits if needed */
+	for (int i = blk_len_no_spb - data_len; i < blk_len - data_len; i++)
+		buf[i] = 0x00;  /* Spare bits if needed */
+
+	const OCTETSTRING& pad_octstr = OCTETSTRING(blk_len - data_len, buf);
+	ttcn_buffer.put_string(pad_octstr);
+}
+
 /////////////////////
 // DECODE
 /////////////////////
@@ -970,6 +992,8 @@
 		}
 	}
 
+	encode_trailing_padding_spb(ttcn_buffer, in.cs());
+
 	ttcn_buffer.get_string(ret_val);
 	return ret_val;
 }
@@ -1040,6 +1064,8 @@
 		}
 	}
 
+	encode_trailing_padding_spb(ttcn_buffer, in.mcs());
+
 	ttcn_buffer.get_string(ret_val);
 	return ret_val;
 }
@@ -1133,6 +1159,8 @@
 		}
 	}
 
+	encode_trailing_padding_spb(ttcn_buffer, in.cs());
+
 	ttcn_buffer.get_string(ret_val);
 	return ret_val;
 }
@@ -1320,6 +1348,8 @@
 	put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
 	//printbuffer("after merging data block", ttcn_buffer);
 
+	encode_trailing_padding_spb(ttcn_buffer, in.mcs());
+
 	ttcn_buffer.get_string(ret_val);
 	return ret_val;
 }
diff --git a/library/RLCMAC_Templates.ttcn b/library/RLCMAC_Templates.ttcn
index 9722f43..f016c4d 100644
--- a/library/RLCMAC_Templates.ttcn
+++ b/library/RLCMAC_Templates.ttcn
@@ -38,6 +38,13 @@
 		return (current_fn + f_rrbp_fn_delay(rrbp)) mod 2715648;
 	}
 
+	function f_rlcmac_cs_mcs_is_mcs(CodingScheme cs_mcs) return boolean {
+		if (cs_mcs >= MCS_0) {
+			return true;
+		}
+		return false;
+	}
+
 	function f_rlcmac_mcs2headertype(CodingScheme mcs) return EgprsHeaderType {
 		select (mcs) {
 		case (MCS_0) { return RLCMAC_HDR_TYPE_3; }
@@ -97,7 +104,27 @@
 		return CS_1;
 	}
 
-	/* Minimum CodingScheme required to fit RLCMAC block */
+	function f_rlcmac_cs_mcs2block_len_no_spare_bits(CodingScheme cs_mcs) return uint32_t {
+		select (cs_mcs) {
+		/* 3GPP TS 44.060 Table 10.2.1: RLC data block size, discounting padding in octet */
+		case (CS_1) { return 23; }
+		case (CS_2) { return 33; }
+		case (CS_3) { return 39; }
+		case (CS_4) { return 53; }
+		case (MCS_1) { return 27; }
+		case (MCS_2) { return 33; }
+		case (MCS_3) { return 42; }
+		case (MCS_4) { return 49; }
+		case (MCS_5) { return 61; }
+		case (MCS_6) { return 79; }
+		case (MCS_7) { return 119; }
+		case (MCS_8) { return 143; }
+		case (MCS_9) { return 155; }
+		}
+		return 0;
+	}
+
+	/* Minimum CodingScheme required to fit RLCMAC block. Spare bits not counted. */
 	function f_rlcmac_block_len_required_cs_mcs(uint32_t len, boolean is_mcs) return CodingScheme {
 		if (is_mcs) {
 			if (len <= 27) { return MCS_1; }
@@ -375,10 +402,11 @@
 	}
 
 	/* Template for uplink Data block */
-	template RlcmacUlBlock t_RLCMAC_UL_DATA(template uint5_t tfi, template uint4_t cv, template uint7_t bsn,
+	template RlcmacUlBlock t_RLCMAC_UL_DATA(template CodingScheme cs, template uint5_t tfi,
+						template uint4_t cv, template uint7_t bsn,
 						template LlcBlocks blocks := {}, template boolean stall := false) := {
 		data := {
-			cs := CS_1, /* TODO: make this available to template */
+			cs := cs,
 			mac_hdr := {
 				payload_type := MAC_PT_RLC_DATA,
 				countdown := cv,
@@ -396,10 +424,12 @@
 			blocks := blocks
 		}
 	}
-	template RlcmacUlBlock t_RLCMAC_UL_DATA_TLLI(template uint5_t tfi, template uint4_t cv, template uint7_t bsn,
-						     template LlcBlocks blocks := {}, template boolean stall := false, template GprsTlli tlli) := {
+	template RlcmacUlBlock t_RLCMAC_UL_DATA_TLLI(template CodingScheme cs, template uint5_t tfi,
+						     template uint4_t cv, template uint7_t bsn,
+						     template LlcBlocks blocks := {}, template boolean stall := false,
+						     template GprsTlli tlli) := {
 		data := {
-			cs := CS_1, /* TODO: make this available to template */
+			cs := cs,
 			mac_hdr := {
 				payload_type := MAC_PT_RLC_DATA,
 				countdown := cv,
diff --git a/library/RLCMAC_Types.ttcn b/library/RLCMAC_Types.ttcn
index eb9d845..3110a66 100644
--- a/library/RLCMAC_Types.ttcn
+++ b/library/RLCMAC_Types.ttcn
@@ -115,6 +115,11 @@
 		DlCtrlOptOctets		opt optional,
 		RlcmacDlCtrlMsg		payload
 	} with {
+		/* Automatic padding by RAW encoder seems to causing problems
+		 * due to padding sequence 2b inserted shifted from octet
+		 * boundary on some messags. See UL CTRL blocks in TC_t3193.
+		 * See 3GPP TS 44.060 Figure 11.1 (below)
+		 * variant "PADDING(184), PADDING_PATTERN('00101011'B)" */
 		variant (opt) "PRESENCE(mac_hdr.payload_type = MAC_PT_RLCMAC_OPT)"
 	};
 
@@ -133,7 +138,14 @@
 	type record RlcmacUlCtrlBlock {
 		UlMacCtrlHeader		mac_hdr,
 		RlcmacUlCtrlMsg		payload
-	} with { variant "" };
+	} with {
+		/* Automatic padding by RAW encoder seems to causing problems
+		 * due to padding sequence 2b inserted shifted from octet
+		 * boundary on some messags. See UL CTRL blocks in TC_t3193.
+		 * See 3GPP TS 44.060 Figure 11.1 (below)
+		 * variant "PADDING(184), PADDING_PATTERN('00101011'B)" */
+		 variant ""
+		};
 
 	external function enc_RlcmacUlCtrlBlock(in RlcmacUlCtrlBlock si) return octetstring
 		with { extension "prototype(convert) encode(RAW)" };