edge: Add Encoding::rlc_data_to_dl_append
This function appends a single chunk to an RLC downlink data block. The implementation is basically taken from the gprs_rlcmac_dl_tbf::create_new_bsn method without the TBF related functionality and any side effects. Note that it still only supports GRPS. Sponsored-by: On-Waves ehf
This commit is contained in:
parent
3a3b6a7e86
commit
14bb0947b4
121
src/encoding.cpp
121
src/encoding.cpp
|
@ -751,3 +751,124 @@ unsigned int Encoding::rlc_copy_from_aligned_buffer(
|
|||
|
||||
return rdbi->data_len;
|
||||
}
|
||||
|
||||
Encoding::AppendResult Encoding::rlc_data_to_dl_append(
|
||||
struct gprs_rlc_data_block_info *rdbi,
|
||||
gprs_llc *llc, int *offset, int *num_chunks,
|
||||
uint8_t *data_block,
|
||||
bool is_final)
|
||||
{
|
||||
int chunk;
|
||||
int space;
|
||||
struct rlc_li_field *li;
|
||||
uint8_t *delimiter, *data, *e_pointer;
|
||||
|
||||
data = data_block + *offset;
|
||||
delimiter = data_block + *num_chunks;
|
||||
e_pointer = (*num_chunks ? delimiter - 1 : NULL);
|
||||
|
||||
chunk = llc->chunk_size();
|
||||
space = rdbi->data_len - *offset;
|
||||
|
||||
/* if chunk will exceed block limit */
|
||||
if (chunk > space) {
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
|
||||
"larger than space (%d) left in block: copy "
|
||||
"only remaining space, and we are done\n",
|
||||
chunk, space);
|
||||
/* block is filled, so there is no extension */
|
||||
if (e_pointer)
|
||||
*e_pointer |= 0x01;
|
||||
/* fill only space */
|
||||
llc->consume(data, space);
|
||||
/* return data block as message */
|
||||
*offset = rdbi->data_len;
|
||||
(*num_chunks)++;
|
||||
return AR_NEED_MORE_BLOCKS;
|
||||
}
|
||||
/* if FINAL chunk would fit precisely in space left */
|
||||
if (chunk == space && is_final)
|
||||
{
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
|
||||
"would exactly fit into space (%d): because "
|
||||
"this is a final block, we don't add length "
|
||||
"header, and we are done\n", chunk, space);
|
||||
/* block is filled, so there is no extension */
|
||||
if (e_pointer)
|
||||
*e_pointer |= 0x01;
|
||||
/* fill space */
|
||||
llc->consume(data, space);
|
||||
*offset = rdbi->data_len;
|
||||
(*num_chunks)++;
|
||||
rdbi->cv = 0;
|
||||
return AR_COMPLETED_BLOCK_FILLED;
|
||||
}
|
||||
/* if chunk would fit exactly in space left */
|
||||
if (chunk == space) {
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
|
||||
"would exactly fit into space (%d): add length "
|
||||
"header with LI=0, to make frame extend to "
|
||||
"next block, and we are done\n", chunk, space);
|
||||
/* make space for delimiter */
|
||||
if (delimiter != data)
|
||||
memmove(delimiter + 1, delimiter,
|
||||
data - delimiter);
|
||||
data++;
|
||||
(*offset)++;
|
||||
space--;
|
||||
/* add LI with 0 length */
|
||||
li = (struct rlc_li_field *)delimiter;
|
||||
li->e = 1; /* not more extension */
|
||||
li->m = 0; /* shall be set to 0, in case of li = 0 */
|
||||
li->li = 0; /* chunk fills the complete space */
|
||||
rdbi->e = 0; /* 0: extensions present */
|
||||
// no need to set e_pointer nor increase delimiter
|
||||
/* fill only space, which is 1 octet less than chunk */
|
||||
llc->consume(data, space);
|
||||
/* return data block as message */
|
||||
*offset = rdbi->data_len;
|
||||
(*num_chunks)++;
|
||||
return AR_NEED_MORE_BLOCKS;
|
||||
}
|
||||
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d is less "
|
||||
"than remaining space (%d): add length header to "
|
||||
"to delimit LLC frame\n", chunk, space);
|
||||
/* the LLC frame chunk ends in this block */
|
||||
/* make space for delimiter */
|
||||
if (delimiter != data)
|
||||
memmove(delimiter + 1, delimiter, data - delimiter);
|
||||
data++;
|
||||
(*offset)++;
|
||||
space--;
|
||||
/* add LI to delimit frame */
|
||||
li = (struct rlc_li_field *)delimiter;
|
||||
li->e = 0; /* Extension bit, maybe set later */
|
||||
li->m = 0; /* will be set later, if there is more LLC data */
|
||||
li->li = chunk; /* length of chunk */
|
||||
rdbi->e = 0; /* 0: extensions present */
|
||||
(*num_chunks)++;
|
||||
/* copy (rest of) LLC frame to space and reset later */
|
||||
llc->consume(data, chunk);
|
||||
data += chunk;
|
||||
space -= chunk;
|
||||
(*offset) += chunk;
|
||||
/* if we have more data and we have space left */
|
||||
if (space > 0 && !is_final) {
|
||||
li->m = 1; /* we indicate more frames to follow */
|
||||
return AR_COMPLETED_SPACE_LEFT;
|
||||
}
|
||||
/* if we don't have more LLC frames */
|
||||
if (is_final) {
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "
|
||||
"done.\n");
|
||||
li->e = 1; /* we cannot extend */
|
||||
rdbi->cv = 0;
|
||||
return AR_COMPLETED_BLOCK_FILLED;
|
||||
}
|
||||
/* we have no space left */
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "
|
||||
"done.\n");
|
||||
li->e = 1; /* we cannot extend */
|
||||
return AR_COMPLETED_BLOCK_FILLED;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
struct gprs_rlcmac_bts;
|
||||
struct gprs_rlcmac_tbf;
|
||||
struct bitvec;
|
||||
struct gprs_llc;
|
||||
struct gprs_rlc_data_block_info;
|
||||
|
||||
/**
|
||||
* I help with encoding data into CSN1 messages.
|
||||
|
@ -76,4 +78,16 @@ public:
|
|||
const struct gprs_rlc_data_info *rlc,
|
||||
unsigned int data_block_idx,
|
||||
uint8_t *dst, const uint8_t *buffer);
|
||||
|
||||
enum AppendResult {
|
||||
AR_NEED_MORE_BLOCKS,
|
||||
AR_COMPLETED_SPACE_LEFT,
|
||||
AR_COMPLETED_BLOCK_FILLED,
|
||||
};
|
||||
|
||||
static AppendResult rlc_data_to_dl_append(
|
||||
struct gprs_rlc_data_block_info *rdbi,
|
||||
gprs_llc *llc, int *offset, int *num_chunks,
|
||||
uint8_t *data,
|
||||
bool is_final);
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "decoding.h"
|
||||
#include "encoding.h"
|
||||
#include "rlc.h"
|
||||
#include "llc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pcu_vty.h"
|
||||
|
@ -483,6 +484,255 @@ static void test_rlc_unit_decoder()
|
|||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void test_rlc_unit_encoder()
|
||||
{
|
||||
struct gprs_rlc_data_block_info rdbi = {0};
|
||||
GprsCodingScheme cs;
|
||||
uint8_t data[74];
|
||||
uint8_t llc_data[1500] = {0,};
|
||||
int num_chunks = 0;
|
||||
int write_offset;
|
||||
struct gprs_llc llc;
|
||||
Encoding::AppendResult ar;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
llc.init();
|
||||
|
||||
/* TS 44.060, B.1 */
|
||||
cs = GprsCodingScheme::CS4;
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 11);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_SPACE_LEFT);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 11);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 26);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_SPACE_LEFT);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 2 + 11 + 26);
|
||||
OSMO_ASSERT(num_chunks == 2);
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 99);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(rdbi.cv != 0);
|
||||
OSMO_ASSERT(write_offset == (int)rdbi.data_len);
|
||||
OSMO_ASSERT(num_chunks == 3);
|
||||
|
||||
OSMO_ASSERT(data[0] == ((11 << 2) | (1 << 1) | (0 << 0)));
|
||||
OSMO_ASSERT(data[1] == ((26 << 2) | (1 << 1) | (1 << 0)));
|
||||
OSMO_ASSERT(data[2] == 0);
|
||||
|
||||
/* TS 44.060, B.2 */
|
||||
cs = GprsCodingScheme::CS1;
|
||||
|
||||
/* Block 1 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 20);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 19);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
OSMO_ASSERT(data[0] == ((0 << 2) | (0 << 1) | (1 << 0)));
|
||||
OSMO_ASSERT(data[1] == 0);
|
||||
|
||||
/* Block 2 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
OSMO_ASSERT(llc.chunk_size() == 1);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_SPACE_LEFT);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 1);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 99);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 1 + 18);
|
||||
OSMO_ASSERT(num_chunks == 2);
|
||||
|
||||
OSMO_ASSERT(data[0] == ((1 << 2) | (1 << 1) | (1 << 0)));
|
||||
OSMO_ASSERT(data[1] == 0);
|
||||
|
||||
/* TS 44.060, B.3 */
|
||||
cs = GprsCodingScheme::CS1;
|
||||
|
||||
/* Block 1 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 7);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_SPACE_LEFT);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 7);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 11);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_BLOCK_FILLED);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 2 + 7 + 11);
|
||||
OSMO_ASSERT(num_chunks == 2);
|
||||
|
||||
OSMO_ASSERT(data[0] == ((7 << 2) | (1 << 1) | (0 << 0)));
|
||||
OSMO_ASSERT(data[1] == ((11 << 2) | (0 << 1) | (1 << 0)));
|
||||
OSMO_ASSERT(data[2] == 0);
|
||||
|
||||
/* TS 44.060, B.4 */
|
||||
cs = GprsCodingScheme::CS1;
|
||||
|
||||
/* Block 1 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 99);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 1);
|
||||
OSMO_ASSERT(write_offset == 20);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
OSMO_ASSERT(rdbi.cv != 0);
|
||||
|
||||
OSMO_ASSERT(data[0] == 0);
|
||||
|
||||
/* TS 44.060, B.5 */
|
||||
cs = GprsCodingScheme::CS1;
|
||||
|
||||
/* Block 1 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 20);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, true);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_BLOCK_FILLED);
|
||||
OSMO_ASSERT(rdbi.e == 1);
|
||||
OSMO_ASSERT(write_offset == 20);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
OSMO_ASSERT(rdbi.cv == 0);
|
||||
|
||||
OSMO_ASSERT(data[0] == 0);
|
||||
|
||||
/* TS 44.060, B.7 */
|
||||
cs = GprsCodingScheme::CS1;
|
||||
|
||||
/* Block 1 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 30);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 1);
|
||||
OSMO_ASSERT(write_offset == 20);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
OSMO_ASSERT(data[0] == 0);
|
||||
|
||||
/* Block 2 */
|
||||
gprs_rlc_data_block_info_init(&rdbi, cs);
|
||||
num_chunks = 0;
|
||||
write_offset = 0;
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
OSMO_ASSERT(llc.chunk_size() == 10);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_COMPLETED_SPACE_LEFT);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 10);
|
||||
OSMO_ASSERT(num_chunks == 1);
|
||||
|
||||
llc.reset();
|
||||
llc.put_frame(llc_data, 99);
|
||||
|
||||
ar = Encoding::rlc_data_to_dl_append(&rdbi,
|
||||
&llc, &write_offset, &num_chunks, data, false);
|
||||
|
||||
OSMO_ASSERT(ar == Encoding::AR_NEED_MORE_BLOCKS);
|
||||
OSMO_ASSERT(rdbi.e == 0);
|
||||
OSMO_ASSERT(write_offset == 1 + 10 + 9);
|
||||
OSMO_ASSERT(num_chunks == 2);
|
||||
|
||||
OSMO_ASSERT(data[0] == ((10 << 2) | (1 << 1) | (1 << 0)));
|
||||
OSMO_ASSERT(data[1] == 0);
|
||||
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void test_rlc_unaligned_copy()
|
||||
{
|
||||
uint8_t bits[256];
|
||||
|
@ -614,6 +864,7 @@ int main(int argc, char **argv)
|
|||
test_rlc_info_init();
|
||||
test_rlc_unit_decoder();
|
||||
test_rlc_unaligned_copy();
|
||||
test_rlc_unit_encoder();
|
||||
|
||||
if (getenv("TALLOC_REPORT_FULL"))
|
||||
talloc_report_full(tall_pcu_ctx, stderr);
|
||||
|
|
|
@ -4,3 +4,5 @@
|
|||
=== end test_rlc_info_init ===
|
||||
=== start test_rlc_unit_decoder ===
|
||||
=== end test_rlc_unit_decoder ===
|
||||
=== start test_rlc_unit_encoder ===
|
||||
=== end test_rlc_unit_encoder ===
|
||||
|
|
Loading…
Reference in New Issue