blob: 7eeb7d2a3a42600387ae3ca8f2bf573550411b8b [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
452 * \param bit_pos[in] The start bit pos to read codeword
453 * \param len_codewd[in] Length of code word
454 * \param rlen[out] Calculated run length
455 */
456static int search_runlen(
457 egprs_compress_node *root,
458 const uint8_t *bmbuf,
459 uint8_t bit_pos,
460 uint8_t *len_codewd,
461 uint16_t *rlen)
462{
463 egprs_compress_node *iter;
464 uint8_t dir;
465
466 iter = root;
467 *len_codewd = 0;
468
469 while (iter->run_length == -1) {
470 if ((!iter->left) && (!iter->right))
471 return -1;
472 /* get the bit value at the bitpos and put it in right most of dir */
473 dir = (bmbuf[bit_pos/8] >> (7 - (bit_pos & 0x07))) & 0x01;
474 bit_pos++;
475 (*len_codewd)++;
476 if (!dir && (iter->left != NULL))
477 iter = iter->left;
478 else if (dir && (iter->right != NULL))
479 iter = iter->right;
480 else
481 return -1;
482 }
483 LOGP(DRLCMACUL, LOGL_DEBUG, "Run_length = %d\n", iter->run_length);
484 *rlen = iter->run_length;
485 return 1;
486}
487
488/* Decompress received block bitmap
489 * \param compress_bmap_len[in] Compressed bitmap length
490 * \param start[in] Starting Color Code, true if bitmap starts with a run
491 * length of ones, false if zeros; see 9.1.10, 3GPP 44.060.
492 * \param orig_crbb_buf[in] Received block crbb bitmap
493 * \param dest[out] Uncompressed bitvector
494 */
495int egprs_compress::decompress_crbb(
496 int8_t compress_bmap_len,
497 bool start,
498 const uint8_t *orig_crbb_buf,
499 bitvec *dest)
500{
501
502 uint8_t bit_pos = 0;
503 uint8_t data;
504 egprs_compress_node *list = NULL;
505 uint8_t nbits = 0; /* number of bits of codeword */
506 uint16_t run_length = 0;
507 uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
508 unsigned wp = dest->cur_bit;
509 int rc = 0;
510 egprs_compress *compress = instance();
511
512 while (compress_bmap_len > 0) {
513 if (start) {
514 data = 0xff;
515 list = compress->ones_list;
516 } else {
517 data = 0x00;
518 list = compress->zeros_list;
519 }
520 rc = search_runlen(list, orig_crbb_buf,
521 bit_pos, &nbits, &run_length);
522 if (rc == -1)
523 return -1;
524 /* If run length > 64, need makeup and terminating code */
525 if (run_length < 64)
526 start = !start;
527 cbmaplen = cbmaplen + run_length;
528 /* put run length of Ones in uncompressed bitmap */
529 while (run_length != 0) {
530 if (run_length > 8) {
Alexander Couzensccde5c92017-02-04 03:10:08 +0100531 bitvec_write_field(dest, &wp, data, 8);
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530532 run_length = run_length - 8;
533 } else {
Alexander Couzensccde5c92017-02-04 03:10:08 +0100534 bitvec_write_field(dest, &wp, data, run_length);
Pravin Kumarvel0a4a6c12016-10-17 11:00:57 +0530535 run_length = 0;
536 }
537 }
538 bit_pos = bit_pos + nbits;
539 compress_bmap_len = compress_bmap_len - nbits;
540 }
541 return 0;
542}
543
544void egprs_compress::decode_tree_init()
545{
546 ones_list = create_tree_node(tall_pcu_ctx);
547 zeros_list = create_tree_node(tall_pcu_ctx);
548 build_codewords(ones_list, one_run_len_code_list);
549 build_codewords(zeros_list, zero_run_len_code_list);
550}
551
552egprs_compress::egprs_compress()
553{
554 decode_tree_init();
555}
556
sivasankari8adfcd02017-01-16 15:41:21 +0530557/* Compress received block bitmap
558 * \param run_len_cnt[in] Count of number of 1's and 0's
559 * \param codewrd_bitmap[in] Code word for coresponding run length.
560 * \param crbb_vec[out] compressed bitvector.
561 */
562static void compress_bitmap(
563 uint16_t *run_len_cnt, /* cnt: run length count */
564 uint16_t *codewrd_bitmap, /* code word */
565 int16_t *codewrd_len, /* number of bits in the code word */
566 bitvec *crbb_vec, /* bitmap buffer to put code word in */
567 bool start)
568{
569 int i = 0;
570 unsigned writeIndex = crbb_vec->cur_bit;
571 *codewrd_bitmap = 0;
572 *codewrd_len = 0;
573 if (*run_len_cnt >= 64) {
574 for (i = 0; i < 15; i++) {
575 if (t4_make_up_ind[i] == *run_len_cnt) {
576 *codewrd_bitmap = t4_make_up[start][i];
577 *codewrd_len = t4_make_up_length[start][i];
578 }
579 }
580 } else {
581 *codewrd_bitmap = t4_term[start][*run_len_cnt];
582 *codewrd_len = t4_term_length[start][*run_len_cnt];
583 }
Alexander Couzensccde5c92017-02-04 03:10:08 +0100584 bitvec_write_field(crbb_vec, &writeIndex, *codewrd_bitmap, *codewrd_len);
sivasankari8adfcd02017-01-16 15:41:21 +0530585}
586
587/* Compress received block bitmap */
588int egprs_compress::osmo_t4_compress(struct bitvec *bv)
589{
590 uint8_t crbb_len = 0;
591 uint8_t uclen_crbb = 0;
592 uint8_t crbb_bitmap[127] = {'\0'};
593 bool start = (bv->data[0] & 0x80)>>7;
594 struct bitvec crbb_vec;
595
596 crbb_vec.data = crbb_bitmap;
597 crbb_vec.cur_bit = 0;
598 crbb_vec.data_len = 127;
599 bv->data_len = bv->cur_bit;
600 bv->cur_bit = 0;
601 if (egprs_compress::compress_rbb(bv, &crbb_vec, &uclen_crbb, 23*8)) {
602 memcpy(bv->data, crbb_bitmap, (crbb_len+7)/8);
603 bv->cur_bit = crbb_len;
604 bv->data_len = (crbb_len+7)/8;
605 return start;
606 }
607 else
608 printf("Encode failed\n");
609 return -1;
610}
611
612/*! \brief compression algorithm using T4 encoding
613 * the compressed bitmap's are copied in crbb_bitmap
614 * \param[in] rbb_vec bit vector to be encoded
615 * \return 1 if compression is success or 0 for failure
616 */
617int egprs_compress::compress_rbb(
618 struct bitvec *urbb_vec,
619 struct bitvec *crbb_vec,
620 uint8_t *uclen_crbb, /* Uncompressed bitmap len in CRBB */
621 uint8_t max_bits) /* max remaining bits */
622{
623 bool run_len_bit;
624 int buflen = urbb_vec->cur_bit;
625 int total_bits = urbb_vec->cur_bit;
626 uint16_t rlen;
627 uint16_t temprl = 0;
628 uint16_t cbmap = 0; /* Compressed code word */
629 int16_t nbits; /* Length of code word */
630 uint16_t uclen = 0;
631 int16_t clen = 0;
632 bool start; /* Starting color code see 9.1.10, 3GPP 44.060 */
633 urbb_vec->cur_bit = 0;
634 run_len_bit = (urbb_vec->data[0] & 0x80)>>7;
635 while (buflen > 0) {
636 temprl = 0;
637 /* Find Run length */
638 if (run_len_bit == 1)
639 rlen = bitvec_rl_curbit(urbb_vec, true, total_bits);
640 else
641 rlen = bitvec_rl_curbit(urbb_vec, false, total_bits);
642 buflen = buflen - rlen;
643 /* if rlen > 64 need Makeup code word */
644 /*Compress the bits */
645 if (run_len_bit == 0) {
646 start = 0;
647 if (rlen >= 64) {
648 temprl = (rlen/64)*64;
649 compress_bitmap(&temprl, &cbmap, &nbits,
650 crbb_vec, start);
651 clen = clen + nbits;
652 }
653 temprl = MOD64(rlen);
654 compress_bitmap(&temprl, &cbmap, &nbits,
655 crbb_vec, start);
656 /* next time the run length will be Ones */
657 run_len_bit = 1;
658 } else {
659 start = 1;
660 if (rlen >= 64) {
661 temprl = (rlen/64)*64;
662 compress_bitmap(&temprl, &cbmap, &nbits,
663 crbb_vec, start);
664 clen = clen + nbits;
665 }
666 temprl = MOD64(rlen);
667 compress_bitmap(&temprl, &cbmap, &nbits,
668 crbb_vec, start);
669
670 /* next time the run length will be Zeros */
671 run_len_bit = 0;
672 }
673 uclen = uclen + rlen;
674 clen = clen + nbits;
675 /*compressed bitmap exceeds the buffer space */
676 if (clen > max_bits) {
677 uclen = uclen - rlen;
678 clen = clen - nbits;
679 break;
680 }
681 }
682 crbb_vec->cur_bit = clen;
683 *uclen_crbb = uclen;
684 if (clen >= uclen)
685 /* No Gain is observed, So no need to compress */
686 return 0;
687 else
688 LOGP(DRLCMACUL, LOGL_DEBUG, "CRBB bitmap = %s\n", osmo_hexdump(crbb_vec->data, (crbb_vec->cur_bit+7)/8));
689 /* Add compressed bitmap to final buffer */
690 return 1;
691}