blob: fae529c37346ce225de5df9ddbcbe12b558a9350 [file] [log] [blame]
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +05301/* egprs_rlc_compression.h
2* Routines for EGPRS RLC bitmap compression handling
3*/
4#include <errno.h>
5#include <decoding.h>
6#include <arpa/inet.h>
7#include <string.h>
8#include <gprs_debug.h>
9#include <gprs_rlcmac.h>
10#include <egprs_rlc_compression.h>
11
12extern "C" {
13#include <osmocom/core/talloc.h>
14#include <osmocom/core/msgb.h>
15#include <osmocom/core/stats.h>
16}
17
18#define EGPRS_CODEWORDS 79 /* total number of codewords */
19
20struct egprs_compress_node{
21 struct egprs_compress_node *left;
22 struct egprs_compress_node *right;
23 int run_length;
24};
25
26extern void *tall_pcu_ctx;
27
28egprs_compress *egprs_compress::s_instance = 0;
29
30egprs_compress_node *egprs_compress::create_tree_node(void *parent)
31{
32 egprs_compress_node *new_node;
33
34 new_node = talloc_zero(parent, egprs_compress_node);
35 new_node->left = NULL;
36 new_node->right = NULL;
37 new_node->run_length = -1;
38 return new_node;
39}
40
41egprs_compress *egprs_compress::instance()
42{
43 if (!egprs_compress::s_instance)
44 egprs_compress::s_instance = new egprs_compress;
45 return egprs_compress::s_instance;
46}
47
48/* Expands the given tree by incorporating
49 * the given codewords.
50 * \param root[in] Root of ones or zeros tree
51 * \param cdwd[in] Array of code words
52 * number of codewords is EGPRS_CODEWORDS
53 */
54void egprs_compress::build_codewords(egprs_compress_node *root, const char *cdwd[])
55{
56 egprs_compress_node *iter;
57 int len;
58 int i;
59 int idx;
60
61 for (idx = 0; idx < EGPRS_CODEWORDS; idx++) {
62 len = strlen((const char *)cdwd[idx]);
63 iter = root;
64 for (i = 0; i < len; i++) {
65 if (cdwd[idx][i] == '0') {
66 if (!iter->left)
67 iter->left = create_tree_node(root);
68 iter = iter->left;
69 } else {
70 if (!iter->right)
71 iter->right = create_tree_node(root);
72 iter = iter->right;
73 }
74 }
75 if (iter) {
76 /* The first 64 run lengths are 0, 1, 2, ..., 63
77 * and the following ones are 64, 128, 192 described in
78 * section 9.1.10 of 3gpp 44.060 */
79 if (idx < 64)
80 iter->run_length = idx;
81 else
82 iter->run_length = (idx - 63) * 64;
83 }
84 }
85}
86
sivasankari8adfcd02017-01-16 15:41:21 +053087/*
88 * Terminating codes for uninterrupted sequences of 0 and 1 up to 64 bit length
89 * according to TS 44.060 9.1.10
90 */
91static const unsigned t4_term[2][64] = {
92 {
93 0b0000110111,
94 0b10,
95 0b11,
96 0b010,
97 0b011,
98 0b0011,
99 0b0010,
100 0b00011,
101 0b000101,
102 0b000100,
103 0b0000100,
104 0b0000101,
105 0b0000111,
106 0b00000100,
107 0b00000111,
108 0b000011000,
109 0b0000010111,
110 0b0000011000,
111 0b0000001000,
112 0b00001100111,
113 0b00001101000,
114 0b00001101100,
115 0b00000110111,
116 0b00000101000,
117 0b00000010111,
118 0b00000011000,
119 0b000011001010,
120 0b000011001011,
121 0b000011001100,
122 0b000011001101,
123 0b000001101000,
124 0b000001101001,
125 0b000001101010,
126 0b000001101011,
127 0b000011010010,
128 0b000011010011,
129 0b000011010100,
130 0b000011010101,
131 0b000011010110,
132 0b000011010111,
133 0b000001101100,
134 0b000001101101,
135 0b000011011010,
136 0b000011011011,
137 0b000001010100,
138 0b000001010101,
139 0b000001010110,
140 0b000001010111,
141 0b000001100100,
142 0b000001100101,
143 0b000001010010,
144 0b000001010011,
145 0b000000100100,
146 0b000000110111,
147 0b000000111000,
148 0b000000100111,
149 0b000000101000,
150 0b000001011000,
151 0b000001011001,
152 0b000000101011,
153 0b000000101100,
154 0b000001011010,
155 0b000001100110,
156 0b000001100111
157
158 },
159 {
160 0b00110101,
161 0b000111,
162 0b0111,
163 0b1000,
164 0b1011,
165 0b1100,
166 0b1110,
167 0b1111,
168 0b10011,
169 0b10100,
170 0b00111,
171 0b01000,
172 0b001000,
173 0b000011,
174 0b110100,
175 0b110101,
176 0b101010,
177 0b101011,
178 0b0100111,
179 0b0001100,
180 0b0001000,
181 0b0010111,
182 0b0000011,
183 0b0000100,
184 0b0101000,
185 0b0101011,
186 0b0010011,
187 0b0100100,
188 0b0011000,
189 0b00000010,
190 0b00000011,
191 0b00011010,
192 0b00011011,
193 0b00010010,
194 0b00010011,
195 0b00010100,
196 0b00010101,
197 0b00010110,
198 0b00010111,
199 0b00101000,
200 0b00101001,
201 0b00101010,
202 0b00101011,
203 0b00101100,
204 0b00101101,
205 0b00000100,
206 0b00000101,
207 0b00001010,
208 0b00001011,
209 0b01010010,
210 0b01010011,
211 0b01010100,
212 0b01010101,
213 0b00100100,
214 0b00100101,
215 0b01011000,
216 0b01011001,
217 0b01011010,
218 0b01011011,
219 0b01001010,
220 0b01001011,
221 0b00110010,
222 0b00110011,
223 0b00110100
224 }
225};
226static const unsigned t4_term_length[2][64] = {
227 {10, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},
228 {8, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
229};
230
231static const unsigned t4_min_term_length[] = {2, 4};
232static const unsigned t4_min_make_up_length[] = {10, 5};
233
234static const unsigned t4_max_term_length[] = {12, 8};
235static const unsigned t4_max_make_up_length[] = {13, 9};
236
237static const unsigned t4_make_up_length[2][15] = {
238 {10, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13},
239 {5, 5, 6, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9}
240};
241
242static const unsigned t4_make_up_ind[15] = {64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960};
243
244static const unsigned t4_make_up[2][15] = {
245 {
246 0b0000001111,
247 0b000011001000,
248 0b000011001001,
249 0b000001011011,
250 0b000000110011,
251 0b000000110100,
252 0b000000110101,
253 0b0000001101100,
254 0b0000001101101,
255 0b0000001001010,
256 0b0000001001011,
257 0b0000001001100,
258 0b0000001001101,
259 0b0000001110010,
260 0b0000001110011
261 },
262 {
263 0b11011,
264 0b10010,
265 0b010111,
266 0b0110111,
267 0b00110110,
268 0b00110111,
269 0b01100100,
270 0b01100101,
271 0b01101000,
272 0b01100111,
273 0b011001100,
274 0b011001101,
275 0b011010010,
276 0b011010011,
277 0b011010100
278 }
279};
280
281/* The code words for one run length and zero
282 * run length are described in table 9.1.10.1
283 * of 3gpp 44.060
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530284 */
285const char *one_run_len_code_list[EGPRS_CODEWORDS] = {
286 "00110101",
287 "000111",
288 "0111",
289 "1000",
290 "1011",
291 "1100",
292 "1110",
293 "1111",
294 "10011",
295 "10100",
296 "00111",
297 "01000",
298 "001000",
299 "000011",
300 "110100",
301 "110101",
302 "101010",
303 "101011",
304 "0100111",
305 "0001100",
306 "0001000",
307 "0010111",
308 "0000011",
309 "0000100",
310 "0101000",
311 "0101011",
312 "0010011",
313 "0100100",
314 "0011000",
315 "00000010",
316 "00000011",
317 "00011010",
318 "00011011",
319 "00010010",
320 "00010011",
321 "00010100",
322 "00010101",
323 "00010110",
324 "00010111",
325 "00101000",
326 "00101001",
327 "00101010",
328 "00101011",
329 "00101100",
330 "00101101",
331 "00000100",
332 "00000101",
333 "00001010",
334 "00001011",
335 "01010010",
336 "01010011",
337 "01010100",
338 "01010101",
339 "00100100",
340 "00100101",
341 "01011000",
342 "01011001",
343 "01011010",
344 "01011011",
345 "01001010",
346 "01001011",
347 "00110010",
348 "00110011",
349 "00110100",
350 "11011",
351 "10010",
352 "010111",
353 "0110111",
354 "00110110",
355 "00110111",
356 "01100100",
357 "01100101",
358 "01101000",
359 "01100111",
360 "011001100",
361 "011001101",
362 "011010010",
363 "011010011",
364 "011010100"
365};
366
367const char *zero_run_len_code_list[EGPRS_CODEWORDS] = {
368 "0000110111",
369 "10",
370 "11",
371 "010",
372 "011",
373 "0011",
374 "0010",
375 "00011",
376 "000101",
377 "000100",
378 "0000100",
379 "0000101",
380 "0000111",
381 "00000100",
382 "00000111",
383 "000011000",
384 "0000010111",
385 "0000011000",
386 "0000001000",
387 "00001100111",
388 "00001101000",
389 "00001101100",
390 "00000110111",
391 "00000101000",
392 "00000010111",
393 "00000011000",
394 "000011001010",
395 "000011001011",
396 "000011001100",
397 "000011001101",
398 "000001101000",
399 "000001101001",
400 "000001101010",
401 "000001101011",
402 "000011010010",
403 "000011010011",
404 "000011010100",
405 "000011010101",
406 "000011010110",
407 "000011010111",
408 "000001101100",
409 "000001101101",
410 "000011011010",
411 "000011011011",
412 "000001010100",
413 "000001010101",
414 "000001010110",
415 "000001010111",
416 "000001100100",
417 "000001100101",
418 "000001010010",
419 "000001010011",
420 "000000100100",
421 "000000110111",
422 "000000111000",
423 "000000100111",
424 "000000101000",
425 "000001011000",
426 "000001011001",
427 "000000101011",
428 "000000101100",
429 "000001011010",
430 "000001100110",
431 "000001100111",
432 "0000001111",
433 "000011001000",
434 "000011001001",
435 "000001011011",
436 "000000110011",
437 "000000110100",
438 "000000110101",
439 "0000001101100",
440 "0000001101101",
441 "0000001001010",
442 "0000001001011",
443 "0000001001100",
444 "0000001001101",
445 "0000001110010",
446 "0000001110011"
447};
448
449/* Calculate runlength of a codeword
450 * \param root[in] Root of Ones or Zeros tree
451 * \param bmbuf[in] Received compressed bitmap buf
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200452 * \param length[in] Length of bitmap buf in bits
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530453 * \param bit_pos[in] The start bit pos to read codeword
454 * \param len_codewd[in] Length of code word
455 * \param rlen[out] Calculated run length
456 */
457static int search_runlen(
458 egprs_compress_node *root,
459 const uint8_t *bmbuf,
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200460 uint8_t length,
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530461 uint8_t bit_pos,
462 uint8_t *len_codewd,
463 uint16_t *rlen)
464{
465 egprs_compress_node *iter;
466 uint8_t dir;
467
468 iter = root;
469 *len_codewd = 0;
470
471 while (iter->run_length == -1) {
472 if ((!iter->left) && (!iter->right))
473 return -1;
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200474 if (bit_pos >= length)
475 return -1;
476
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530477 /* get the bit value at the bitpos and put it in right most of dir */
478 dir = (bmbuf[bit_pos/8] >> (7 - (bit_pos & 0x07))) & 0x01;
479 bit_pos++;
480 (*len_codewd)++;
481 if (!dir && (iter->left != NULL))
482 iter = iter->left;
483 else if (dir && (iter->right != NULL))
484 iter = iter->right;
485 else
486 return -1;
487 }
488 LOGP(DRLCMACUL, LOGL_DEBUG, "Run_length = %d\n", iter->run_length);
489 *rlen = iter->run_length;
490 return 1;
491}
492
493/* Decompress received block bitmap
494 * \param compress_bmap_len[in] Compressed bitmap length
495 * \param start[in] Starting Color Code, true if bitmap starts with a run
496 * length of ones, false if zeros; see 9.1.10, 3GPP 44.060.
497 * \param orig_crbb_buf[in] Received block crbb bitmap
498 * \param dest[out] Uncompressed bitvector
499 */
500int egprs_compress::decompress_crbb(
501 int8_t compress_bmap_len,
502 bool start,
503 const uint8_t *orig_crbb_buf,
504 bitvec *dest)
505{
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200506 int8_t remaining_bmap_len = compress_bmap_len;
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530507 uint8_t bit_pos = 0;
508 uint8_t data;
509 egprs_compress_node *list = NULL;
510 uint8_t nbits = 0; /* number of bits of codeword */
511 uint16_t run_length = 0;
512 uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
513 unsigned wp = dest->cur_bit;
514 int rc = 0;
515 egprs_compress *compress = instance();
516
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200517 while (remaining_bmap_len > 0) {
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530518 if (start) {
519 data = 0xff;
520 list = compress->ones_list;
521 } else {
522 data = 0x00;
523 list = compress->zeros_list;
524 }
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200525 rc = search_runlen(list, orig_crbb_buf, compress_bmap_len,
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530526 bit_pos, &nbits, &run_length);
527 if (rc == -1)
528 return -1;
529 /* If run length > 64, need makeup and terminating code */
530 if (run_length < 64)
531 start = !start;
532 cbmaplen = cbmaplen + run_length;
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200533
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530534 /* put run length of Ones in uncompressed bitmap */
535 while (run_length != 0) {
536 if (run_length > 8) {
Alexander Couzensccde5c92017-02-04 03:10:08 +0100537 bitvec_write_field(dest, &wp, data, 8);
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530538 run_length = run_length - 8;
539 } else {
Alexander Couzensccde5c92017-02-04 03:10:08 +0100540 bitvec_write_field(dest, &wp, data, run_length);
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530541 run_length = 0;
542 }
543 }
544 bit_pos = bit_pos + nbits;
Alexander Couzens2d24eba2019-06-17 01:41:29 +0200545 remaining_bmap_len = remaining_bmap_len - nbits;
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530546 }
547 return 0;
548}
549
550void egprs_compress::decode_tree_init()
551{
552 ones_list = create_tree_node(tall_pcu_ctx);
553 zeros_list = create_tree_node(tall_pcu_ctx);
554 build_codewords(ones_list, one_run_len_code_list);
555 build_codewords(zeros_list, zero_run_len_code_list);
556}
557
558egprs_compress::egprs_compress()
559{
560 decode_tree_init();
561}
562
sivasankari8adfcd02017-01-16 15:41:21 +0530563/* Compress received block bitmap
564 * \param run_len_cnt[in] Count of number of 1's and 0's
565 * \param codewrd_bitmap[in] Code word for coresponding run length.
566 * \param crbb_vec[out] compressed bitvector.
567 */
568static void compress_bitmap(
569 uint16_t *run_len_cnt, /* cnt: run length count */
570 uint16_t *codewrd_bitmap, /* code word */
571 int16_t *codewrd_len, /* number of bits in the code word */
572 bitvec *crbb_vec, /* bitmap buffer to put code word in */
573 bool start)
574{
575 int i = 0;
576 unsigned writeIndex = crbb_vec->cur_bit;
577 *codewrd_bitmap = 0;
578 *codewrd_len = 0;
579 if (*run_len_cnt >= 64) {
580 for (i = 0; i < 15; i++) {
581 if (t4_make_up_ind[i] == *run_len_cnt) {
582 *codewrd_bitmap = t4_make_up[start][i];
583 *codewrd_len = t4_make_up_length[start][i];
584 }
585 }
586 } else {
587 *codewrd_bitmap = t4_term[start][*run_len_cnt];
588 *codewrd_len = t4_term_length[start][*run_len_cnt];
589 }
Alexander Couzensccde5c92017-02-04 03:10:08 +0100590 bitvec_write_field(crbb_vec, &writeIndex, *codewrd_bitmap, *codewrd_len);
sivasankari8adfcd02017-01-16 15:41:21 +0530591}
592
593/* Compress received block bitmap */
594int egprs_compress::osmo_t4_compress(struct bitvec *bv)
595{
596 uint8_t crbb_len = 0;
597 uint8_t uclen_crbb = 0;
598 uint8_t crbb_bitmap[127] = {'\0'};
599 bool start = (bv->data[0] & 0x80)>>7;
600 struct bitvec crbb_vec;
601
602 crbb_vec.data = crbb_bitmap;
603 crbb_vec.cur_bit = 0;
604 crbb_vec.data_len = 127;
605 bv->data_len = bv->cur_bit;
606 bv->cur_bit = 0;
607 if (egprs_compress::compress_rbb(bv, &crbb_vec, &uclen_crbb, 23*8)) {
608 memcpy(bv->data, crbb_bitmap, (crbb_len+7)/8);
609 bv->cur_bit = crbb_len;
610 bv->data_len = (crbb_len+7)/8;
611 return start;
612 }
613 else
614 printf("Encode failed\n");
615 return -1;
616}
617
618/*! \brief compression algorithm using T4 encoding
619 * the compressed bitmap's are copied in crbb_bitmap
620 * \param[in] rbb_vec bit vector to be encoded
621 * \return 1 if compression is success or 0 for failure
622 */
623int egprs_compress::compress_rbb(
624 struct bitvec *urbb_vec,
625 struct bitvec *crbb_vec,
626 uint8_t *uclen_crbb, /* Uncompressed bitmap len in CRBB */
Alexander Couzens6d732052019-06-16 16:13:42 +0200627 uint8_t max_bits) /* max remaining bits */
sivasankari8adfcd02017-01-16 15:41:21 +0530628{
629 bool run_len_bit;
630 int buflen = urbb_vec->cur_bit;
631 int total_bits = urbb_vec->cur_bit;
632 uint16_t rlen;
633 uint16_t temprl = 0;
634 uint16_t cbmap = 0; /* Compressed code word */
635 int16_t nbits; /* Length of code word */
636 uint16_t uclen = 0;
637 int16_t clen = 0;
638 bool start; /* Starting color code see 9.1.10, 3GPP 44.060 */
639 urbb_vec->cur_bit = 0;
640 run_len_bit = (urbb_vec->data[0] & 0x80)>>7;
641 while (buflen > 0) {
642 temprl = 0;
643 /* Find Run length */
644 if (run_len_bit == 1)
645 rlen = bitvec_rl_curbit(urbb_vec, true, total_bits);
646 else
647 rlen = bitvec_rl_curbit(urbb_vec, false, total_bits);
648 buflen = buflen - rlen;
649 /* if rlen > 64 need Makeup code word */
650 /*Compress the bits */
651 if (run_len_bit == 0) {
652 start = 0;
653 if (rlen >= 64) {
654 temprl = (rlen/64)*64;
655 compress_bitmap(&temprl, &cbmap, &nbits,
656 crbb_vec, start);
657 clen = clen + nbits;
658 }
659 temprl = MOD64(rlen);
660 compress_bitmap(&temprl, &cbmap, &nbits,
661 crbb_vec, start);
662 /* next time the run length will be Ones */
663 run_len_bit = 1;
664 } else {
665 start = 1;
666 if (rlen >= 64) {
667 temprl = (rlen/64)*64;
668 compress_bitmap(&temprl, &cbmap, &nbits,
669 crbb_vec, start);
670 clen = clen + nbits;
671 }
672 temprl = MOD64(rlen);
673 compress_bitmap(&temprl, &cbmap, &nbits,
674 crbb_vec, start);
675
676 /* next time the run length will be Zeros */
677 run_len_bit = 0;
678 }
679 uclen = uclen + rlen;
680 clen = clen + nbits;
681 /*compressed bitmap exceeds the buffer space */
682 if (clen > max_bits) {
683 uclen = uclen - rlen;
684 clen = clen - nbits;
685 break;
686 }
687 }
688 crbb_vec->cur_bit = clen;
689 *uclen_crbb = uclen;
690 if (clen >= uclen)
691 /* No Gain is observed, So no need to compress */
692 return 0;
Pau Espin Pedrol6e251192021-05-19 11:58:56 +0200693 LOGP(DRLCMACUL, LOGL_DEBUG, "CRBB bitmap = %s\n", osmo_hexdump(crbb_vec->data, (crbb_vec->cur_bit+7)/8));
694 /* Add compressed bitmap to final buffer */
695 return 1;
sivasankari8adfcd02017-01-16 15:41:21 +0530696}