RLCMAC_EncDec.cc: Fix egprs data block encode alignment
Selftests I'm using in the pcu testsuite to verify encoding are attached too. Change-Id: Id0e21248853eb5fac89e863822804cfbecf3c865
This commit is contained in:
parent
27d6af5edb
commit
2456dad91e
|
@ -2,6 +2,7 @@
|
|||
#include <endian.h>
|
||||
|
||||
#include "RLCMAC_Types.hh"
|
||||
#include "RLCMAC_Templates.hh"
|
||||
#include "GSM_Types.hh"
|
||||
/* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions
|
||||
* beyond what TITAN RAW coder can handle internally.
|
||||
|
@ -172,6 +173,22 @@ struct gprs_rlc_dl_header_egprs_3 {
|
|||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
static const char hex_chars[] = "0123456789abcdef";
|
||||
void printbuffer(const char* ptr, TTCN_Buffer& buf) {
|
||||
int len = buf.get_len();
|
||||
const unsigned char* cbuf = buf.get_data();
|
||||
|
||||
fprintf(stderr, "printbuffer %s (len=%d): [", ptr, len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
fprintf(stderr, " %c%c", hex_chars[cbuf[i] >> 4], hex_chars[cbuf[i] & 0xf]);
|
||||
}
|
||||
|
||||
fprintf(stderr, " ]\n");
|
||||
}
|
||||
*/
|
||||
|
||||
static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) {
|
||||
switch (payload_len) {
|
||||
case 23:
|
||||
|
@ -294,7 +311,7 @@ static void clone_aligned_buffer_lsbf(unsigned int offset_bits, unsigned int len
|
|||
hdr_bytes = offset_bits / 8;
|
||||
extra_bits = offset_bits % 8;
|
||||
|
||||
fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
|
||||
//fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
|
||||
|
||||
if (extra_bits == 0) {
|
||||
/* It is aligned already */
|
||||
|
@ -324,9 +341,8 @@ static void get_egprs_data_block(const TTCN_Buffer& orig_ttcn_buffer, unsigned i
|
|||
size_t length_bytes = (initial_spare_bits + length_bits + 7) / 8;
|
||||
size_t accepted_len = length_bytes;
|
||||
|
||||
fprintf(stderr, "RLMAC: trying to allocate %u bytes (orig is %zu bytes long with read pos %zu)\n", length_bytes, orig_ttcn_buffer.get_len(), orig_ttcn_buffer.get_pos());
|
||||
//fprintf(stderr, "RLMAC: trying to allocate %u bytes (orig is %zu bytes long with read pos %zu)\n", length_bytes, orig_ttcn_buffer.get_len(), orig_ttcn_buffer.get_pos());
|
||||
dst_ttcn_buffer.get_end(aligned_buf, accepted_len);
|
||||
fprintf(stderr, "RLMAC: For dst ptr=%p with length=%zu\n", aligned_buf, accepted_len);
|
||||
if (accepted_len < length_bytes) {
|
||||
fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
|
||||
}
|
||||
|
@ -337,14 +353,90 @@ static void get_egprs_data_block(const TTCN_Buffer& orig_ttcn_buffer, unsigned i
|
|||
orig_ttcn_buffer.get_data(),
|
||||
aligned_buf);
|
||||
|
||||
fprintf(stderr, "RLMAC: clone_aligned_buffer_lsbf success\n");
|
||||
|
||||
/* clear spare bits and move block header bits to the right */
|
||||
aligned_buf[0] = aligned_buf[0] >> initial_spare_bits;
|
||||
|
||||
dst_ttcn_buffer.increase_length(length_bytes);
|
||||
}
|
||||
|
||||
/* bit-shift the entire 'src' of length 'length_bytes'
|
||||
* and store the result to caller-allocated 'buffer' by 'offset_bits'. The shifting is
|
||||
* done lsb-first. */
|
||||
static void clone_unaligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
|
||||
const uint8_t *src, uint8_t *buffer)
|
||||
{
|
||||
unsigned int hdr_bytes;
|
||||
unsigned int extra_bits;
|
||||
unsigned int i;
|
||||
|
||||
uint8_t c, last_hdr_c, last_c;
|
||||
uint8_t *dst;
|
||||
|
||||
hdr_bytes = offset_bits / 8;
|
||||
extra_bits = offset_bits % 8;
|
||||
|
||||
//fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
|
||||
|
||||
if (extra_bits == 0) {
|
||||
/* It is aligned already */
|
||||
memcpy(buffer, src + hdr_bytes, length_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy first header+data byte, it's not handled correctly by loop */
|
||||
dst = buffer + hdr_bytes;
|
||||
last_hdr_c = *dst;
|
||||
last_c = *dst << (8 - extra_bits);
|
||||
|
||||
for (i = 0; i < length_bytes; i++) {
|
||||
c = src[i];
|
||||
*(dst++) = (last_c >> (8 - extra_bits)) | (c << extra_bits);
|
||||
last_c = c;
|
||||
}
|
||||
/* overwrite the lower extra_bits */
|
||||
*dst = (*dst & (0xff << extra_bits)) | (last_c >> (8 - extra_bits));
|
||||
|
||||
/* Copy back first header+data byte */
|
||||
dst = buffer + hdr_bytes;
|
||||
*(dst++) = last_hdr_c | (src[0] << (8 - extra_bits));
|
||||
*dst |= (src[0] >> (extra_bits)) & (0xff >> (8 - extra_bits));
|
||||
}
|
||||
|
||||
/* put an (aligned) EGPRS data block with given bit-offset and
|
||||
* bit-length into parent buffer */
|
||||
static void put_egprs_data_block(const TTCN_Buffer& aligned_data_block_buffer, unsigned int offset_bits,
|
||||
unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
|
||||
{
|
||||
const unsigned int initial_spare_bits = 6;
|
||||
unsigned char *unaligned_buf = NULL;
|
||||
char tmpbuf[120];
|
||||
int tmplen = dst_ttcn_buffer.get_len();
|
||||
//size_t max_length_bytes = (initial_spare_bits + length_bits + 7) / 8;
|
||||
size_t length_bytes = tmplen + aligned_data_block_buffer.get_len();
|
||||
size_t accepted_len = length_bytes;
|
||||
|
||||
//fprintf(stderr, "RLMAC: trying to allocate %u bytes\n", length_bytes);
|
||||
|
||||
/* API .get_end() is the only one I could find to access writeable
|
||||
memory in the buffer. It points to the end. Hence, we first copy
|
||||
(readonly) data to tmpbuf and later clear() so that .get_end()
|
||||
provides us with a pointer to the start of the buffer. */
|
||||
memcpy(tmpbuf, dst_ttcn_buffer.get_data(), tmplen);
|
||||
dst_ttcn_buffer.clear();
|
||||
dst_ttcn_buffer.get_end(unaligned_buf, accepted_len);
|
||||
if (accepted_len < tmplen) {
|
||||
fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
|
||||
}
|
||||
memcpy(unaligned_buf, tmpbuf, tmplen);
|
||||
|
||||
/* Copy the data out of the tvb to an aligned buffer */
|
||||
clone_unaligned_buffer_lsbf(
|
||||
offset_bits - initial_spare_bits, length_bytes,
|
||||
aligned_data_block_buffer.get_data(),
|
||||
unaligned_buf);
|
||||
|
||||
dst_ttcn_buffer.increase_length(length_bytes);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// DECODE
|
||||
|
@ -1078,8 +1170,15 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
|
|||
{
|
||||
RlcmacUlEgprsDataBlock in = si;
|
||||
OCTETSTRING ret_val;
|
||||
TTCN_Buffer ttcn_buffer;
|
||||
TTCN_Buffer ttcn_buffer, aligned_buffer;
|
||||
int i;
|
||||
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());
|
||||
|
||||
if (!in.blocks().is_bound()) {
|
||||
/* we don't have nay blocks: Add length value (zero) */
|
||||
|
@ -1109,10 +1208,14 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
|
|||
break; /* TODO: error */
|
||||
}
|
||||
|
||||
/* Put first TI + E byte */
|
||||
aligned_buffer.put_c(tlli_ind << 1 | e << 0); /* M=0, E=1 LEN=0 */
|
||||
//printbuffer("After encoding first byte", aligned_buffer);
|
||||
|
||||
if (in.e() == false) {
|
||||
/* Add LI octets, if any */
|
||||
if (!in.blocks().is_bound()) {
|
||||
ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
|
||||
aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
|
||||
} else {
|
||||
for (i = 0; i < in.blocks().size_of(); i++) {
|
||||
#if 0
|
||||
|
@ -1138,28 +1241,38 @@ OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
|
|||
}
|
||||
#endif
|
||||
if (in.blocks()[i].hdr() != OMIT_VALUE) {
|
||||
in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer,
|
||||
in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
|
||||
TTCN_EncDec::CT_RAW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (in.tlli__ind()) {
|
||||
ttcn_buffer.put_string(in.tlli());
|
||||
aligned_buffer.put_string(in.tlli());
|
||||
}
|
||||
|
||||
if (in.mac__hdr().pfi__ind()) {
|
||||
in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
|
||||
in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
|
||||
}
|
||||
|
||||
//printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
|
||||
if (in.blocks().is_bound()) {
|
||||
for (i = 0; i < in.blocks().size_of(); i++) {
|
||||
if (!in.blocks()[i].is_bound())
|
||||
continue;
|
||||
ttcn_buffer.put_string(in.blocks()[i].payload());
|
||||
aligned_buffer.put_string(in.blocks()[i].payload());
|
||||
}
|
||||
}
|
||||
//printbuffer("After encoding EgprsLlc payload", aligned_buffer);
|
||||
|
||||
setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
|
||||
&num_calls, &data_block_bits, data_block_offsets);
|
||||
//printbuffer("before merging data block", ttcn_buffer);
|
||||
put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
|
||||
//printbuffer("after merging data block", ttcn_buffer);
|
||||
|
||||
ttcn_buffer.get_string(ret_val);
|
||||
return ret_val;
|
||||
|
|
|
@ -326,6 +326,31 @@ module RLCMAC_Templates {
|
|||
}
|
||||
}
|
||||
|
||||
/* Template for uplink Data block */
|
||||
template RlcmacUlBlock t_RLCMAC_UL_EGPRS_DATA(CodingScheme mcs,
|
||||
template uint5_t tfi, template uint4_t cv,
|
||||
template uint11_t bsn1, template EgprsLlcBlocks blocks := {}) := {
|
||||
data_egprs := {
|
||||
mac_hdr := {
|
||||
header_type := f_rlcmac_mcs2headertype(mcs),
|
||||
tfi := tfi,
|
||||
countdown := cv,
|
||||
foi_si := '0'B,
|
||||
r_ri := '0'B,
|
||||
bsn1 := bsn1,
|
||||
cps := f_rlcmac_mcs_to_cps(mcs, 1, false),
|
||||
pfi_ind := false,
|
||||
rsb := '0'B,
|
||||
spb := '00'B
|
||||
},
|
||||
tlli_ind := false,
|
||||
e := false,
|
||||
tlli := omit,
|
||||
pfi := omit,
|
||||
blocks := blocks
|
||||
}
|
||||
}
|
||||
|
||||
template DlMacHeader t_RLCMAC_DlMacH(template MacPayloadType pt, template MacRrbp rrbp, template
|
||||
uint3_t usf) := {
|
||||
payload_type := pt,
|
||||
|
@ -519,4 +544,11 @@ uint3_t usf) := {
|
|||
payload := data
|
||||
}
|
||||
|
||||
/* Template for a LlcBlock (part of a LLC frame inside RlcMacEgprs?lDataBlock */
|
||||
template EgprsLlcBlock t_RLCMAC_LLCBLOCK_EGPRS(octetstring data, boolean e := true) := {
|
||||
/* let encoder figure out the header */
|
||||
hdr := omit,
|
||||
payload := data
|
||||
}
|
||||
|
||||
} with { encode "RAW"; variant "FIELDORDER(msb)" }
|
||||
|
|
|
@ -187,7 +187,7 @@ private function f_init_vty(charstring id) runs on RAW_PCU_Test_CT {
|
|||
}
|
||||
}
|
||||
|
||||
private function f_init_raw(charstring id, template (value) PCUIF_info_ind info_ind := ts_PCUIF_INFO_default)
|
||||
function f_init_raw(charstring id, template (value) PCUIF_info_ind info_ind := ts_PCUIF_INFO_default)
|
||||
runs on RAW_PCU_Test_CT {
|
||||
var RAW_PCUIF_CT vc_PCUIF;
|
||||
var RAW_PCU_BTS_CT vc_BTS;
|
||||
|
@ -394,7 +394,7 @@ runs on RAW_PCU_Test_CT return boolean {
|
|||
}
|
||||
|
||||
/* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
|
||||
private function f_pcuif_tx_data_ind(octetstring data, int16_t lqual_cb := 0, uint32_t fn := 0)
|
||||
function f_pcuif_tx_data_ind(octetstring data, int16_t lqual_cb := 0, uint32_t fn := 0)
|
||||
runs on RAW_PCU_Test_CT {
|
||||
var template RAW_PCU_EventParam ev_param := {tdma_fn := ? };
|
||||
BTS.send(ts_PCUIF_DATA_IND(bts_nr := 0, trx_nr := 0, ts_nr := 7, block_nr := 0,
|
||||
|
|
|
@ -17,12 +17,15 @@ import from NS_Types all;
|
|||
import from NS_Emulation all;
|
||||
import from GPRS_Context all;
|
||||
import from Osmocom_Gb_Types all;
|
||||
import from Osmocom_Types all;
|
||||
import from LLC_Types all;
|
||||
import from LLC_Templates all;
|
||||
import from L3_Templates all;
|
||||
import from GSM_RR_Types all;
|
||||
import from RLCMAC_Types all;
|
||||
import from RLCMAC_CSN1_Types all;
|
||||
import from RLCMAC_Types all;
|
||||
import from RLCMAC_Templates all;
|
||||
import from PCU_Tests all;
|
||||
|
||||
type component dummy_CT extends BSSGP_Client_CT {
|
||||
var NS_CT ns_component;
|
||||
|
@ -249,6 +252,53 @@ testcase TC_selftest_rlcmac() runs on dummy_CT {
|
|||
f_rlcmac_ul_decenc(c_ul_dl_ack_nack);
|
||||
}
|
||||
|
||||
testcase TC_selftest_rlcmac_egprs() runs on RAW_PCU_Test_CT
|
||||
{
|
||||
var octetstring data;
|
||||
var CodingSchemeArray schemes := {
|
||||
//MCS_0,
|
||||
MCS_1,
|
||||
MCS_2,
|
||||
MCS_3,
|
||||
MCS_4,
|
||||
MCS_5,
|
||||
MCS_6,
|
||||
MCS_7,
|
||||
MCS_8,
|
||||
MCS_9
|
||||
};
|
||||
|
||||
/* Initialize the PCU interface abstraction */
|
||||
f_init_raw(testcasename());
|
||||
|
||||
log("Started Uplink test");
|
||||
for (var integer i := 0; i < sizeof(schemes); i := i+1) {
|
||||
log("Testing Coding Schema ", schemes[i]);
|
||||
var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_EGPRS_DATA(
|
||||
schemes[i],
|
||||
tfi := 4,
|
||||
cv := 1, /* num UL blocks to be sent (to be overridden in loop) */
|
||||
bsn1 := 2, /* TODO: what should be here? */
|
||||
blocks := { /* To be generated in loop */ });
|
||||
|
||||
ul_data.data_egprs.tlli := '00100101'O;
|
||||
ul_data.data_egprs.blocks := { valueof(t_RLCMAC_LLCBLOCK_EGPRS('AABBCCDDEEFF00112233'O)) };
|
||||
|
||||
/* Encode the payload of DATA.ind */
|
||||
log("Encoding ", valueof(ul_data));
|
||||
data := enc_RlcmacUlBlock(valueof(ul_data));
|
||||
data := f_pad_oct(data, f_rlcmac_cs_mcs2block_len(schemes[i]), '00'O);
|
||||
|
||||
/* Send to PCU so that we get gsmtap traces to verify with wireshark */
|
||||
f_pcuif_tx_data_ind(data, 0, 0);
|
||||
|
||||
log("Decoding ", schemes[i]);
|
||||
ul_data := dec_RlcmacUlBlock(data);
|
||||
log("Decoded: ", ul_data);
|
||||
}
|
||||
log("Done Uplink test");
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// RR selftest
|
||||
///////////////////
|
||||
|
|
Loading…
Reference in New Issue