aboutsummaryrefslogtreecommitdiffstats
path: root/library/RLCMAC_EncDec.cc
diff options
context:
space:
mode:
Diffstat (limited to 'library/RLCMAC_EncDec.cc')
-rw-r--r--library/RLCMAC_EncDec.cc196
1 files changed, 169 insertions, 27 deletions
diff --git a/library/RLCMAC_EncDec.cc b/library/RLCMAC_EncDec.cc
index d25a7e07..dd32d8f8 100644
--- a/library/RLCMAC_EncDec.cc
+++ b/library/RLCMAC_EncDec.cc
@@ -207,17 +207,23 @@ static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) {
return CodingScheme::MCS__3;
case 49:
return CodingScheme::MCS__4;
+ case 60: /* fall through */
case 61:
return CodingScheme::MCS__5;
+ case 78: /* fall through */
case 79:
return CodingScheme::MCS__6;
+ case 118: /* fall through */
case 119:
return CodingScheme::MCS__7;
- case 142:
+ case 142: /* fall through */
+ case 143:
return CodingScheme::MCS__8;
+ case 154: /* fall through */
case 155:
return CodingScheme::MCS__9;
default:
+ fprintf(stderr, "ERROR: Unknown CodingSCheme for payload_len=%zu\n", payload_len);
return CodingScheme::CS__1;
}
}
@@ -438,6 +444,29 @@ static void put_egprs_data_block(const TTCN_Buffer& aligned_data_block_buffer, u
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?
+ return;
+ }
+
+ 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
/////////////////////
@@ -450,6 +479,8 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
TTCN_Buffer ttcn_buffer(stream);
int num_llc_blocks = 0;
+ ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
+
/* use automatic/generated decoder for header */
ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
@@ -475,6 +506,7 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
/* LI not present: The Upper Layer PDU that starts with the current RLC data block either
* fills the current RLC data block precisely or continues in the following in-sequence RLC
* data block */
+ lb.hdr() = OMIT_VALUE;
lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
ttcn_buffer.increase_pos(length);
ret_val.blocks()[0] = lb;
@@ -482,8 +514,17 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
if (ret_val.blocks().is_bound()) {
for (int i = 0; i < ret_val.blocks().size_of(); i++) {
unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
+
+ /* LI[0]=0 indicates: The current LLC PDU would fit within
+ current RLC data block but the addition of the length
+ indicator octet (to indicate the LLC PDU boundary) causes the
+ LLC PDU to extend into another RLC data block */
+ if (i == 0 && length == 0)
+ length = ttcn_buffer.get_read_len();
+
if (length > ttcn_buffer.get_read_len())
length = ttcn_buffer.get_read_len();
+
ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
ttcn_buffer.increase_pos(length);
}
@@ -496,20 +537,54 @@ RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
static
EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
{
+ TTCN_Buffer ttcn_buffer(stream);
EgprsDlMacDataHeader ret_val;
+ const struct gprs_rlc_dl_header_egprs_1 *egprs1;
+ uint8_t tmp;
- fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
+ egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *>
+ ((const void *)ttcn_buffer.get_data());
+ ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1;
+ ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0;
+ ret_val.rrbp() = egprs1->rrbp;
+ tmp = egprs1->es_p;
+ ret_val.esp() = BITSTRING(2, &tmp);
+ ret_val.usf() = egprs1->usf;
+ ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi;
+ ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi;
+ ret_val.pr() = egprs1->pr;
+ ret_val.cps() = egprs1->cps;
+ ret_val.spb() = OMIT_VALUE;
+
+ ttcn_buffer.increase_pos(sizeof(*egprs1));
return ret_val;
}
static
EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
{
+ TTCN_Buffer ttcn_buffer(stream);
EgprsDlMacDataHeader ret_val;
+ const struct gprs_rlc_dl_header_egprs_2 *egprs2;
+ uint8_t tmp;
- fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
+ egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *>
+ ((const void *)ttcn_buffer.get_data());
+ ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2;
+ ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0;
+ ret_val.rrbp() = egprs2->rrbp;
+ tmp = egprs2->es_p;
+ ret_val.esp() = BITSTRING(2, &tmp);
+ ret_val.usf() = egprs2->usf;
+ ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi;
+ ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
+ ret_val.pr() = egprs2->pr;
+ ret_val.cps() = egprs2->cps;
+ ret_val.spb() = OMIT_VALUE;
+
+ ttcn_buffer.increase_pos(sizeof(*egprs2));
return ret_val;
}
@@ -541,7 +616,7 @@ EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
}
static
-RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
+RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
{
RlcmacDlEgprsDataBlock ret_val;
TTCN_Buffer ttcn_buffer(stream);
@@ -551,7 +626,8 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co
unsigned int num_calls;
const uint8_t *ti_e;
- switch (mcs) {
+ ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
+ switch (ret_val.mcs()) {
case CodingScheme::MCS__0:
case CodingScheme::MCS__1:
case CodingScheme::MCS__2:
@@ -569,7 +645,7 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co
ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
break;
}
- setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), false,
+ setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
&num_calls, &data_block_bits, data_block_offsets);
get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
@@ -594,13 +670,26 @@ RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, Co
}
/* RLC blocks at end */
- if (ret_val.blocks().is_bound()) {
- for (int i = 0; i < ret_val.blocks().size_of(); i++) {
- unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
- if (length > aligned_buffer.get_read_len())
- length = aligned_buffer.get_read_len();
- ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
- aligned_buffer.increase_pos(length);
+ if (ret_val.e() == true) {
+ EgprsLlcBlock lb;
+ unsigned int length = aligned_buffer.get_read_len();
+ /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
+ * fills the current RLC data block precisely or continues in the following in-sequence RLC
+ * data block */
+ lb.hdr() = OMIT_VALUE;
+ lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
+ aligned_buffer.increase_pos(length);
+ ret_val.blocks()[0] = lb;
+ } else {
+ /* RLC blocks at end */
+ if (ret_val.blocks().is_bound()) {
+ for (int i = 0; i < ret_val.blocks().size_of(); i++) {
+ unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
+ if (length > aligned_buffer.get_read_len())
+ length = aligned_buffer.get_read_len();
+ ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
+ aligned_buffer.increase_pos(length);
+ }
}
}
@@ -611,10 +700,10 @@ RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
{
RlcmacDlBlock ret_val;
size_t stream_len = stream.lengthof();
- CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
+ CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
unsigned char pt;
- switch (mcs) {
+ switch (cs_mcs) {
case CodingScheme::CS__1:
case CodingScheme::CS__2:
case CodingScheme::CS__3:
@@ -635,7 +724,7 @@ RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
case CodingScheme::MCS__7:
case CodingScheme::MCS__8:
case CodingScheme::MCS__9:
- ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream, mcs);
+ ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
break;
}
return ret_val;
@@ -655,6 +744,8 @@ RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
stream.log();
TTCN_Logger::end_event();
+ ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
+
/* use automatic/generated decoder for header */
ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
@@ -715,6 +806,7 @@ RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
/* LI not present: The Upper Layer PDU that starts with the current RLC data block either
* fills the current RLC data block precisely or continues in the following in-sequence RLC
* data block */
+ lb.hdr() = OMIT_VALUE;
lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
ttcn_buffer.increase_pos(length);
ret_val.blocks()[0] = lb;
@@ -792,7 +884,7 @@ EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
return ret_val;
}
-RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
+RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
{
RlcmacUlEgprsDataBlock ret_val;
TTCN_Buffer ttcn_buffer(stream);
@@ -802,7 +894,8 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co
unsigned int num_calls;
const uint8_t *ti_e;
- switch (mcs) {
+ ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
+ switch (ret_val.mcs()) {
case CodingScheme::MCS__1:
case CodingScheme::MCS__2:
case CodingScheme::MCS__3:
@@ -819,7 +912,7 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co
ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
break;
}
- setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), true,
+ setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
&num_calls, &data_block_bits, data_block_offsets);
get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
@@ -867,6 +960,7 @@ RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, Co
/* LI not present: The Upper Layer PDU that starts with the current RLC data block either
* fills the current RLC data block precisely or continues in the following in-sequence RLC
* data block */
+ lb.hdr() = OMIT_VALUE;
lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
aligned_buffer.increase_pos(length);
ret_val.blocks()[0] = lb;
@@ -889,10 +983,10 @@ RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
{
RlcmacUlBlock ret_val;
size_t stream_len = stream.lengthof();
- CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
+ CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
unsigned char pt;
- switch (mcs) {
+ switch (cs_mcs) {
case CodingScheme::CS__1:
case CodingScheme::CS__2:
case CodingScheme::CS__3:
@@ -912,7 +1006,7 @@ RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
case CodingScheme::MCS__7:
case CodingScheme::MCS__8:
case CodingScheme::MCS__9:
- ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream, mcs);
+ ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
break;
}
@@ -964,6 +1058,8 @@ OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
}
}
+ encode_trailing_padding_spb(ttcn_buffer, in.cs());
+
ttcn_buffer.get_string(ret_val);
return ret_val;
}
@@ -1034,6 +1130,8 @@ OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
}
}
+ encode_trailing_padding_spb(ttcn_buffer, in.mcs());
+
ttcn_buffer.get_string(ret_val);
return ret_val;
}
@@ -1127,6 +1225,8 @@ OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
}
}
+ encode_trailing_padding_spb(ttcn_buffer, in.cs());
+
ttcn_buffer.get_string(ret_val);
return ret_val;
}
@@ -1134,13 +1234,48 @@ OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
static
void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
{
- fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
+ struct gprs_rlc_ul_header_egprs_1 egprs1;
+
+ egprs1.r = bs2uint8(si.r__ri());
+ egprs1.si = bs2uint8(si.foi__si());
+ egprs1.cv = si.countdown();
+ egprs1.tfi_hi = si.tfi() >> 0;
+ egprs1.tfi_lo = si.tfi() >> 2;
+ egprs1.bsn1_hi = si.bsn1() >> 0;
+ egprs1.bsn1_lo = si.bsn1() >> 5;
+ egprs1.bsn2_hi = si.bsn2__offset() >> 0;
+ egprs1.bsn2_lo = si.bsn2__offset() >> 2;
+ egprs1.cps = si.cps();
+ egprs1.rsb = bs2uint8(si.rsb());
+ egprs1.pi = si.pfi__ind();
+ egprs1.spare_hi = 0;
+ egprs1.spare_lo = 0;
+ egprs1.dummy = 0;
+
+ ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
}
static
void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
{
- fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
+ struct gprs_rlc_ul_header_egprs_2 egprs2;
+
+ egprs2.r = bs2uint8(si.r__ri());
+ egprs2.si = bs2uint8(si.foi__si());
+ egprs2.cv = si.countdown();
+ egprs2.tfi_hi = si.tfi() >> 0;
+ egprs2.tfi_lo = si.tfi() >> 2;
+ egprs2.bsn1_hi = si.bsn1() >> 0;
+ egprs2.bsn1_lo = si.bsn1() >> 5;
+ egprs2.cps_hi = si.cps() >> 0;
+ egprs2.cps_lo = si.cps() >> 2;
+ egprs2.rsb = bs2uint8(si.rsb());
+ egprs2.pi = si.pfi__ind();
+ egprs2.spare_hi = 0;
+ egprs2.spare_lo = 0;
+ egprs2.dummy = 0;
+
+ ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
}
static
@@ -1175,7 +1310,6 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
unsigned int data_block_bits, data_block_offsets[2];
unsigned int num_calls;
CodingScheme mcs;
- boolean tlli_ind, e;
mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
//fprintf(stderr, "RLCMAC: infered MCS %s (%d)\n", mcs.enum_to_str(static_cast<CodingScheme::enum_type>(mcs.as_int())), mcs.as_int());
@@ -1209,7 +1343,7 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
}
/* Put first TI + E byte */
- aligned_buffer.put_c(tlli_ind << 1 | e << 0); /* M=0, E=1 LEN=0 */
+ aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
//printbuffer("After encoding first byte", aligned_buffer);
if (in.e() == false) {
@@ -1251,7 +1385,13 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
if (in.tlli__ind()) {
- aligned_buffer.put_string(in.tlli());
+ /* The TLLI is encoded in little endian for EGPRS (see
+ * TS 44.060, figure 10.3a.2.1, note 2) */
+ OCTETSTRING tlli = in.tlli();
+ aligned_buffer.put_c(tlli[3].get_octet());
+ aligned_buffer.put_c(tlli[2].get_octet());
+ aligned_buffer.put_c(tlli[1].get_octet());
+ aligned_buffer.put_c(tlli[0].get_octet());
}
if (in.mac__hdr().pfi__ind()) {
@@ -1274,6 +1414,8 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
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;
}