blob: 8837c1fb19f997a5a66c7a8c965bb762157d382b [file] [log] [blame]
Piotr Krysik9e2e8352018-02-27 12:16:25 +01001/*
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 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <stdint.h>
26
27#include <osmocom/core/bits.h>
28
29/*! \addtogroup bits
30 * @{
31 * Osmocom bit level support code.
32 *
33 * This module implements the notion of different bit-fields, such as
34 * - unpacked bits (\ref ubit_t), i.e. 1 bit per byte
35 * - packed bits (\ref pbit_t), i.e. 8 bits per byte
36 * - soft bits (\ref sbit_t), 1 bit per byte from -127 to 127
37 *
38 * \file bits.c */
39
40/*! convert unpacked bits to packed bits, return length in bytes
41 * \param[out] out output buffer of packed bits
42 * \param[in] in input buffer of unpacked bits
43 * \param[in] num_bits number of bits
44 */
45int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits)
46{
47 unsigned int i;
48 uint8_t curbyte = 0;
49 pbit_t *outptr = out;
50
51 for (i = 0; i < num_bits; i++) {
52 uint8_t bitnum = 7 - (i % 8);
53
54 curbyte |= (in[i] << bitnum);
55
56 if(i % 8 == 7){
57 *outptr++ = curbyte;
58 curbyte = 0;
59 }
60 }
61 /* we have a non-modulo-8 bitcount */
62 if (i % 8)
63 *outptr++ = curbyte;
64
65 return outptr - out;
66}
67
68/*! Shift unaligned input to octet-aligned output
69 * \param[out] out output buffer, unaligned
70 * \param[in] in input buffer, octet-aligned
71 * \param[in] num_nibbles number of nibbles
72 */
73void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
74 unsigned int num_nibbles)
75{
76 unsigned int i, num_whole_bytes = num_nibbles / 2;
77 if (!num_whole_bytes)
78 return;
79
80 /* first byte: upper nibble empty, lower nibble from src */
81 out[0] = (in[0] >> 4);
82
83 /* bytes 1.. */
84 for (i = 1; i < num_whole_bytes; i++)
85 out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
86
87 /* shift the last nibble, in case there's an odd count */
88 i = num_whole_bytes;
89 if (num_nibbles & 1)
90 out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
91 else
92 out[i] = (in[i - 1] & 0xF) << 4;
93}
94
95/*! Shift unaligned input to octet-aligned output
96 * \param[out] out output buffer, octet-aligned
97 * \param[in] in input buffer, unaligned
98 * \param[in] num_nibbles number of nibbles
99 */
100void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
101 unsigned int num_nibbles)
102{
103 unsigned int i, num_whole_bytes = num_nibbles / 2;
104 if (!num_whole_bytes)
105 return;
106
107 for (i = 0; i < num_whole_bytes; i++)
108 out[i] = ((in[i] & 0xF) << 4) | (in[i + 1] >> 4);
109
110 /* shift the last nibble, in case there's an odd count */
111 i = num_whole_bytes;
112 if (num_nibbles & 1)
113 out[i] = (in[i] & 0xF) << 4;
114}
115
116/*! convert unpacked bits to soft bits
117 * \param[out] out output buffer of soft bits
118 * \param[in] in input buffer of unpacked bits
119 * \param[in] num_bits number of bits
120 */
121void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits)
122{
123 unsigned int i;
124 for (i = 0; i < num_bits; i++)
125 out[i] = in[i] ? -127 : 127;
126}
127
128/*! convert soft bits to unpacked bits
129 * \param[out] out output buffer of unpacked bits
130 * \param[in] in input buffer of soft bits
131 * \param[in] num_bits number of bits
132 */
133void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits)
134{
135 unsigned int i;
136 for (i = 0; i < num_bits; i++)
137 out[i] = in[i] < 0;
138}
139
140/*! convert packed bits to unpacked bits, return length in bytes
141 * \param[out] out output buffer of unpacked bits
142 * \param[in] in input buffer of packed bits
143 * \param[in] num_bits number of bits
144 * \return number of bytes used in \ref out
145 */
146int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits)
147{
148 unsigned int i;
149 ubit_t *cur = out;
150 ubit_t *limit = out + num_bits;
151
152 for (i = 0; i < (num_bits/8)+1; i++) {
153 pbit_t byte = in[i];
154 *cur++ = (byte >> 7) & 1;
155 if (cur >= limit)
156 break;
157 *cur++ = (byte >> 6) & 1;
158 if (cur >= limit)
159 break;
160 *cur++ = (byte >> 5) & 1;
161 if (cur >= limit)
162 break;
163 *cur++ = (byte >> 4) & 1;
164 if (cur >= limit)
165 break;
166 *cur++ = (byte >> 3) & 1;
167 if (cur >= limit)
168 break;
169 *cur++ = (byte >> 2) & 1;
170 if (cur >= limit)
171 break;
172 *cur++ = (byte >> 1) & 1;
173 if (cur >= limit)
174 break;
175 *cur++ = (byte >> 0) & 1;
176 if (cur >= limit)
177 break;
178 }
179 return cur - out;
180}
181
182/*! convert unpacked bits to packed bits (extended options)
183 * \param[out] out output buffer of packed bits
184 * \param[in] out_ofs offset into output buffer
185 * \param[in] in input buffer of unpacked bits
186 * \param[in] in_ofs offset into input buffer
187 * \param[in] num_bits number of bits
188 * \param[in] lsb_mode Encode bits in LSB orde instead of MSB
189 * \returns length in bytes (max written offset of output buffer + 1)
190 */
191int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
192 const ubit_t *in, unsigned int in_ofs,
193 unsigned int num_bits, int lsb_mode)
194{
195 int i, op, bn;
196 for (i=0; i<num_bits; i++) {
197 op = out_ofs + i;
198 bn = lsb_mode ? (op&7) : (7-(op&7));
199 if (in[in_ofs+i])
200 out[op>>3] |= 1 << bn;
201 else
202 out[op>>3] &= ~(1 << bn);
203 }
204 return ((out_ofs + num_bits - 1) >> 3) + 1;
205}
206
207/*! convert packed bits to unpacked bits (extended options)
208 * \param[out] out output buffer of unpacked bits
209 * \param[in] out_ofs offset into output buffer
210 * \param[in] in input buffer of packed bits
211 * \param[in] in_ofs offset into input buffer
212 * \param[in] num_bits number of bits
213 * \param[in] lsb_mode Encode bits in LSB orde instead of MSB
214 * \returns length in bytes (max written offset of output buffer + 1)
215 */
216int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
217 const pbit_t *in, unsigned int in_ofs,
218 unsigned int num_bits, int lsb_mode)
219{
220 int i, ip, bn;
221 for (i=0; i<num_bits; i++) {
222 ip = in_ofs + i;
223 bn = lsb_mode ? (ip&7) : (7-(ip&7));
224 out[out_ofs+i] = !!(in[ip>>3] & (1<<bn));
225 }
226 return out_ofs + num_bits;
227}
228
229/*! generalized bit reversal function
230 * \param[in] x the 32bit value to be reversed
231 * \param[in] k the type of reversal requested
232 * \returns the reversed 32bit dword
233 *
234 * This function reverses the bit order within a 32bit word. Depending
235 * on "k", it either reverses all bits in a 32bit dword, or the bytes in
236 * the dword, or the bits in each byte of a dword, or simply swaps the
237 * two 16bit words in a dword. See Chapter 7 "Hackers Delight"
238 */
239uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k)
240{
241 if (k & 1) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
242 if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
243 if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
244 if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
245 if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
246
247 return x;
248}
249
250/*! reverse the bit-order in each byte of a dword
251 * \param[in] x 32bit input value
252 * \returns 32bit value where bits of each byte have been reversed
253 *
254 * See Chapter 7 "Hackers Delight"
255 */
256uint32_t osmo_revbytebits_32(uint32_t x)
257{
258 x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
259 x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
260 x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
261
262 return x;
263}
264
265/*! reverse the bit order in a byte
266 * \param[in] x 8bit input value
267 * \returns 8bit value where bits order has been reversed
268 *
269 * See Chapter 7 "Hackers Delight"
270 */
271uint32_t osmo_revbytebits_8(uint8_t x)
272{
273 x = (x & 0x55) << 1 | (x & 0xAA) >> 1;
274 x = (x & 0x33) << 2 | (x & 0xCC) >> 2;
275 x = (x & 0x0F) << 4 | (x & 0xF0) >> 4;
276
277 return x;
278}
279
280/*! reverse bit-order of each byte in a buffer
281 * \param[in] buf buffer containing bytes to be bit-reversed
282 * \param[in] len length of buffer in bytes
283 *
284 * This function reverses the bits in each byte of the buffer
285 */
286void osmo_revbytebits_buf(uint8_t *buf, int len)
287{
288 unsigned int i;
289 unsigned int unaligned_cnt;
290 int len_remain = len;
291
292 unaligned_cnt = ((unsigned long)buf & 3);
293 for (i = 0; i < unaligned_cnt; i++) {
294 buf[i] = osmo_revbytebits_8(buf[i]);
295 len_remain--;
296 if (len_remain <= 0)
297 return;
298 }
299
300 for (i = unaligned_cnt; i + 3 < len; i += 4) {
301 osmo_store32be(osmo_revbytebits_32(osmo_load32be(buf + i)), buf + i);
302 len_remain -= 4;
303 }
304
305 for (i = len - len_remain; i < len; i++) {
306 buf[i] = osmo_revbytebits_8(buf[i]);
307 len_remain--;
308 }
309}
310
311/*! @} */