blob: af09441ac52ae8dda485ab79411d8c69e12d42af [file] [log] [blame]
Harald Welte468b6432014-09-11 13:05:51 +08001/*
2 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
3 * (C) 2011 by Sylvain Munaut <tnt@246tNt.com>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
Harald Welte2230c132011-01-19 10:10:16 +010022
23#include <stdint.h>
24
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010025#include <osmocom/core/bits.h>
Harald Welte2230c132011-01-19 10:10:16 +010026
Harald Welteba6988b2011-08-17 12:46:48 +020027/*! \addtogroup bits
28 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020029 * Osmocom bit level support code.
30 *
31 * \file bits.c */
Harald Welteba6988b2011-08-17 12:46:48 +020032
Neels Hofmeyr87e45502017-06-20 00:17:59 +020033/*! convert unpacked bits to packed bits, return length in bytes
Harald Welteba6988b2011-08-17 12:46:48 +020034 * \param[out] out output buffer of packed bits
35 * \param[in] in input buffer of unpacked bits
36 * \param[in] num_bits number of bits
37 */
Harald Welte2230c132011-01-19 10:10:16 +010038int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits)
39{
40 unsigned int i;
41 uint8_t curbyte = 0;
42 pbit_t *outptr = out;
43
44 for (i = 0; i < num_bits; i++) {
45 uint8_t bitnum = 7 - (i % 8);
46
47 curbyte |= (in[i] << bitnum);
48
Christian Vogelc7f84e92011-01-22 22:48:37 +010049 if(i % 8 == 7){
Harald Welte2230c132011-01-19 10:10:16 +010050 *outptr++ = curbyte;
51 curbyte = 0;
52 }
53 }
54 /* we have a non-modulo-8 bitcount */
55 if (i % 8)
56 *outptr++ = curbyte;
57
58 return outptr - out;
59}
60
Neels Hofmeyr87e45502017-06-20 00:17:59 +020061/*! Shift unaligned input to octet-aligned output
Maxe0a7d9e2016-06-17 17:58:52 +020062 * \param[out] out output buffer, unaligned
63 * \param[in] in input buffer, octet-aligned
64 * \param[in] num_nibbles number of nibbles
65 */
66void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
67 unsigned int num_nibbles)
68{
69 unsigned int i, num_whole_bytes = num_nibbles / 2;
70 if (!num_whole_bytes)
71 return;
72
73 /* first byte: upper nibble empty, lower nibble from src */
74 out[0] = (in[0] >> 4);
75
76 /* bytes 1.. */
77 for (i = 1; i < num_whole_bytes; i++)
78 out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
79
80 /* shift the last nibble, in case there's an odd count */
81 i = num_whole_bytes;
82 if (num_nibbles & 1)
83 out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
84 else
85 out[i] = (in[i - 1] & 0xF) << 4;
86}
87
Neels Hofmeyr87e45502017-06-20 00:17:59 +020088/*! Shift unaligned input to octet-aligned output
Maxe0a7d9e2016-06-17 17:58:52 +020089 * \param[out] out output buffer, octet-aligned
90 * \param[in] in input buffer, unaligned
91 * \param[in] num_nibbles number of nibbles
92 */
93void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
94 unsigned int num_nibbles)
95{
96 unsigned int i, num_whole_bytes = num_nibbles / 2;
97 if (!num_whole_bytes)
98 return;
99
100 for (i = 0; i < num_whole_bytes; i++)
101 out[i] = ((in[i] & 0xF) << 4) | (in[i + 1] >> 4);
102
103 /* shift the last nibble, in case there's an odd count */
104 i = num_whole_bytes;
105 if (num_nibbles & 1)
106 out[i] = (in[i] & 0xF) << 4;
107}
108
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200109/*! convert unpacked bits to soft bits
Maxd8fb1422016-04-06 16:13:00 +0200110 * \param[out] out output buffer of soft bits
111 * \param[in] in input buffer of unpacked bits
112 * \param[in] num_bits number of bits
113 */
114void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits)
115{
116 unsigned int i;
117 for (i = 0; i < num_bits; i++)
118 out[i] = in[i] ? -127 : 127;
119}
120
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200121/*! convert soft bits to unpacked bits
Maxd8fb1422016-04-06 16:13:00 +0200122 * \param[out] out output buffer of unpacked bits
123 * \param[in] in input buffer of soft bits
124 * \param[in] num_bits number of bits
125 */
126void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits)
127{
128 unsigned int i;
129 for (i = 0; i < num_bits; i++)
130 out[i] = in[i] < 0;
131}
132
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200133/*! convert packed bits to unpacked bits, return length in bytes
Harald Welteba6988b2011-08-17 12:46:48 +0200134 * \param[out] out output buffer of unpacked bits
135 * \param[in] in input buffer of packed bits
136 * \param[in] num_bits number of bits
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200137 * \return number of bytes used in \ref out
Harald Welteba6988b2011-08-17 12:46:48 +0200138 */
Harald Welte2230c132011-01-19 10:10:16 +0100139int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits)
140{
141 unsigned int i;
142 ubit_t *cur = out;
143 ubit_t *limit = out + num_bits;
144
145 for (i = 0; i < (num_bits/8)+1; i++) {
146 pbit_t byte = in[i];
147 *cur++ = (byte >> 7) & 1;
148 if (cur >= limit)
149 break;
150 *cur++ = (byte >> 6) & 1;
151 if (cur >= limit)
152 break;
153 *cur++ = (byte >> 5) & 1;
154 if (cur >= limit)
155 break;
156 *cur++ = (byte >> 4) & 1;
157 if (cur >= limit)
158 break;
159 *cur++ = (byte >> 3) & 1;
160 if (cur >= limit)
161 break;
162 *cur++ = (byte >> 2) & 1;
163 if (cur >= limit)
164 break;
165 *cur++ = (byte >> 1) & 1;
166 if (cur >= limit)
167 break;
168 *cur++ = (byte >> 0) & 1;
169 if (cur >= limit)
170 break;
171 }
172 return cur - out;
173}
Sylvain Munautaeb10772011-01-21 12:22:30 +0100174
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200175/*! convert unpacked bits to packed bits (extended options)
Harald Welteba6988b2011-08-17 12:46:48 +0200176 * \param[out] out output buffer of packed bits
177 * \param[in] out_ofs offset into output buffer
178 * \param[in] in input buffer of unpacked bits
179 * \param[in] in_ofs offset into input buffer
180 * \param[in] num_bits number of bits
181 * \param[in] lsb_mode Encode bits in LSB orde instead of MSB
182 * \returns length in bytes (max written offset of output buffer + 1)
183 */
Sylvain Munautaeb10772011-01-21 12:22:30 +0100184int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
185 const ubit_t *in, unsigned int in_ofs,
186 unsigned int num_bits, int lsb_mode)
187{
188 int i, op, bn;
189 for (i=0; i<num_bits; i++) {
190 op = out_ofs + i;
191 bn = lsb_mode ? (op&7) : (7-(op&7));
192 if (in[in_ofs+i])
193 out[op>>3] |= 1 << bn;
194 else
195 out[op>>3] &= ~(1 << bn);
196 }
197 return ((out_ofs + num_bits - 1) >> 3) + 1;
198}
199
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200200/*! convert packed bits to unpacked bits (extended options)
Harald Welteba6988b2011-08-17 12:46:48 +0200201 * \param[out] out output buffer of unpacked bits
202 * \param[in] out_ofs offset into output buffer
203 * \param[in] in input buffer of packed bits
204 * \param[in] in_ofs offset into input buffer
205 * \param[in] num_bits number of bits
206 * \param[in] lsb_mode Encode bits in LSB orde instead of MSB
207 * \returns length in bytes (max written offset of output buffer + 1)
208 */
Sylvain Munautaeb10772011-01-21 12:22:30 +0100209int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
210 const pbit_t *in, unsigned int in_ofs,
211 unsigned int num_bits, int lsb_mode)
212{
213 int i, ip, bn;
214 for (i=0; i<num_bits; i++) {
215 ip = in_ofs + i;
216 bn = lsb_mode ? (ip&7) : (7-(ip&7));
217 out[out_ofs+i] = !!(in[ip>>3] & (1<<bn));
218 }
219 return out_ofs + num_bits;
220}
Harald Welteba6988b2011-08-17 12:46:48 +0200221
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200222/*! generalized bit reversal function
Harald Weltede6e4982012-12-06 21:25:27 +0100223 * \param[in] x the 32bit value to be reversed
224 * \param[in] k the type of reversal requested
225 * \returns the reversed 32bit dword
226 *
227 * This function reverses the bit order within a 32bit word. Depending
228 * on "k", it either reverses all bits in a 32bit dword, or the bytes in
229 * the dword, or the bits in each byte of a dword, or simply swaps the
230 * two 16bit words in a dword. See Chapter 7 "Hackers Delight"
231 */
Harald Welte712691d2011-09-01 14:47:31 +0200232uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k)
233{
234 if (k & 1) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
235 if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
236 if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
237 if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
238 if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
239
240 return x;
241}
242
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200243/*! reverse the bit-order in each byte of a dword
Harald Weltede6e4982012-12-06 21:25:27 +0100244 * \param[in] x 32bit input value
245 * \returns 32bit value where bits of each byte have been reversed
246 *
247 * See Chapter 7 "Hackers Delight"
248 */
Harald Welte712691d2011-09-01 14:47:31 +0200249uint32_t osmo_revbytebits_32(uint32_t x)
250{
251 x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
252 x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
253 x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
254
255 return x;
256}
257
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200258/*! reverse the bit order in a byte
Harald Weltede6e4982012-12-06 21:25:27 +0100259 * \param[in] x 8bit input value
260 * \returns 8bit value where bits order has been reversed
261 *
262 * See Chapter 7 "Hackers Delight"
263 */
Harald Welte712691d2011-09-01 14:47:31 +0200264uint32_t osmo_revbytebits_8(uint8_t x)
265{
266 x = (x & 0x55) << 1 | (x & 0xAA) >> 1;
267 x = (x & 0x33) << 2 | (x & 0xCC) >> 2;
268 x = (x & 0x0F) << 4 | (x & 0xF0) >> 4;
269
270 return x;
271}
272
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200273/*! reverse bit-order of each byte in a buffer
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100274 * \param[in] buf buffer containing bytes to be bit-reversed
275 * \param[in] len length of buffer in bytes
Harald Weltede6e4982012-12-06 21:25:27 +0100276 *
277 * This function reverses the bits in each byte of the buffer
278 */
Harald Welte712691d2011-09-01 14:47:31 +0200279void osmo_revbytebits_buf(uint8_t *buf, int len)
280{
281 unsigned int i;
282 unsigned int unaligned_cnt;
283 int len_remain = len;
284
285 unaligned_cnt = ((unsigned long)buf & 3);
286 for (i = 0; i < unaligned_cnt; i++) {
287 buf[i] = osmo_revbytebits_8(buf[i]);
288 len_remain--;
289 if (len_remain <= 0)
290 return;
291 }
292
Sylvain Munaut01e06042013-01-03 09:36:16 +0100293 for (i = unaligned_cnt; i + 3 < len; i += 4) {
Max08621a82016-01-21 17:16:56 +0100294 osmo_store32be(osmo_revbytebits_32(osmo_load32be(buf + i)), buf + i);
Harald Welte712691d2011-09-01 14:47:31 +0200295 len_remain -= 4;
296 }
297
298 for (i = len - len_remain; i < len; i++) {
299 buf[i] = osmo_revbytebits_8(buf[i]);
300 len_remain--;
301 }
302}
303
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200304/*! @} */