Defines new structure for Tree node and Declaration of zero's run length code list and one's run length code list --- src/Makefile.am | 6 +- src/egprs_rlc_compression.cpp | 169 +++++++++++++++++++++++++++++++++++++++++ src/egprs_rlc_compression.h | 25 ++++++ 3 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 src/egprs_rlc_compression.cpp create mode 100644 src/egprs_rlc_compression.h
diff --git a/src/Makefile.am b/src/Makefile.am index 6428bef..981d5b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,7 +57,8 @@ libgprs_la_SOURCES = \ rlc.cpp \ osmobts_sock.cpp \ gprs_codel.c \ - gprs_coding_scheme.cpp + gprs_coding_scheme.cpp \ + egprs_rlc_compression.cpp
bin_PROGRAMS = \ osmo-pcu @@ -96,7 +97,8 @@ noinst_HEADERS = \ pcu_utils.h \ cxx_linuxlist.h \ gprs_codel.h \ - gprs_coding_scheme.h + gprs_coding_scheme.h \ + egprs_rlc_compression.h
osmo_pcu_SOURCES = pcu_main.cpp
diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp new file mode 100644 index 0000000..55ff595 --- /dev/null +++ b/src/egprs_rlc_compression.cpp @@ -0,0 +1,169 @@ +/* egprs_rlc_compression.h +* Routines for EGPRS RLC bitmap compression handling +*/ +#include <egprs_rlc_compression.h> +#include <errno.h> + +const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { + "00110101", + "000111", + "0111", + "1000", + "1011", + "1100", + "1110", + "1111", + "10011", + "10100", + "00111", + "01000", + "001000", + "000011", + "110100", + "110101", + "101010", + "101011", + "0100111", + "0001100", + "0001000", + "0010111", + "0000011", + "0000100", + "0101000", + "0101011", + "0010011", + "0100100", + "0011000", + "00000010", + "00000011", + "00011010", + "00011011", + "00010010", + "00010011", + "00010100", + "00010101", + "00010110", + "00010111", + "00101000", + "00101001", + "00101010", + "00101011", + "00101100", + "00101101", + "00000100", + "00000101", + "00001010", + "00001011", + "01010010", + "01010011", + "01010100", + "01010101", + "00100100", + "00100101", + "01011000", + "01011001", + "01011010", + "01011011", + "01001010", + "01001011", + "00110010", + "00110011", + "00110100", + "11011", + "10010", + "010111", + "0110111", + "00110110", + "00110111", + "01100100", + "01100101", + "01101000", + "01100111", + "011001100", + "011001101", + "011010010", + "011010011", + "011010100" +}; + +const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { + "0000110111", + "10", + "11", + "010", + "011", + "0011", + "0010", + "00011", + "000101", + "000100", + "0000100", + "0000101", + "0000111", + "00000100", + "00000111", + "000011000", + "0000010111", + "0000011000", + "0000001000", + "00001100111", + "00001101000", + "00001101100", + "00000110111", + "00000101000", + "00000010111", + "00000011000", + "000011001010", + "000011001011", + "000011001100", + "000011001101", + "000001101000", + "000001101001", + "000001101010", + "000001101011", + "000011010010", + "000011010011", + "000011010100", + "000011010101", + "000011010110", + "000011010111", + "000001101100", + "000001101101", + "000011011010", + "000011011011", + "000001010100", + "000001010101", + "000001010110", + "000001010111", + "000001100100", + "000001100101", + "000001010010", + "000001010011", + "000000100100", + "000000110111", + "000000111000", + "000000100111", + "000000101000", + "000001011000", + "000001011001", + "000000101011", + "000000101100", + "000001011010", + "000001100110", + "000001100111", + "0000001111", + "000011001000", + "000011001001", + "000001011011", + "000000110011", + "000000110100", + "000000110101", + "0000001101100", + "0000001101101", + "0000001001010", + "0000001001011", + "0000001001100", + "0000001001101", + "0000001110010", + "0000001110011" +}; diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h new file mode 100644 index 0000000..00d850e --- /dev/null +++ b/src/egprs_rlc_compression.h @@ -0,0 +1,25 @@ +/* egprs_rlc_compression.h + * Routines for EGPRS RLC bitmap compression handling + */ +#include <gprs_rlcmac.h> +#include <gprs_debug.h> + +extern "C" { +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/stats.h> +} + +#include <arpa/inet.h> +#include <errno.h> +#include <string.h> + +#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ +#define BITS_TO_BYTES(X) (X ? (X/8):0)+1 +#define MOD8(X) (((X)+8) & (0x07)) + +typedef struct node { + struct node *left; + struct node *right; + uint16_t *run_length; +} Node;
This patch includes the changes to build the tree of code words to save run length during BTS initialization --- src/egprs_rlc_compression.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ src/egprs_rlc_compression.h | 37 +++++++++++++++++++++++++++++- src/pcu_main.cpp | 3 +++ 3 files changed, 90 insertions(+), 1 deletion(-)
diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp index 55ff595..4c17a17 100644 --- a/src/egprs_rlc_compression.cpp +++ b/src/egprs_rlc_compression.cpp @@ -3,6 +3,57 @@ */ #include <egprs_rlc_compression.h> #include <errno.h> +#include <decoding.h> + +egprs_compress *egprs_compress::s_instance = 0; +Node *egprs_compress::ones_list = NULL; +Node *egprs_compress::zeros_list = NULL; + +void egprs_compress::build_codeword(Node *root, const char *cdwd[]) +{ + Node *iter; /* iterate the node on the tree */ + int len; /* length of the code word */ + int i; /* iterater */ + uint16_t idx; /* interate index of the code word table */ + + root->left = NULL; + root->right = NULL; + root->run_length = NULL; + + for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) { + len = strlen((const char *)cdwd[idx]); + iter = root; + for (i = 0; i < len; i++) { + if (cdwd[idx][i] == '0') { + if (iter->left == NULL) { + iter->left = (Node *)malloc(sizeof(Node)); + /* create a clean node */ + iter->left->left = NULL; + iter->left->right = NULL; + iter->left->run_length = NULL; + } + iter = iter->left; + } else if (cdwd[idx][i] == '1') { + if (iter->right == NULL) { + iter->right = (Node *)malloc(sizeof(Node)); + /* create a clean node */ + iter->right->left = NULL; + iter->right->right = NULL; + iter->right->run_length = NULL; + } + iter = iter->right; + } + } + if (iter != NULL) { + iter->run_length = (uint16_t *)malloc(sizeof(uint16_t)); + *(iter->run_length) = (uint16_t)NULL; + if (idx < 64) + *(iter->run_length) = idx; + else + *(iter->run_length) = (idx - 63) * 64; + } + } +}
const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = { "00110101", diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h index 00d850e..db1f880 100644 --- a/src/egprs_rlc_compression.h +++ b/src/egprs_rlc_compression.h @@ -15,7 +15,7 @@ extern "C" { #include <string.h>
#define MAX_CDWDTBL_LEN 79 /* total number of codewords */ -#define BITS_TO_BYTES(X) (X ? (X/8):0)+1 +#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1) #define MOD8(X) (((X)+8) & (0x07))
typedef struct node { @@ -23,3 +23,38 @@ typedef struct node { struct node *right; uint16_t *run_length; } Node; + +extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN]; +extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN]; + +/* Creating singleton class + */ +class egprs_compress +{ + static egprs_compress *s_instance; + + egprs_compress() + { + egprs_compress::ones_list = (Node *)malloc(sizeof(Node)); + egprs_compress::zeros_list = (Node *)malloc(sizeof(Node)); + } + void build_codeword(Node *root, const char *cdwd[]); +public: + static Node *ones_list; + static Node *zeros_list; + + void decode_tree_init(void) + { + egprs_compress::instance()->build_codeword( + egprs_compress::ones_list, one_run_len_code_list); + egprs_compress::instance()->build_codeword( + egprs_compress::zeros_list, zero_run_len_code_list); + } + static egprs_compress *instance() + { + if (!s_instance) + s_instance = new egprs_compress; + + return s_instance; + } +}; diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index f66c631..642ab33 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -28,6 +28,7 @@ #include <signal.h> #include <sched.h> #include <bts.h> +#include <egprs_rlc_compression.h> extern "C" { #include "pcu_vty.h" #include <osmocom/vty/telnet_interface.h> @@ -253,6 +254,8 @@ int main(int argc, char *argv[]) if (!bts->alloc_algorithm) bts->alloc_algorithm = alloc_algorithm_dynamic;
+ egprs_compress::instance()->decode_tree_init(); + rc = pcu_l1if_open();
if (rc < 0)
This patch includes the changes for compression algorithm which decompress the received CRBB bitmap and corresponding modification of EPDAN handling --- src/decoding.cpp | 30 ++++--------- src/decoding.h | 10 ++++- src/egprs_rlc_compression.cpp | 96 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 23 deletions(-)
diff --git a/src/decoding.cpp b/src/decoding.cpp index f2b548c..4535d1b 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -536,7 +536,6 @@ int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc, bool have_bitmap; int implicitly_acked_blocks; int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc;
if (desc->FINAL_ACK_INDICATION) return handle_final_ack(bits, bsn_begin, bsn_end, window); @@ -576,26 +575,15 @@ int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
if (crbb_len > 0) { int old_len = bits->cur_bit; - struct bitvec crbb; - - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - - if (rc < 0) { - LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); - /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ - goto aborted; - } + + LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist," + "CRBB LEN =%d and Starting color code =%d", + desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE); + + decompress_crbb(desc->CRBB_LENGTH, + desc->CRBB_STARTING_COLOR_CODE, + desc->CRBB, + bits);
LOGP(DRLCMACDL, LOGL_DEBUG, "CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n", diff --git a/src/decoding.h b/src/decoding.h index 58ecd18..5989907 100644 --- a/src/decoding.h +++ b/src/decoding.h @@ -60,6 +60,12 @@ public: struct gprs_rlc_dl_window *window); static int decode_gprs_acknack_bits( const Ack_Nack_Description_t *desc, - bitvec *bits, int *bsn_begin, int *bsn_end, - gprs_rlc_dl_window *window); + bitvec * bits, int *bsn_begin, int *bsn_end, + gprs_rlc_dl_window * window); + static void decompress_crbb( + int8_t compress_bmap_len, + uint8_t clr_code_bit, + const uint8_t *orig_buf, + bitvec * dest + ); }; diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp index 4c17a17..2e4dc05 100644 --- a/src/egprs_rlc_compression.cpp +++ b/src/egprs_rlc_compression.cpp @@ -218,3 +218,99 @@ const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = { "0000001110010", "0000001110011" }; + +int search_runlen( + Node *root, /* root of Ones or Zeros tree */ + const uint8_t *bmbuf, /* Received compressed bitmap buf */ + uint8_t bit_pos, /* the start bit pos to read codeword */ + uint8_t *len_codewd, /* length of codeword */ + uint16_t *rlen /* run length of Ones or Zeros */ + ) +{ + Node *iter; + uint8_t dir; + + iter = root; + *len_codewd = 0; + + while (iter->run_length == 0) { + if ((iter->left == NULL) && (iter->right == NULL)) + return -1; + + /* get the bit value at the bitpos and put it in right most of dir */ + dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1] + >>(7-(MOD8(bit_pos)))) & 0x01); + (bit_pos)++; + (*len_codewd)++; + + if (((dir&0x01) == 0) && (iter->left != NULL)) + iter = iter->left; + + else if (((dir&0x01) == 1) && (iter->right != NULL)) + iter = iter->right; + else + return -1; + } + (*rlen) = *(iter->run_length); + + return 1; +} /* search_runlen */ + +void Decoding::decompress_crbb( + int8_t compress_bmap_len, /* compressed bitmap length */ + uint8_t clr_code_bit, /* run length of Ones or Zeros */ + const uint8_t *orig_crbb_buf, /* received block crbb bitmap */ + bitvec * dest + ) +{ + + uint8_t bit_pos = 0; + uint8_t nbits = 0; /* number of bits of codeword */ + uint16_t run_length = 0; + uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */ + unsigned wp = 0; + + egprs_compress *compress = egprs_compress::instance(); + + while (compress_bmap_len >= 0) { + if (clr_code_bit == 1) { + search_runlen(compress->ones_list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit = 0; + cbmaplen = cbmaplen + run_length; + /* put run length of Ones in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, 0xff, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, 0xff, + run_length); + run_length = 0; + } + } + } else { + search_runlen(compress->zeros_list, orig_crbb_buf, + bit_pos, &nbits, &run_length); + /*If run length > 64, need makeup and terminating code*/ + if (run_length < 64) + clr_code_bit = 1; + cbmaplen = cbmaplen + run_length; + /* put run length of Zeros in uncompressed bitmap */ + while (run_length != 0) { + if (run_length > 8) { + bitvec_write_field(dest, wp, 0x00, 8); + run_length = run_length - 8; + } else { + bitvec_write_field(dest, wp, 0x00, + run_length); + run_length = 0; + } + } + } + bit_pos = bit_pos + nbits; + compress_bmap_len = compress_bmap_len - nbits; + } +} /* Decompress_CRBB */
Hi.
Thank you for your contribution. Could you clarify - what's the advantage of this approach over existing osmo_t4_decode() function? Is there some test case which works for one but not the other?
On Wed, Mar 30, 2016 at 05:35:01PM +0200, Max wrote:
Hi.
Thank you for your contribution. Could you clarify - what's the advantage of this approach over existing osmo_t4_decode() function? Is there some test case which works for one but not the other?
Not sure if it answers your question, but Sangamesh has posted a description of the patch a while ago in this and the following mails:
Date: Thu, 17 Mar 2016 15:43:36 +0000 From: Sangamesh Sajjan Sangamesh.Sajjan@radisys.com To: "osmocom-net-gprs@lists.osmocom.org" osmocom-net-gprs@lists.osmocom.org Subject: Proposal for new structure definition for compression algorithm
~Neels
Hello Max,
On Wednesday, March 30, 2016 9:05 PM, Max Suraev wrote:
Thank you for your contribution. Could you clarify - what's the advantage of this approach over existing osmo_t4_decode() function?
To highlight the difference between osmo_t4_decode and Tree based approach consider the example below,
if the received code word from the bitmap is “0111” and 0’s color code, then following steps involved to find run length using osmo_t4_decode 1. Initially it finds the number of bits based on the color code ( i.e if it is 0 color code, then read 2 bits or 4 bits if it is 1 color code ) 2. Since it is 0’s color code, read 2 bits from the received encoded bitmap 3. Check whether received 2 bits matches to any of the table entry ( i.e Makeup or Terminating table), if it doesn’t match then increment one more bit. o This will require loop of 15 followed by 64, So total of 79 comparison 4. Repeat the 3rd step if there is no matching code word
Hence to find 0111 code word from the table, osmo_t4_decode would require Two iterations of makeup table ( i.e 15 times each ) and terminating table ( i.e 64 times each) = ((15 + 64 )* 2 ) = 158 Third iteration where in exact match of code word is found in terminating table 3rd position = 15+3 So total 176 comparisons required to find the run length.
Usually there will be multiple code words in the received bitmap and each require multiple iterations to find run length as explained above.
Whereas In tree based approach two trees (i.e. ones list and zero list ) are used and entire code word traversing shall be done in respective tree in single traversal based on color code. • Read every bit from the received encoded bitmap and traverse the tree generated in init, If the bit is 0 traverse left and if it is 1 traverse right, Repeat this procedure till we find valid run length. • In example above for “0111” only 4 comparisons are required
Hence we see advantage in using tree based approach for CRBB decoding.
Is there some test case which works for one but not the other?
Currently we don’t have this specific test.
Regards, Sangamesh
Hi and thanks for detailed write-up.
So the code do exactly the same thing just more efficiently under the assumption that gcc optimization is not working. Is there a way to quantify this potential difference?
More specifically - is there a test-case which could demonstrate that this difference actually matters in practice?
I mean if the code in question constitute, for example, 10% of cpu time spent by osmo-pcu and the replacement would shrink it to 2% it's one thing. If it's 0.1% and 0.001% it's another: the relative gain in the latter case is bigger but I'm not sure it justifies allegedly higher code complexity.
On 03/31/2016 12:51 PM, Sangamesh Sajjan wrote:
Hello Max,
On Wednesday, March 30, 2016 9:05 PM, Max Suraev wrote:
Thank you for your contribution. Could you clarify - what's the advantage of this approach over existing osmo_t4_decode() function?
To highlight the difference between osmo_t4_decode and Tree based approach consider the example below,
if the received code word from the bitmap is “0111” and 0’s color code, then following steps involved to find run length using osmo_t4_decode
- Initially it finds the number of bits based on the color code ( i.e if it is 0 color code, then read 2 bits or 4 bits if it is 1 color code )
- Since it is 0’s color code, read 2 bits from the received encoded bitmap
- Check whether received 2 bits matches to any of the table entry ( i.e Makeup or Terminating table), if it doesn’t match then increment one more bit.
o This will require loop of 15 followed by 64, So total of 79 comparison 4. Repeat the 3rd step if there is no matching code word
Hence to find 0111 code word from the table, osmo_t4_decode would require Two iterations of makeup table ( i.e 15 times each ) and terminating table ( i.e 64 times each) = ((15 + 64 )* 2 ) = 158 Third iteration where in exact match of code word is found in terminating table 3rd position = 15+3 So total 176 comparisons required to find the run length.
Usually there will be multiple code words in the received bitmap and each require multiple iterations to find run length as explained above.
Whereas In tree based approach two trees (i.e. ones list and zero list ) are used and entire code word traversing shall be done in respective tree in single traversal based on color code. • Read every bit from the received encoded bitmap and traverse the tree generated in init, If the bit is 0 traverse left and if it is 1 traverse right, Repeat this procedure till we find valid run length. • In example above for “0111” only 4 comparisons are required
Hence we see advantage in using tree based approach for CRBB decoding.
Is there some test case which works for one but not the other?
Currently we don’t have this specific test.
Regards, Sangamesh
On 31 Mar 2016, at 13:04, Max msuraev@sysmocom.de wrote:
Hi and thanks for detailed write-up.
So the code do exactly the same thing just more efficiently under the assumption that gcc optimization is not working. Is there a way to quantify this potential difference?
Hi Sangamesh,
let me refer to Haralds mail on optmization and let me add that any "performance" improvement needs to have a benchmark that proves progress.
Looking at both implementations I am not convinced any of the two will be faster/slower than the other. Now the look-up in a tree might be log(N) in terms of compares but as each tree node is sitting on different memory (between we never use malloc, but always use talloc to allocate) the cache misses might make it slower than Max's version.
Please collect typical bitmaps, create a benchmark and compare the two implementations and we can make a decision.
thank you holger
On Thu, Mar 31, 2016 at 01:25:10PM +0200, Holger Freyther wrote:
Please collect typical bitmaps, create a benchmark and compare the two implementations and we can make a decision.
fair enough. +1.
~Neels
On Thu, Mar 31, 2016 at 01:04:36PM +0200, Max wrote:
Hi and thanks for detailed write-up.
So the code do exactly the same thing just more efficiently under the assumption that gcc optimization is not working.
Correct me if I'm wrong, but I firmly assume gcc optimization wouldn't implement a tree search algorithm for looking up items in a struct, when our code walks the struct linearly.
Is there a way to quantify this potential difference?
Hard besides timing, I guess, and we know how flaky timing based assumptions in a test suite can be. We'd have to count comparisons or something, i.e. add code just to prove efficiency. Let's not.
More specifically - is there a test-case which could demonstrate that this difference actually matters in practice?
I mean if the code in question constitute, for example, 10% of cpu time spent by osmo-pcu and the replacement would shrink it to 2% it's one thing. If it's 0.1% and 0.001% it's another: the relative gain in the latter case is bigger but I'm not sure it justifies allegedly higher code complexity.
I'm with Sangamesh here: if 176 comparisons reduce to 4 comparisons (factor 44!), and assuming a compression algorithm would do this for a whole stream of message bits, IMHO this justifies code complexity. Right?
I must reserve the fact that I still haven't read the entire code in detail, I'm just arguing theoretically.
~Neels
On 03/31/2016 12:51 PM, Sangamesh Sajjan wrote:
Hello Max,
On Wednesday, March 30, 2016 9:05 PM, Max Suraev wrote:
Thank you for your contribution. Could you clarify - what's the advantage of this approach over existing osmo_t4_decode() function?
To highlight the difference between osmo_t4_decode and Tree based approach consider the example below,
if the received code word from the bitmap is “0111” and 0’s color code, then following steps involved to find run length using osmo_t4_decode
- Initially it finds the number of bits based on the color code ( i.e if it is 0 color code, then read 2 bits or 4 bits if it is 1 color code )
- Since it is 0’s color code, read 2 bits from the received encoded bitmap
- Check whether received 2 bits matches to any of the table entry ( i.e Makeup or Terminating table), if it doesn’t match then increment one more bit.
o This will require loop of 15 followed by 64, So total of 79 comparison 4. Repeat the 3rd step if there is no matching code word
Hence to find 0111 code word from the table, osmo_t4_decode would require Two iterations of makeup table ( i.e 15 times each ) and terminating table ( i.e 64 times each) = ((15 + 64 )* 2 ) = 158 Third iteration where in exact match of code word is found in terminating table 3rd position = 15+3 So total 176 comparisons required to find the run length.
Usually there will be multiple code words in the received bitmap and each require multiple iterations to find run length as explained above.
Whereas In tree based approach two trees (i.e. ones list and zero list ) are used and entire code word traversing shall be done in respective tree in single traversal based on color code. • Read every bit from the received encoded bitmap and traverse the tree generated in init, If the bit is 0 traverse left and if it is 1 traverse right, Repeat this procedure till we find valid run length. • In example above for “0111” only 4 comparisons are required
Hence we see advantage in using tree based approach for CRBB decoding.
Is there some test case which works for one but not the other?
Currently we don’t have this specific test.
Regards, Sangamesh
-- Max Suraev msuraev@sysmocom.de http://www.sysmocom.de/ =======================================================================
- sysmocom - systems for mobile communications GmbH
- Alt-Moabit 93
- 10559 Berlin, Germany
- Sitz / Registered office: Berlin, HRB 134158 B
- Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte
osmocom-net-gprs@lists.osmocom.org