diff options
-rw-r--r-- | src/encoding.cpp | 120 | ||||
-rw-r--r-- | src/encoding.h | 8 | ||||
-rw-r--r-- | src/rlc.h | 15 | ||||
-rw-r--r-- | tests/edge/EdgeTest.cpp | 70 |
4 files changed, 213 insertions, 0 deletions
diff --git a/src/encoding.cpp b/src/encoding.cpp index fdc8d0ae..0756ffcb 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -25,6 +25,9 @@ #include <tbf.h> #include <gprs_debug.h> +#include <errno.h> +#include <string.h> + // GSM 04.08 9.1.18 Immediate assignment int Encoding::write_immediate_assignment( struct gprs_rlcmac_bts *bts, @@ -631,3 +634,120 @@ unsigned Encoding::write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t return wp; } +int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc, + uint8_t *data) +{ + struct gprs_rlc_dl_header_egprs_3 *egprs3; + struct rlc_dl_header *gprs; + unsigned int e_fbi_header; + GprsCodingScheme cs = rlc->cs; + + switch(cs.headerTypeData()) { + case GprsCodingScheme::HEADER_GPRS_DATA: + gprs = static_cast<struct rlc_dl_header *> + ((void *)data); + + gprs->usf = rlc->usf; + gprs->s_p = rlc->es_p != 0 ? 1 : 0; + gprs->rrbp = rlc->rrbp; + gprs->pt = 0; + gprs->tfi = rlc->tfi; + gprs->pr = rlc->pr; + + gprs->fbi = rlc->block_info[0].cv == 0; + gprs->e = rlc->block_info[0].e; + gprs->bsn = rlc->block_info[0].bsn; + break; + + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3: + egprs3 = static_cast<struct gprs_rlc_dl_header_egprs_3 *> + ((void *)data); + + egprs3->usf = rlc->usf; + egprs3->es_p = rlc->es_p; + egprs3->rrbp = rlc->rrbp; + egprs3->tfi_a = rlc->tfi >> 0; /* 1 bit LSB */ + egprs3->tfi_b = rlc->tfi >> 1; /* 4 bits */ + egprs3->pr = rlc->pr; + egprs3->cps = rlc->cps; + + egprs3->bsn1_a = rlc->block_info[0].bsn >> 0; /* 2 bits LSB */ + egprs3->bsn1_b = rlc->block_info[0].bsn >> 2; /* 8 bits */ + egprs3->bsn1_c = rlc->block_info[0].bsn >> 10; /* 1 bit */ + + egprs3->spb = rlc->block_info[0].spb; + + e_fbi_header = rlc->block_info[0].e ? 0x01 : 0; + e_fbi_header |= rlc->block_info[0].cv == 0 ? 0x02 : 0; /* FBI */ + e_fbi_header <<= 7; + data[3] = (data[3] & 0b01111111) | (e_fbi_header >> 0); + data[4] = (data[4] & 0b11111110) | (e_fbi_header >> 8); + break; + + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1: + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2: + /* TODO: Support both header types */ + /* fall through */ + default: + LOGP(DRLCMACDL, LOGL_ERROR, + "Encoding of uplink %s data blocks not yet supported.\n", + cs.name()); + return -ENOTSUP; + }; + + return 0; +} + +/** + * \brief Copy LSB bitstream RLC data block from byte aligned buffer. + * + * Note that the bitstream is encoded in LSB first order, so the two octets + * 654321xx xxxxxx87 contain the octet 87654321 starting at bit position 3 + * (LSB has bit position 1). This is a different order than the one used by + * CSN.1. + * + * \param data_block_idx The block index, 0..1 for header type 1, 0 otherwise + * \param src A pointer to the start of the RLC block (incl. the header) + * \param buffer A data area of a least the size of the RLC block + * \returns the number of bytes copied + */ +unsigned int Encoding::rlc_copy_from_aligned_buffer( + const struct gprs_rlc_data_info *rlc, + unsigned int data_block_idx, + uint8_t *dst, const uint8_t *buffer) +{ + unsigned int hdr_bytes; + unsigned int extra_bits; + unsigned int i; + + uint8_t c, last_c; + const uint8_t *src; + const struct gprs_rlc_data_block_info *rdbi; + + OSMO_ASSERT(data_block_idx < rlc->num_data_blocks); + rdbi = &rlc->block_info[data_block_idx]; + + hdr_bytes = rlc->data_offs_bits[data_block_idx] / 8; + extra_bits = (rlc->data_offs_bits[data_block_idx] % 8); + + if (extra_bits == 0) { + /* It is aligned already */ + memmove(dst + hdr_bytes, buffer, rdbi->data_len); + return rdbi->data_len; + } + + src = buffer; + dst = dst + hdr_bytes; + last_c = *dst << (8 - extra_bits); + + for (i = 0; i < rdbi->data_len; 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)); + + return rdbi->data_len; +} diff --git a/src/encoding.h b/src/encoding.h index ff62bc90..6764ce41 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -68,4 +68,12 @@ public: uint8_t *identity, uint8_t chan_needed); static unsigned write_packet_paging_request(bitvec * dest); + + static int rlc_write_dl_data_header( + const struct gprs_rlc_data_info *rlc, + uint8_t *data); + static unsigned int rlc_copy_from_aligned_buffer( + const struct gprs_rlc_data_info *rlc, + unsigned int data_block_idx, + uint8_t *dst, const uint8_t *buffer); }; @@ -298,6 +298,21 @@ struct gprs_rlc_ul_header_egprs_3 { spare:1, dummy:1; } __attribute__ ((packed)); + +struct gprs_rlc_dl_header_egprs_3 { + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_a:1; + uint8_t tfi_b:4, + pr:2, + bsn1_a:2; + uint8_t bsn1_b:8; + uint8_t bsn1_c:1, + cps:4, + spb:2, + dummy:1; +} __attribute__ ((packed)); #else # error "Only little endian headers are supported yet. TODO: add missing structs" #endif diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp index 7bb81e47..11459457 100644 --- a/tests/edge/EdgeTest.cpp +++ b/tests/edge/EdgeTest.cpp @@ -23,6 +23,7 @@ #include "gprs_debug.h" #include "gprs_coding_scheme.h" #include "decoding.h" +#include "encoding.h" #include "rlc.h" extern "C" { @@ -36,6 +37,7 @@ extern "C" { } #include <errno.h> +#include <string.h> void *tall_pcu_ctx; int16_t spoof_mnc = 0, spoof_mcc = 0; @@ -481,6 +483,73 @@ static void test_rlc_unit_decoder() printf("=== end %s ===\n", __func__); } +static void test_rlc_unaligned_copy() +{ + uint8_t bits[256]; + uint8_t saved_block[256]; + uint8_t test_block[256]; + uint8_t out_block[256]; + GprsCodingScheme::Scheme scheme; + int pattern; + volatile unsigned int block_idx, i; + + for (scheme = GprsCodingScheme::CS1; + scheme < GprsCodingScheme::NUM_SCHEMES; + scheme = GprsCodingScheme::Scheme(scheme + 1)) + { + GprsCodingScheme cs(scheme); + + for (pattern = 0; pattern <= 0xff; pattern += 0xff) { + /* prepare test block */ + test_block[0] = pattern ^ 0xff; + for (i = 1; i + 1 < cs.maxDataBlockBytes(); i++) + test_block[i] = i; + test_block[cs.maxDataBlockBytes()-1] = pattern ^ 0xff; + + for (block_idx = 0; + block_idx < cs.numDataBlocks(); + block_idx++) + { + struct gprs_rlc_data_info rlc; + gprs_rlc_data_info_init_dl(&rlc, cs); + + memset(bits, pattern, sizeof(bits)); + Decoding::rlc_copy_to_aligned_buffer( + &rlc, block_idx, bits, saved_block); + + fprintf(stderr, + "Test data block: %s\n", + osmo_hexdump(test_block, cs.maxDataBlockBytes())); + + Encoding::rlc_copy_from_aligned_buffer( + &rlc, block_idx, bits, test_block); + + fprintf(stderr, + "Encoded message block, %s, idx %d, " + "pattern %02x: %s\n", + rlc.cs.name(), block_idx, pattern, + osmo_hexdump(bits, cs.sizeDL())); + + Decoding::rlc_copy_to_aligned_buffer( + &rlc, block_idx, bits, out_block); + + fprintf(stderr, + "Out data block: %s\n", + osmo_hexdump(out_block, cs.maxDataBlockBytes())); + /* restore original bits */ + Encoding::rlc_copy_from_aligned_buffer( + &rlc, block_idx, bits, saved_block); + + OSMO_ASSERT(memcmp(test_block, out_block, + rlc.cs.maxDataBlockBytes()) == 0); + + for (i = 0; i < sizeof(bits); i++) + OSMO_ASSERT(bits[i] == pattern); + } + } + } +} + static void test_rlc_info_init() { struct gprs_rlc_data_info rlc; @@ -544,6 +613,7 @@ int main(int argc, char **argv) test_coding_scheme(); test_rlc_info_init(); test_rlc_unit_decoder(); + test_rlc_unaligned_copy(); if (getenv("TALLOC_REPORT_FULL")) talloc_report_full(tall_pcu_ctx, stderr); |