blob: f4e6bdee743499115c8ac39e34ab99fd13bdeaf4 [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
87/* The code words for one run length and zero run length are described in
88 * table 9.1.10.1 of 3gpp 44.060
89 */
90const char *one_run_len_code_list[EGPRS_CODEWORDS] = {
91 "00110101",
92 "000111",
93 "0111",
94 "1000",
95 "1011",
96 "1100",
97 "1110",
98 "1111",
99 "10011",
100 "10100",
101 "00111",
102 "01000",
103 "001000",
104 "000011",
105 "110100",
106 "110101",
107 "101010",
108 "101011",
109 "0100111",
110 "0001100",
111 "0001000",
112 "0010111",
113 "0000011",
114 "0000100",
115 "0101000",
116 "0101011",
117 "0010011",
118 "0100100",
119 "0011000",
120 "00000010",
121 "00000011",
122 "00011010",
123 "00011011",
124 "00010010",
125 "00010011",
126 "00010100",
127 "00010101",
128 "00010110",
129 "00010111",
130 "00101000",
131 "00101001",
132 "00101010",
133 "00101011",
134 "00101100",
135 "00101101",
136 "00000100",
137 "00000101",
138 "00001010",
139 "00001011",
140 "01010010",
141 "01010011",
142 "01010100",
143 "01010101",
144 "00100100",
145 "00100101",
146 "01011000",
147 "01011001",
148 "01011010",
149 "01011011",
150 "01001010",
151 "01001011",
152 "00110010",
153 "00110011",
154 "00110100",
155 "11011",
156 "10010",
157 "010111",
158 "0110111",
159 "00110110",
160 "00110111",
161 "01100100",
162 "01100101",
163 "01101000",
164 "01100111",
165 "011001100",
166 "011001101",
167 "011010010",
168 "011010011",
169 "011010100"
170};
171
172const char *zero_run_len_code_list[EGPRS_CODEWORDS] = {
173 "0000110111",
174 "10",
175 "11",
176 "010",
177 "011",
178 "0011",
179 "0010",
180 "00011",
181 "000101",
182 "000100",
183 "0000100",
184 "0000101",
185 "0000111",
186 "00000100",
187 "00000111",
188 "000011000",
189 "0000010111",
190 "0000011000",
191 "0000001000",
192 "00001100111",
193 "00001101000",
194 "00001101100",
195 "00000110111",
196 "00000101000",
197 "00000010111",
198 "00000011000",
199 "000011001010",
200 "000011001011",
201 "000011001100",
202 "000011001101",
203 "000001101000",
204 "000001101001",
205 "000001101010",
206 "000001101011",
207 "000011010010",
208 "000011010011",
209 "000011010100",
210 "000011010101",
211 "000011010110",
212 "000011010111",
213 "000001101100",
214 "000001101101",
215 "000011011010",
216 "000011011011",
217 "000001010100",
218 "000001010101",
219 "000001010110",
220 "000001010111",
221 "000001100100",
222 "000001100101",
223 "000001010010",
224 "000001010011",
225 "000000100100",
226 "000000110111",
227 "000000111000",
228 "000000100111",
229 "000000101000",
230 "000001011000",
231 "000001011001",
232 "000000101011",
233 "000000101100",
234 "000001011010",
235 "000001100110",
236 "000001100111",
237 "0000001111",
238 "000011001000",
239 "000011001001",
240 "000001011011",
241 "000000110011",
242 "000000110100",
243 "000000110101",
244 "0000001101100",
245 "0000001101101",
246 "0000001001010",
247 "0000001001011",
248 "0000001001100",
249 "0000001001101",
250 "0000001110010",
251 "0000001110011"
252};
253
254/* Calculate runlength of a codeword
255 * \param root[in] Root of Ones or Zeros tree
256 * \param bmbuf[in] Received compressed bitmap buf
257 * \param bit_pos[in] The start bit pos to read codeword
258 * \param len_codewd[in] Length of code word
259 * \param rlen[out] Calculated run length
260 */
261static int search_runlen(
262 egprs_compress_node *root,
263 const uint8_t *bmbuf,
264 uint8_t bit_pos,
265 uint8_t *len_codewd,
266 uint16_t *rlen)
267{
268 egprs_compress_node *iter;
269 uint8_t dir;
270
271 iter = root;
272 *len_codewd = 0;
273
274 while (iter->run_length == -1) {
275 if ((!iter->left) && (!iter->right))
276 return -1;
277 /* get the bit value at the bitpos and put it in right most of dir */
278 dir = (bmbuf[bit_pos/8] >> (7 - (bit_pos & 0x07))) & 0x01;
279 bit_pos++;
280 (*len_codewd)++;
281 if (!dir && (iter->left != NULL))
282 iter = iter->left;
283 else if (dir && (iter->right != NULL))
284 iter = iter->right;
285 else
286 return -1;
287 }
288 LOGP(DRLCMACUL, LOGL_DEBUG, "Run_length = %d\n", iter->run_length);
289 *rlen = iter->run_length;
290 return 1;
291}
292
293/* Decompress received block bitmap
294 * \param compress_bmap_len[in] Compressed bitmap length
295 * \param start[in] Starting Color Code, true if bitmap starts with a run
296 * length of ones, false if zeros; see 9.1.10, 3GPP 44.060.
297 * \param orig_crbb_buf[in] Received block crbb bitmap
298 * \param dest[out] Uncompressed bitvector
299 */
300int egprs_compress::decompress_crbb(
301 int8_t compress_bmap_len,
302 bool start,
303 const uint8_t *orig_crbb_buf,
304 bitvec *dest)
305{
306
307 uint8_t bit_pos = 0;
308 uint8_t data;
309 egprs_compress_node *list = NULL;
310 uint8_t nbits = 0; /* number of bits of codeword */
311 uint16_t run_length = 0;
312 uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
313 unsigned wp = dest->cur_bit;
314 int rc = 0;
315 egprs_compress *compress = instance();
316
317 while (compress_bmap_len > 0) {
318 if (start) {
319 data = 0xff;
320 list = compress->ones_list;
321 } else {
322 data = 0x00;
323 list = compress->zeros_list;
324 }
325 rc = search_runlen(list, orig_crbb_buf,
326 bit_pos, &nbits, &run_length);
327 if (rc == -1)
328 return -1;
329 /* If run length > 64, need makeup and terminating code */
330 if (run_length < 64)
331 start = !start;
332 cbmaplen = cbmaplen + run_length;
333 /* put run length of Ones in uncompressed bitmap */
334 while (run_length != 0) {
335 if (run_length > 8) {
336 bitvec_write_field(dest, wp, data, 8);
337 run_length = run_length - 8;
338 } else {
339 bitvec_write_field(dest, wp, data, run_length);
340 run_length = 0;
341 }
342 }
343 bit_pos = bit_pos + nbits;
344 compress_bmap_len = compress_bmap_len - nbits;
345 }
346 return 0;
347}
348
349void egprs_compress::decode_tree_init()
350{
351 ones_list = create_tree_node(tall_pcu_ctx);
352 zeros_list = create_tree_node(tall_pcu_ctx);
353 build_codewords(ones_list, one_run_len_code_list);
354 build_codewords(zeros_list, zero_run_len_code_list);
355}
356
357egprs_compress::egprs_compress()
358{
359 decode_tree_init();
360}
361