Remove local copy of associated osmo libraries
Change-Id: I2b4afedd9f2d568b5287d791891b2c2893fc6843
This commit is contained in:
parent
df417739b0
commit
e4da417f8d
|
@ -129,14 +129,10 @@ find_package(Doxygen)
|
|||
########################################################################
|
||||
# Find osmocom build dependencies
|
||||
########################################################################
|
||||
option(LOCAL_OSMOCOM "Build with local osmocom libraries" OFF)
|
||||
find_package(Libosmocore)
|
||||
find_package(Libosmocodec)
|
||||
find_package(Libosmocoding)
|
||||
find_package(Libosmogsm)
|
||||
if(NOT LIBOSMOCORE_FOUND OR NOT LIBOSMOCODEC_FOUND OR NOT LIBOSMOGSM_FOUND)
|
||||
set(LOCAL_OSMOCOM ON)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Setup doxygen option
|
||||
|
|
|
@ -76,33 +76,14 @@ add_subdirectory(receiver)
|
|||
add_subdirectory(transmitter)
|
||||
add_subdirectory(trx)
|
||||
|
||||
if(NOT LOCAL_OSMOCOM)
|
||||
list (APPEND grgsm_link_libraries ${LIBOSMOCORE_LIBRARY} ${LIBOSMOCODEC_LIBRARY} ${LIBOSMOGSM_LIBRARY})
|
||||
if(LIBOSMOCODING_FOUND)
|
||||
list (APPEND grgsm_link_libraries
|
||||
${LIBOSMOCODING_LIBRARY}
|
||||
)
|
||||
list (APPEND grgsm_include_directories
|
||||
PUBLIC $<BUILD_INTERFACE:${LIBOSMOCORE_INCLUDE_DIR}>
|
||||
)
|
||||
else()
|
||||
list (APPEND grgsm_include_directories
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/decoding>
|
||||
)
|
||||
endif()
|
||||
else(NOT LOCAL_OSMOCOM)
|
||||
list (APPEND grgsm_include_directories
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/decoding>
|
||||
)
|
||||
endif(NOT LOCAL_OSMOCOM)
|
||||
|
||||
list (APPEND grgsm_link_libraries ${LIBOSMOCORE_LIBRARY} ${LIBOSMOCODEC_LIBRARY} ${LIBOSMOGSM_LIBRARY} ${LIBOSMOCODING_LIBRARY})
|
||||
|
||||
add_library(grgsm SHARED ${grgsm_sources})
|
||||
target_link_libraries(grgsm gnuradio::gnuradio-runtime gnuradio::gnuradio-filter volk ${grgsm_link_libraries})
|
||||
target_include_directories(grgsm
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/receiver>
|
||||
${grgsm_include_directories}
|
||||
PUBLIC $<BUILD_INTERFACE:${LIBOSMOCORE_INCLUDE_DIR}>
|
||||
PUBLIC $<BUILD_INTERFACE:${Boost_INCLUDE_DIR}>
|
||||
PUBLIC $<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
|
|
@ -17,15 +17,6 @@
|
|||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(LOCAL_OSMOCOM)
|
||||
add_subdirectory(osmocom/core)
|
||||
add_subdirectory(osmocom/codec)
|
||||
add_subdirectory(osmocom/gsm)
|
||||
add_subdirectory(osmocom/coding)
|
||||
elseif(NOT LIBOSMOCODING_FOUND)
|
||||
add_subdirectory(osmocom/coding)
|
||||
endif()
|
||||
|
||||
add_subdirectory(openbts)
|
||||
|
||||
add_sources(
|
||||
|
@ -34,4 +25,3 @@ add_sources(
|
|||
tch_h_decoder_impl.cc
|
||||
sch.c
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
add_sources(
|
||||
gsm610.c
|
||||
gsm620.c
|
||||
gsm660.c
|
||||
gsm690.c
|
||||
)
|
|
@ -1,81 +0,0 @@
|
|||
/*! \file codec.h */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
/* TS 101318 Chapter 5.1: 260 bits + 4bit sig */
|
||||
#define GSM_FR_BYTES 33
|
||||
/* TS 101318 Chapter 5.2: 112 bits, no sig */
|
||||
#define GSM_HR_BYTES 14
|
||||
/* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
|
||||
#define GSM_EFR_BYTES 31
|
||||
|
||||
extern const uint16_t gsm610_bitorder[]; /* FR */
|
||||
extern const uint16_t gsm620_unvoiced_bitorder[]; /* HR unvoiced */
|
||||
extern const uint16_t gsm620_voiced_bitorder[]; /* HR voiced */
|
||||
extern const uint16_t gsm660_bitorder[]; /* EFR */
|
||||
|
||||
extern const uint16_t gsm690_12_2_bitorder[]; /* AMR 12.2 kbits */
|
||||
extern const uint16_t gsm690_10_2_bitorder[]; /* AMR 10.2 kbits */
|
||||
extern const uint16_t gsm690_7_95_bitorder[]; /* AMR 7.95 kbits */
|
||||
extern const uint16_t gsm690_7_4_bitorder[]; /* AMR 7.4 kbits */
|
||||
extern const uint16_t gsm690_6_7_bitorder[]; /* AMR 6.7 kbits */
|
||||
extern const uint16_t gsm690_5_9_bitorder[]; /* AMR 5.9 kbits */
|
||||
extern const uint16_t gsm690_5_15_bitorder[]; /* AMR 5.15 kbits */
|
||||
extern const uint16_t gsm690_4_75_bitorder[]; /* AMR 4.75 kbits */
|
||||
|
||||
extern const struct value_string osmo_amr_type_names[];
|
||||
|
||||
enum osmo_amr_type {
|
||||
AMR_4_75 = 0,
|
||||
AMR_5_15 = 1,
|
||||
AMR_5_90 = 2,
|
||||
AMR_6_70 = 3,
|
||||
AMR_7_40 = 4,
|
||||
AMR_7_95 = 5,
|
||||
AMR_10_2 = 6,
|
||||
AMR_12_2 = 7,
|
||||
AMR_SID = 8,
|
||||
AMR_GSM_EFR_SID = 9,
|
||||
AMR_TDMA_EFR_SID = 10,
|
||||
AMR_PDC_EFR_SID = 11,
|
||||
AMR_NO_DATA = 15,
|
||||
};
|
||||
|
||||
enum osmo_amr_quality {
|
||||
AMR_BAD = 0,
|
||||
AMR_GOOD = 1
|
||||
};
|
||||
|
||||
/*! Check if given AMR Frame Type is a speech frame
|
||||
* \param[in] ft AMR Frame Type
|
||||
* \returns true if AMR with given Frame Type contains voice, false otherwise
|
||||
*/
|
||||
static inline bool osmo_amr_is_speech(enum osmo_amr_type ft)
|
||||
{
|
||||
switch (ft) {
|
||||
case AMR_4_75:
|
||||
case AMR_5_15:
|
||||
case AMR_5_90:
|
||||
case AMR_6_70:
|
||||
case AMR_7_40:
|
||||
case AMR_7_95:
|
||||
case AMR_10_2:
|
||||
case AMR_12_2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len);
|
||||
bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len);
|
||||
int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
|
||||
enum osmo_amr_quality bfi);
|
||||
int osmo_amr_rtp_dec(const uint8_t *payload, int payload_len, uint8_t *cmr,
|
||||
int8_t *cmi, enum osmo_amr_type *ft,
|
||||
enum osmo_amr_quality *bfi, int8_t *sti);
|
|
@ -1,336 +0,0 @@
|
|||
/*! \file gsm610.c
|
||||
* GSM 06.10 - GSM FR codec. */
|
||||
/*
|
||||
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/bitvec.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
/* GSM FR - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 2.
|
||||
* It's also GSM 06.10 Table A.2.1a
|
||||
*
|
||||
* It converts between serial parameter output by the encoder and the
|
||||
* order needed before channel encoding.
|
||||
*/
|
||||
const uint16_t gsm610_bitorder[260] = {
|
||||
0, /* LARc0:5 */
|
||||
47, /* Xmaxc0:5 */
|
||||
103, /* Xmaxc1:5 */
|
||||
159, /* Xmaxc2:5 */
|
||||
215, /* Xmaxc3:5 */
|
||||
1, /* LARc0:4 */
|
||||
6, /* LARc1:5 */
|
||||
12, /* LARc2:4 */
|
||||
2, /* LARc0:3 */
|
||||
7, /* LARc1:4 */
|
||||
13, /* LARc2:3 */
|
||||
17, /* LARc3:4 */
|
||||
36, /* Nc0:6 */
|
||||
92, /* Nc1:6 */
|
||||
148, /* Nc2:6 */
|
||||
204, /* Nc3:6 */
|
||||
48, /* Xmaxc0:4 */
|
||||
104, /* Xmaxc1:4 */
|
||||
160, /* Xmaxc2:4 */
|
||||
216, /* Xmaxc3:4 */
|
||||
8, /* LARc1:3 */
|
||||
22, /* LARc4:3 */
|
||||
26, /* LARc5:3 */
|
||||
37, /* Nc0:5 */
|
||||
93, /* Nc1:5 */
|
||||
149, /* Nc2:5 */
|
||||
205, /* Nc3:5 */
|
||||
38, /* Nc0:4 */
|
||||
94, /* Nc1:4 */
|
||||
150, /* Nc2:4 */
|
||||
206, /* Nc3:4 */
|
||||
39, /* Nc0:3 */
|
||||
95, /* Nc1:3 */
|
||||
151, /* Nc2:3 */
|
||||
207, /* Nc3:3 */
|
||||
40, /* Nc0:2 */
|
||||
96, /* Nc1:2 */
|
||||
152, /* Nc2:2 */
|
||||
208, /* Nc3:2 */
|
||||
49, /* Xmaxc0:3 */
|
||||
105, /* Xmaxc1:3 */
|
||||
161, /* Xmaxc2:3 */
|
||||
217, /* Xmaxc3:3 */
|
||||
3, /* LARc0:2 */
|
||||
18, /* LARc3:3 */
|
||||
30, /* LARc6:2 */
|
||||
41, /* Nc0:1 */
|
||||
97, /* Nc1:1 */
|
||||
153, /* Nc2:1 */
|
||||
209, /* Nc3:1 */
|
||||
23, /* LARc4:2 */
|
||||
27, /* LARc5:2 */
|
||||
43, /* bc0:1 */
|
||||
99, /* bc1:1 */
|
||||
155, /* bc2:1 */
|
||||
211, /* bc3:1 */
|
||||
42, /* Nc0:0 */
|
||||
98, /* Nc1:0 */
|
||||
154, /* Nc2:0 */
|
||||
210, /* Nc3:0 */
|
||||
45, /* Mc0:1 */
|
||||
101, /* Mc1:1 */
|
||||
157, /* Mc2:1 */
|
||||
213, /* Mc3:1 */
|
||||
4, /* LARc0:1 */
|
||||
9, /* LARc1:2 */
|
||||
14, /* LARc2:2 */
|
||||
33, /* LARc7:2 */
|
||||
19, /* LARc3:2 */
|
||||
24, /* LARc4:1 */
|
||||
31, /* LARc6:1 */
|
||||
44, /* bc0:0 */
|
||||
100, /* bc1:0 */
|
||||
156, /* bc2:0 */
|
||||
212, /* bc3:0 */
|
||||
50, /* Xmaxc0:2 */
|
||||
106, /* Xmaxc1:2 */
|
||||
162, /* Xmaxc2:2 */
|
||||
218, /* Xmaxc3:2 */
|
||||
53, /* xmc0_0:2 */
|
||||
56, /* xmc0_1:2 */
|
||||
59, /* xmc0_2:2 */
|
||||
62, /* xmc0_3:2 */
|
||||
65, /* xmc0_4:2 */
|
||||
68, /* xmc0_5:2 */
|
||||
71, /* xmc0_6:2 */
|
||||
74, /* xmc0_7:2 */
|
||||
77, /* xmc0_8:2 */
|
||||
80, /* xmc0_9:2 */
|
||||
83, /* xmc0_10:2 */
|
||||
86, /* xmc0_11:2 */
|
||||
89, /* xmc0_12:2 */
|
||||
109, /* xmc1_0:2 */
|
||||
112, /* xmc1_1:2 */
|
||||
115, /* xmc1_2:2 */
|
||||
118, /* xmc1_3:2 */
|
||||
121, /* xmc1_4:2 */
|
||||
124, /* xmc1_5:2 */
|
||||
127, /* xmc1_6:2 */
|
||||
130, /* xmc1_7:2 */
|
||||
133, /* xmc1_8:2 */
|
||||
136, /* xmc1_9:2 */
|
||||
139, /* xmc1_10:2 */
|
||||
142, /* xmc1_11:2 */
|
||||
145, /* xmc1_12:2 */
|
||||
165, /* xmc2_0:2 */
|
||||
168, /* xmc2_1:2 */
|
||||
171, /* xmc2_2:2 */
|
||||
174, /* xmc2_3:2 */
|
||||
177, /* xmc2_4:2 */
|
||||
180, /* xmc2_5:2 */
|
||||
183, /* xmc2_6:2 */
|
||||
186, /* xmc2_7:2 */
|
||||
189, /* xmc2_8:2 */
|
||||
192, /* xmc2_9:2 */
|
||||
195, /* xmc2_10:2 */
|
||||
198, /* xmc2_11:2 */
|
||||
201, /* xmc2_12:2 */
|
||||
221, /* xmc3_0:2 */
|
||||
224, /* xmc3_1:2 */
|
||||
227, /* xmc3_2:2 */
|
||||
230, /* xmc3_3:2 */
|
||||
233, /* xmc3_4:2 */
|
||||
236, /* xmc3_5:2 */
|
||||
239, /* xmc3_6:2 */
|
||||
242, /* xmc3_7:2 */
|
||||
245, /* xmc3_8:2 */
|
||||
248, /* xmc3_9:2 */
|
||||
251, /* xmc3_10:2 */
|
||||
254, /* xmc3_11:2 */
|
||||
257, /* xmc3_12:2 */
|
||||
46, /* Mc0:0 */
|
||||
102, /* Mc1:0 */
|
||||
158, /* Mc2:0 */
|
||||
214, /* Mc3:0 */
|
||||
51, /* Xmaxc0:1 */
|
||||
107, /* Xmaxc1:1 */
|
||||
163, /* Xmaxc2:1 */
|
||||
219, /* Xmaxc3:1 */
|
||||
54, /* xmc0_0:1 */
|
||||
57, /* xmc0_1:1 */
|
||||
60, /* xmc0_2:1 */
|
||||
63, /* xmc0_3:1 */
|
||||
66, /* xmc0_4:1 */
|
||||
69, /* xmc0_5:1 */
|
||||
72, /* xmc0_6:1 */
|
||||
75, /* xmc0_7:1 */
|
||||
78, /* xmc0_8:1 */
|
||||
81, /* xmc0_9:1 */
|
||||
84, /* xmc0_10:1 */
|
||||
87, /* xmc0_11:1 */
|
||||
90, /* xmc0_12:1 */
|
||||
110, /* xmc1_0:1 */
|
||||
113, /* xmc1_1:1 */
|
||||
116, /* xmc1_2:1 */
|
||||
119, /* xmc1_3:1 */
|
||||
122, /* xmc1_4:1 */
|
||||
125, /* xmc1_5:1 */
|
||||
128, /* xmc1_6:1 */
|
||||
131, /* xmc1_7:1 */
|
||||
134, /* xmc1_8:1 */
|
||||
137, /* xmc1_9:1 */
|
||||
140, /* xmc1_10:1 */
|
||||
143, /* xmc1_11:1 */
|
||||
146, /* xmc1_12:1 */
|
||||
166, /* xmc2_0:1 */
|
||||
169, /* xmc2_1:1 */
|
||||
172, /* xmc2_2:1 */
|
||||
175, /* xmc2_3:1 */
|
||||
178, /* xmc2_4:1 */
|
||||
181, /* xmc2_5:1 */
|
||||
184, /* xmc2_6:1 */
|
||||
187, /* xmc2_7:1 */
|
||||
190, /* xmc2_8:1 */
|
||||
193, /* xmc2_9:1 */
|
||||
196, /* xmc2_10:1 */
|
||||
199, /* xmc2_11:1 */
|
||||
202, /* xmc2_12:1 */
|
||||
222, /* xmc3_0:1 */
|
||||
225, /* xmc3_1:1 */
|
||||
228, /* xmc3_2:1 */
|
||||
231, /* xmc3_3:1 */
|
||||
234, /* xmc3_4:1 */
|
||||
237, /* xmc3_5:1 */
|
||||
240, /* xmc3_6:1 */
|
||||
243, /* xmc3_7:1 */
|
||||
246, /* xmc3_8:1 */
|
||||
249, /* xmc3_9:1 */
|
||||
252, /* xmc3_10:1 */
|
||||
255, /* xmc3_11:1 */
|
||||
258, /* xmc3_12:1 */
|
||||
5, /* LARc0:0 */
|
||||
10, /* LARc1:1 */
|
||||
15, /* LARc2:1 */
|
||||
28, /* LARc5:1 */
|
||||
32, /* LARc6:0 */
|
||||
34, /* LARc7:1 */
|
||||
35, /* LARc7:0 */
|
||||
16, /* LARc2:0 */
|
||||
20, /* LARc3:1 */
|
||||
21, /* LARc3:0 */
|
||||
25, /* LARc4:0 */
|
||||
52, /* Xmaxc0:0 */
|
||||
108, /* Xmaxc1:0 */
|
||||
164, /* Xmaxc2:0 */
|
||||
220, /* Xmaxc3:0 */
|
||||
55, /* xmc0_0:0 */
|
||||
58, /* xmc0_1:0 */
|
||||
61, /* xmc0_2:0 */
|
||||
64, /* xmc0_3:0 */
|
||||
67, /* xmc0_4:0 */
|
||||
70, /* xmc0_5:0 */
|
||||
73, /* xmc0_6:0 */
|
||||
76, /* xmc0_7:0 */
|
||||
79, /* xmc0_8:0 */
|
||||
82, /* xmc0_9:0 */
|
||||
85, /* xmc0_10:0 */
|
||||
88, /* xmc0_11:0 */
|
||||
91, /* xmc0_12:0 */
|
||||
111, /* xmc1_0:0 */
|
||||
114, /* xmc1_1:0 */
|
||||
117, /* xmc1_2:0 */
|
||||
120, /* xmc1_3:0 */
|
||||
123, /* xmc1_4:0 */
|
||||
126, /* xmc1_5:0 */
|
||||
129, /* xmc1_6:0 */
|
||||
132, /* xmc1_7:0 */
|
||||
135, /* xmc1_8:0 */
|
||||
138, /* xmc1_9:0 */
|
||||
141, /* xmc1_10:0 */
|
||||
144, /* xmc1_11:0 */
|
||||
147, /* xmc1_12:0 */
|
||||
167, /* xmc2_0:0 */
|
||||
170, /* xmc2_1:0 */
|
||||
173, /* xmc2_2:0 */
|
||||
176, /* xmc2_3:0 */
|
||||
179, /* xmc2_4:0 */
|
||||
182, /* xmc2_5:0 */
|
||||
185, /* xmc2_6:0 */
|
||||
188, /* xmc2_7:0 */
|
||||
191, /* xmc2_8:0 */
|
||||
194, /* xmc2_9:0 */
|
||||
197, /* xmc2_10:0 */
|
||||
200, /* xmc2_11:0 */
|
||||
203, /* xmc2_12:0 */
|
||||
223, /* xmc3_0:0 */
|
||||
226, /* xmc3_1:0 */
|
||||
229, /* xmc3_2:0 */
|
||||
232, /* xmc3_3:0 */
|
||||
235, /* xmc3_4:0 */
|
||||
238, /* xmc3_5:0 */
|
||||
241, /* xmc3_6:0 */
|
||||
244, /* xmc3_7:0 */
|
||||
247, /* xmc3_8:0 */
|
||||
250, /* xmc3_9:0 */
|
||||
253, /* xmc3_10:0 */
|
||||
256, /* xmc3_11:0 */
|
||||
259, /* xmc3_12:0 */
|
||||
11, /* LARc1:0 */
|
||||
29, /* LARc5:0 */
|
||||
};
|
||||
|
||||
/*! Check whether RTP frame contains FR SID code word according to
|
||||
* TS 101 318 §5.1.2
|
||||
* \param[in] rtp_payload Buffer with RTP payload
|
||||
* \param[in] payload_len Length of payload
|
||||
* \returns true if code word is found, false otherwise
|
||||
*/
|
||||
bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
|
||||
{
|
||||
struct bitvec bv;
|
||||
uint16_t i, z_bits[] = { 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73,
|
||||
75, 76, 78, 79, 81, 82, 84, 85, 87, 88, 90, 91,
|
||||
93, 94, 113, 114, 116, 117, 119, 120, 122, 123,
|
||||
125, 126, 128, 129, 131, 132, 134, 135, 137,
|
||||
138, 140, 141, 143, 144, 146, 147, 149, 150,
|
||||
169, 170, 172, 173, 175, 176, 178, 179, 181,
|
||||
182, 184, 185, 187, 188, 190, 191, 193, 194,
|
||||
196, 197, 199, 200, 202, 203, 205, 206, 225,
|
||||
226, 228, 229, 231, 232, 234, 235, 237, 240,
|
||||
243, 246, 249, 252, 255, 258, 261 };
|
||||
|
||||
/* signature does not match Full Rate SID */
|
||||
if ((rtp_payload[0] >> 4) != 0xD)
|
||||
return false;
|
||||
|
||||
bv.data = (uint8_t *) rtp_payload;
|
||||
bv.data_len = payload_len;
|
||||
|
||||
/* code word is all 0 at given bits, numbered from 1 */
|
||||
for (i = 0; i < ARRAY_SIZE(z_bits); i++)
|
||||
if (bitvec_get_bit_pos(&bv, z_bits[i]) != ZERO)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,272 +0,0 @@
|
|||
/*! \file gsm610_bits.h */
|
||||
|
||||
#pragma once
|
||||
|
||||
/* This enumeration describs a GSM-FR (GSM 06.10) frame in ints RTP bit order
|
||||
* representation. See also RFC 3551 Table 3: GSM payload format */
|
||||
enum gsm610_rtp_bit_offsets {
|
||||
GSM610_RTP_SIGNATURE_0,
|
||||
GSM610_RTP_SIGNATURE_1,
|
||||
GSM610_RTP_SIGNATURE_2,
|
||||
GSM610_RTP_SIGNATURE_3,
|
||||
GSM610_RTP_LARC0_0,
|
||||
GSM610_RTP_LARC0_1,
|
||||
GSM610_RTP_LARC0_2,
|
||||
GSM610_RTP_LARC0_3,
|
||||
GSM610_RTP_LARC0_4,
|
||||
GSM610_RTP_LARC0_5,
|
||||
GSM610_RTP_LARC1_0,
|
||||
GSM610_RTP_LARC1_1,
|
||||
GSM610_RTP_LARC1_2,
|
||||
GSM610_RTP_LARC1_3,
|
||||
GSM610_RTP_LARC1_4,
|
||||
GSM610_RTP_LARC1_5,
|
||||
GSM610_RTP_LARC2_0,
|
||||
GSM610_RTP_LARC2_1,
|
||||
GSM610_RTP_LARC2_2,
|
||||
GSM610_RTP_LARC2_3,
|
||||
GSM610_RTP_LARC2_4,
|
||||
GSM610_RTP_LARC3_0,
|
||||
GSM610_RTP_LARC3_1,
|
||||
GSM610_RTP_LARC3_2,
|
||||
GSM610_RTP_LARC3_3,
|
||||
GSM610_RTP_LARC3_4,
|
||||
GSM610_RTP_LARC4_0,
|
||||
GSM610_RTP_LARC4_1,
|
||||
GSM610_RTP_LARC4_2,
|
||||
GSM610_RTP_LARC4_3,
|
||||
GSM610_RTP_LARC5_0,
|
||||
GSM610_RTP_LARC5_1,
|
||||
GSM610_RTP_LARC5_2,
|
||||
GSM610_RTP_LARC5_3,
|
||||
GSM610_RTP_LARC6_0,
|
||||
GSM610_RTP_LARC6_1,
|
||||
GSM610_RTP_LARC6_2,
|
||||
GSM610_RTP_LARC7_0,
|
||||
GSM610_RTP_LARC7_1,
|
||||
GSM610_RTP_LARC7_2,
|
||||
GSM610_RTP_NC0_0,
|
||||
GSM610_RTP_NC0_1,
|
||||
GSM610_RTP_NC0_2,
|
||||
GSM610_RTP_NC0_3,
|
||||
GSM610_RTP_NC0_4,
|
||||
GSM610_RTP_NC0_5,
|
||||
GSM610_RTP_NC0_6,
|
||||
GSM610_RTP_BC0_0,
|
||||
GSM610_RTP_BC0_1,
|
||||
GSM610_RTP_MC0_0,
|
||||
GSM610_RTP_MC0_1,
|
||||
GSM610_RTP_XMAXC00,
|
||||
GSM610_RTP_XMAXC01,
|
||||
GSM610_RTP_XMAXC02,
|
||||
GSM610_RTP_XMAXC03,
|
||||
GSM610_RTP_XMAXC04,
|
||||
GSM610_RTP_XMAXC05,
|
||||
GSM610_RTP_XMC0_0,
|
||||
GSM610_RTP_XMC0_1,
|
||||
GSM610_RTP_XMC0_2,
|
||||
GSM610_RTP_XMC1_0,
|
||||
GSM610_RTP_XMC1_1,
|
||||
GSM610_RTP_XMC1_2,
|
||||
GSM610_RTP_XMC2_0,
|
||||
GSM610_RTP_XMC2_1,
|
||||
GSM610_RTP_XMC2_2,
|
||||
GSM610_RTP_XMC3_0,
|
||||
GSM610_RTP_XMC3_1,
|
||||
GSM610_RTP_XMC3_2,
|
||||
GSM610_RTP_XMC4_0,
|
||||
GSM610_RTP_XMC4_1,
|
||||
GSM610_RTP_XMC4_2,
|
||||
GSM610_RTP_XMC5_0,
|
||||
GSM610_RTP_XMC5_1,
|
||||
GSM610_RTP_XMC5_2,
|
||||
GSM610_RTP_XMC6_0,
|
||||
GSM610_RTP_XMC6_1,
|
||||
GSM610_RTP_XMC6_2,
|
||||
GSM610_RTP_XMC7_0,
|
||||
GSM610_RTP_XMC7_1,
|
||||
GSM610_RTP_XMC7_2,
|
||||
GSM610_RTP_XMC8_0,
|
||||
GSM610_RTP_XMC8_1,
|
||||
GSM610_RTP_XMC8_2,
|
||||
GSM610_RTP_XMC9_0,
|
||||
GSM610_RTP_XMC9_1,
|
||||
GSM610_RTP_XMC9_2,
|
||||
GSM610_RTP_XMC10_0,
|
||||
GSM610_RTP_XMC10_1,
|
||||
GSM610_RTP_XMC10_2,
|
||||
GSM610_RTP_XMC11_0,
|
||||
GSM610_RTP_XMC11_1,
|
||||
GSM610_RTP_XMC11_2,
|
||||
GSM610_RTP_XMC12_0,
|
||||
GSM610_RTP_XMC12_1,
|
||||
GSM610_RTP_XCM12_2,
|
||||
GSM610_RTP_NC1_0,
|
||||
GSM610_RTP_NC1_1,
|
||||
GSM610_RTP_NC1_2,
|
||||
GSM610_RTP_NC1_3,
|
||||
GSM610_RTP_NC1_4,
|
||||
GSM610_RTP_NC1_5,
|
||||
GSM610_RTP_NC1_6,
|
||||
GSM610_RTP_BC1_0,
|
||||
GSM610_RTP_BC1_1,
|
||||
GSM610_RTP_MC1_0,
|
||||
GSM610_RTP_MC1_1,
|
||||
GSM610_RTP_XMAXC10,
|
||||
GSM610_RTP_XMAXC11,
|
||||
GSM610_RTP_XMAXC12,
|
||||
GSM610_RTP_XMAXC13,
|
||||
GSM610_RTP_XMAXC14,
|
||||
GSM610_RTP_XMAX15,
|
||||
GSM610_RTP_XMC13_0,
|
||||
GSM610_RTP_XMC13_1,
|
||||
GSM610_RTP_XMC13_2,
|
||||
GSM610_RTP_XMC14_0,
|
||||
GSM610_RTP_XMC14_1,
|
||||
GSM610_RTP_XMC14_2,
|
||||
GSM610_RTP_XMC15_0,
|
||||
GSM610_RTP_XMC15_1,
|
||||
GSM610_RTP_XMC15_2,
|
||||
GSM610_RTP_XMC16_0,
|
||||
GSM610_RTP_XMC16_1,
|
||||
GSM610_RTP_XMC16_2,
|
||||
GSM610_RTP_XMC17_0,
|
||||
GSM610_RTP_XMC17_1,
|
||||
GSM610_RTP_XMC17_2,
|
||||
GSM610_RTP_XMC18_0,
|
||||
GSM610_RTP_XMC18_1,
|
||||
GSM610_RTP_XMC18_2,
|
||||
GSM610_RTP_XMC19_0,
|
||||
GSM610_RTP_XMC19_1,
|
||||
GSM610_RTP_XMC19_2,
|
||||
GSM610_RTP_XMC20_0,
|
||||
GSM610_RTP_XMC20_1,
|
||||
GSM610_RTP_XMC20_2,
|
||||
GSM610_RTP_XMC21_0,
|
||||
GSM610_RTP_XMC21_1,
|
||||
GSM610_RTP_XMC21_2,
|
||||
GSM610_RTP_XMC22_0,
|
||||
GSM610_RTP_XMC22_1,
|
||||
GSM610_RTP_XMC22_2,
|
||||
GSM610_RTP_XMC23_0,
|
||||
GSM610_RTP_XMC23_1,
|
||||
GSM610_RTP_XMC23_2,
|
||||
GSM610_RTP_XMC24_0,
|
||||
GSM610_RTP_XMC24_1,
|
||||
GSM610_RTP_XMC24_2,
|
||||
GSM610_RTP_XMC25_0,
|
||||
GSM610_RTP_XMC25_1,
|
||||
GSM610_RTP_XMC25_2,
|
||||
GSM610_RTP_NC2_0,
|
||||
GSM610_RTP_NC2_1,
|
||||
GSM610_RTP_NC2_2,
|
||||
GSM610_RTP_NC2_3,
|
||||
GSM610_RTP_NC2_4,
|
||||
GSM610_RTP_NC2_5,
|
||||
GSM610_RTP_NC2_6,
|
||||
GSM610_RTP_BC2_0,
|
||||
GSM610_RTP_BC2_1,
|
||||
GSM610_RTP_MC2_0,
|
||||
GSM610_RTP_MC2_1,
|
||||
GSM610_RTP_XMAXC20,
|
||||
GSM610_RTP_XMAXC21,
|
||||
GSM610_RTP_XMAXC22,
|
||||
GSM610_RTP_XMAXC23,
|
||||
GSM610_RTP_XMAXC24,
|
||||
GSM610_RTP_XMAXC25,
|
||||
GSM610_RTP_XMC26_0,
|
||||
GSM610_RTP_XMC26_1,
|
||||
GSM610_RTP_XMC26_2,
|
||||
GSM610_RTP_XMC27_0,
|
||||
GSM610_RTP_XMC27_1,
|
||||
GSM610_RTP_XMC27_2,
|
||||
GSM610_RTP_XMC28_0,
|
||||
GSM610_RTP_XMC28_1,
|
||||
GSM610_RTP_XMC28_2,
|
||||
GSM610_RTP_XMC29_0,
|
||||
GSM610_RTP_XMC29_1,
|
||||
GSM610_RTP_XMC29_2,
|
||||
GSM610_RTP_XMC30_0,
|
||||
GSM610_RTP_XMC30_1,
|
||||
GSM610_RTP_XMC30_2,
|
||||
GSM610_RTP_XMC31_0,
|
||||
GSM610_RTP_XMC31_1,
|
||||
GSM610_RTP_XMC31_2,
|
||||
GSM610_RTP_XMC32_0,
|
||||
GSM610_RTP_XMC32_1,
|
||||
GSM610_RTP_XMC32_2,
|
||||
GSM610_RTP_XMC33_0,
|
||||
GSM610_RTP_XMC33_1,
|
||||
GSM610_RTP_XMC33_2,
|
||||
GSM610_RTP_XMC34_0,
|
||||
GSM610_RTP_XMC34_1,
|
||||
GSM610_RTP_XMC34_2,
|
||||
GSM610_RTP_XMC35_0,
|
||||
GSM610_RTP_XMC35_1,
|
||||
GSM610_RTP_XMC35_2,
|
||||
GSM610_RTP_XMC36_0,
|
||||
GSM610_RTP_XMC36_1,
|
||||
GSM610_RTP_XMC36_2,
|
||||
GSM610_RTP_XMC37_0,
|
||||
GSM610_RTP_XMC37_1,
|
||||
GSM610_RTP_XMC37_2,
|
||||
GSM610_RTP_XMC38_0,
|
||||
GSM610_RTP_XMC38_1,
|
||||
GSM610_RTP_XMC38_2,
|
||||
GSM610_RTP_NC3_0,
|
||||
GSM610_RTP_NC3_1,
|
||||
GSM610_RTP_NC3_2,
|
||||
GSM610_RTP_NC3_3,
|
||||
GSM610_RTP_NC3_4,
|
||||
GSM610_RTP_NC3_5,
|
||||
GSM610_RTP_NC3_6,
|
||||
GSM610_RTP_BC3_0,
|
||||
GSM610_RTP_BC3_1,
|
||||
GSM610_RTP_MC3_0,
|
||||
GSM610_RTP_MC3_1,
|
||||
GSM610_RTP_XMAXC30,
|
||||
GSM610_RTP_XMAXC31,
|
||||
GSM610_RTP_XMAXC32,
|
||||
GSM610_RTP_XMAXC33,
|
||||
GSM610_RTP_XMAXC34,
|
||||
GSM610_RTP_XMAXC35,
|
||||
GSM610_RTP_XMC39_0,
|
||||
GSM610_RTP_XMC39_1,
|
||||
GSM610_RTP_XMC39_2,
|
||||
GSM610_RTP_XMC40_0,
|
||||
GSM610_RTP_XMC40_1,
|
||||
GSM610_RTP_XMC40_2,
|
||||
GSM610_RTP_XMC41_0,
|
||||
GSM610_RTP_XMC41_1,
|
||||
GSM610_RTP_XMC41_2,
|
||||
GSM610_RTP_XMC42_0,
|
||||
GSM610_RTP_XMC42_1,
|
||||
GSM610_RTP_XMC42_2,
|
||||
GSM610_RTP_XMC43_0,
|
||||
GSM610_RTP_XMC43_1,
|
||||
GSM610_RTP_XMC43_2,
|
||||
GSM610_RTP_XMC44_0,
|
||||
GSM610_RTP_XMC44_1,
|
||||
GSM610_RTP_XMC44_2,
|
||||
GSM610_RTP_XMC45_0,
|
||||
GSM610_RTP_XMC45_1,
|
||||
GSM610_RTP_XMC45_2,
|
||||
GSM610_RTP_XMC46_0,
|
||||
GSM610_RTP_XMC46_1,
|
||||
GSM610_RTP_XMC46_2,
|
||||
GSM610_RTP_XMC47_0,
|
||||
GSM610_RTP_XMC47_1,
|
||||
GSM610_RTP_XMC47_2,
|
||||
GSM610_RTP_XMC48_0,
|
||||
GSM610_RTP_XMC48_1,
|
||||
GSM610_RTP_XMC48_2,
|
||||
GSM610_RTP_XMC49_0,
|
||||
GSM610_RTP_XMC49_1,
|
||||
GSM610_RTP_XMC49_2,
|
||||
GSM610_RTP_XMC50_0,
|
||||
GSM610_RTP_XMC50_1,
|
||||
GSM610_RTP_XMC50_2,
|
||||
GSM610_RTP_XMC51_0,
|
||||
GSM610_RTP_XMC51_1,
|
||||
GSM610_RTP_XMC51_2
|
||||
};
|
|
@ -1,297 +0,0 @@
|
|||
/*! \file gsm620.c
|
||||
* GSM 06.20 - GSM HR codec. */
|
||||
/*
|
||||
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/bitvec.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
/* GSM HR unvoiced (mode=0) frames - subjective importance bit ordering */
|
||||
/* This array encode mapping between GSM 05.03 Table 3a (bits
|
||||
* ordering before channel coding on TCH) and GSM 06.20 Table B.1
|
||||
* (bit ordering on A-bis */
|
||||
const uint16_t gsm620_unvoiced_bitorder[112] = {
|
||||
3, /* R0:1 */
|
||||
25, /* LPC 3:7 */
|
||||
52, /* GSP 0-1:2 */
|
||||
71, /* GSP 0-2:2 */
|
||||
90, /* GSP 0-3:2 */
|
||||
109, /* GSP 0-4:2 */
|
||||
15, /* LPC 1:0 */
|
||||
19, /* LPC 2:5 */
|
||||
20, /* LPC 2:4 */
|
||||
21, /* LPC 2:3 */
|
||||
22, /* LPC 2:2 */
|
||||
23, /* LPC 2:1 */
|
||||
26, /* LPC 3:6 */
|
||||
27, /* LPC 3:5 */
|
||||
28, /* LPC 3:4 */
|
||||
29, /* LPC 3:3 */
|
||||
30, /* LPC 3:2 */
|
||||
31, /* LPC 3:1 */
|
||||
61, /* Code 1-2:0 */
|
||||
62, /* Code 2-2:6 */
|
||||
63, /* Code 2-2:5 */
|
||||
64, /* Code 2-2:4 */
|
||||
65, /* Code 2-2:3 */
|
||||
66, /* Code 2-2:2 */
|
||||
67, /* Code 2-2:1 */
|
||||
68, /* Code 2-2:0 */
|
||||
74, /* Code 1-3:6 */
|
||||
75, /* Code 1-3:5 */
|
||||
76, /* Code 1-3:4 */
|
||||
77, /* Code 1-3:3 */
|
||||
78, /* Code 1-3:2 */
|
||||
79, /* Code 1-3:1 */
|
||||
80, /* Code 1-3:0 */
|
||||
81, /* Code 2-3:6 */
|
||||
82, /* Code 2-3:5 */
|
||||
83, /* Code 2-3:4 */
|
||||
84, /* Code 2-3:3 */
|
||||
32, /* LPC 3:0 */
|
||||
4, /* R0:0 */
|
||||
33, /* INT-LPC:0 */
|
||||
60, /* Code 1-2:1 */
|
||||
59, /* Code 1-2:2 */
|
||||
58, /* Code 1-2:3 */
|
||||
57, /* Code 1-2:4 */
|
||||
56, /* Code 1-2:5 */
|
||||
55, /* Code 1-2:6 */
|
||||
49, /* Code 2-1:0 */
|
||||
48, /* Code 2-1:1 */
|
||||
47, /* Code 2-1:2 */
|
||||
46, /* Code 2-1:3 */
|
||||
45, /* Code 2-1:4 */
|
||||
44, /* Code 2-1:5 */
|
||||
43, /* Code 2-1:6 */
|
||||
42, /* Code 1-1:0 */
|
||||
41, /* Code 1-1:1 */
|
||||
40, /* Code 1-1:2 */
|
||||
39, /* Code 1-1:3 */
|
||||
38, /* Code 1-1:4 */
|
||||
37, /* Code 1-1:5 */
|
||||
36, /* Code 1-1:6 */
|
||||
111, /* GSP 0-4:0 */
|
||||
92, /* GSP 0-3:0 */
|
||||
73, /* GSP 0-2:0 */
|
||||
54, /* GSP 0-1:0 */
|
||||
24, /* LPC 2:0 */
|
||||
110, /* GSP 0-4:1 */
|
||||
91, /* GSP 0-3:1 */
|
||||
72, /* GSP 0-2:1 */
|
||||
53, /* GSP 0-1:1 */
|
||||
14, /* LPC 1:1 */
|
||||
13, /* LPC 1:2 */
|
||||
12, /* LPC 1:3 */
|
||||
11, /* LPC 1:4 */
|
||||
10, /* LPC 1:5 */
|
||||
108, /* GSP 0-4:3 */
|
||||
89, /* GSP 0-3:3 */
|
||||
70, /* GSP 0-2:3 */
|
||||
51, /* GSP 0-1:3 */
|
||||
16, /* LPC 2:8 */
|
||||
17, /* LPC 2:7 */
|
||||
18, /* LPC 2:6 */
|
||||
107, /* GSP 0-4:4 */
|
||||
88, /* GSP 0-3:4 */
|
||||
69, /* GSP 0-2:4 */
|
||||
50, /* GSP 0-1:4 */
|
||||
9, /* LPC 1:6 */
|
||||
8, /* LPC 1:7 */
|
||||
7, /* LPC 1:8 */
|
||||
6, /* LPC 1:9 */
|
||||
2, /* R0:2 */
|
||||
5, /* LPC 1:10 */
|
||||
1, /* R0:3 */
|
||||
0, /* R0:4 */
|
||||
35, /* Mode:0 */
|
||||
34, /* Mode:1 */
|
||||
106, /* Code 2-4:0 */
|
||||
105, /* Code 2-4:1 */
|
||||
104, /* Code 2-4:2 */
|
||||
103, /* Code 2-4:3 */
|
||||
102, /* Code 2-4:4 */
|
||||
101, /* Code 2-4:5 */
|
||||
100, /* Code 2-4:6 */
|
||||
99, /* Code 1-4:0 */
|
||||
98, /* Code 1-4:1 */
|
||||
97, /* Code 1-4:2 */
|
||||
96, /* Code 1-4:3 */
|
||||
95, /* Code 1-4:4 */
|
||||
94, /* Code 1-4:5 */
|
||||
93, /* Code 1-4:6 */
|
||||
87, /* Code 2-3:0 */
|
||||
86, /* Code 2-3:1 */
|
||||
85, /* Code 2-3:2 */
|
||||
};
|
||||
|
||||
/* GSM HR voiced (mode=1,2,3) frames - subjective importance bit ordering */
|
||||
/* This array encode mapping between GSM 05.03 Table 3b (bits
|
||||
* ordering before channel coding on TCH) and GSM 06.20 Table B.2
|
||||
* (bit ordering on A-bis */
|
||||
const uint16_t gsm620_voiced_bitorder[112] = {
|
||||
13, /* LPC 1:2 */
|
||||
14, /* LPC 1:1 */
|
||||
18, /* LPC 2:6 */
|
||||
19, /* LPC 2:5 */
|
||||
20, /* LPC 2:4 */
|
||||
53, /* GSP 0-1:4 */
|
||||
71, /* GSP 0-2:4 */
|
||||
89, /* GSP 0-3:4 */
|
||||
107, /* GSP 0-4:4 */
|
||||
54, /* GSP 0-1:3 */
|
||||
72, /* GSP 0-2:3 */
|
||||
90, /* GSP 0-3:3 */
|
||||
108, /* GSP 0-4:3 */
|
||||
55, /* GSP 0-1:2 */
|
||||
73, /* GSP 0-2:2 */
|
||||
91, /* GSP 0-3:2 */
|
||||
109, /* GSP 0-4:2 */
|
||||
44, /* Code 1:8 */
|
||||
45, /* Code 1:7 */
|
||||
46, /* Code 1:6 */
|
||||
47, /* Code 1:5 */
|
||||
48, /* Code 1:4 */
|
||||
49, /* Code 1:3 */
|
||||
50, /* Code 1:2 */
|
||||
51, /* Code 1:1 */
|
||||
52, /* Code 1:0 */
|
||||
62, /* Code 2:8 */
|
||||
63, /* Code 2:7 */
|
||||
64, /* Code 2:6 */
|
||||
65, /* Code 2:5 */
|
||||
68, /* Code 2:2 */
|
||||
69, /* Code 2:1 */
|
||||
70, /* Code 2:0 */
|
||||
80, /* Code 3:8 */
|
||||
66, /* Code 2:4 */
|
||||
67, /* Code 2:3 */
|
||||
56, /* GSP 0-1:1 */
|
||||
74, /* GSP 0-2:1 */
|
||||
92, /* GSP 0-3:1 */
|
||||
110, /* GSP 0-4:1 */
|
||||
57, /* GSP 0-1:0 */
|
||||
75, /* GSP 0-2:0 */
|
||||
93, /* GSP 0-3:0 */
|
||||
111, /* GSP 0-4:0 */
|
||||
33, /* INT-LPC:0 */
|
||||
24, /* LPC 2:0 */
|
||||
32, /* LPC 3:0 */
|
||||
97, /* LAG 4:0 */
|
||||
31, /* LPC 3:1 */
|
||||
23, /* LPC 2:1 */
|
||||
96, /* LAG 4:1 */
|
||||
79, /* LAG 3:0 */
|
||||
61, /* LAG 2:0 */
|
||||
43, /* LAG 1:0 */
|
||||
95, /* LAG 4:2 */
|
||||
78, /* LAG 3:1 */
|
||||
60, /* LAG 2:1 */
|
||||
42, /* LAG 1:1 */
|
||||
30, /* LPC 3:2 */
|
||||
29, /* LPC 3:3 */
|
||||
28, /* LPC 3:4 */
|
||||
22, /* LPC 2:2 */
|
||||
27, /* LPC 3:5 */
|
||||
26, /* LPC 3:6 */
|
||||
21, /* LPC 2:3 */
|
||||
4, /* R0:0 */
|
||||
25, /* LPC 3:7 */
|
||||
15, /* LPC 1:0 */
|
||||
94, /* LAG 4:3 */
|
||||
77, /* LAG 3:2 */
|
||||
59, /* LAG 2:2 */
|
||||
41, /* LAG 1:2 */
|
||||
3, /* R0:1 */
|
||||
76, /* LAG 3:3 */
|
||||
58, /* LAG 2:3 */
|
||||
40, /* LAG 1:3 */
|
||||
39, /* LAG 1:4 */
|
||||
17, /* LPC 2:7 */
|
||||
16, /* LPC 2:8 */
|
||||
12, /* LPC 1:3 */
|
||||
11, /* LPC 1:4 */
|
||||
10, /* LPC 1:5 */
|
||||
9, /* LPC 1:6 */
|
||||
2, /* R0:2 */
|
||||
38, /* LAG 1:5 */
|
||||
37, /* LAG 1:6 */
|
||||
36, /* LAG 1:7 */
|
||||
8, /* LPC 1:7 */
|
||||
7, /* LPC 1:8 */
|
||||
6, /* LPC 1:9 */
|
||||
5, /* LPC 1:10 */
|
||||
1, /* R0:3 */
|
||||
0, /* R0:4 */
|
||||
35, /* Mode:0 */
|
||||
34, /* Mode:1 */
|
||||
106, /* Code 4:0 */
|
||||
105, /* Code 4:1 */
|
||||
104, /* Code 4:2 */
|
||||
103, /* Code 4:3 */
|
||||
102, /* Code 4:4 */
|
||||
101, /* Code 4:5 */
|
||||
100, /* Code 4:6 */
|
||||
99, /* Code 4:7 */
|
||||
98, /* Code 4:8 */
|
||||
88, /* Code 3:0 */
|
||||
87, /* Code 3:1 */
|
||||
86, /* Code 3:2 */
|
||||
85, /* Code 3:3 */
|
||||
84, /* Code 3:4 */
|
||||
83, /* Code 3:5 */
|
||||
82, /* Code 3:6 */
|
||||
81, /* Code 3:7 */
|
||||
};
|
||||
|
||||
static inline uint16_t mask(const uint8_t msb)
|
||||
{
|
||||
const uint16_t m = (uint16_t)1 << (msb - 1);
|
||||
return (m - 1) ^ m;
|
||||
}
|
||||
|
||||
/*! Check whether RTP frame contains HR SID code word according to
|
||||
* TS 101 318 §5.2.2
|
||||
* \param[in] rtp_payload Buffer with RTP payload
|
||||
* \param[in] payload_len Length of payload
|
||||
* \returns true if code word is found, false otherwise
|
||||
*/
|
||||
bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
|
||||
{
|
||||
uint8_t i, bits[] = { 1, 2, 8, 9, 5, 4, 9, 5, 4, 9, 5, 4, 9, 5 };
|
||||
struct bitvec bv;
|
||||
bv.data = (uint8_t *) rtp_payload;
|
||||
bv.data_len = payload_len;
|
||||
bv.cur_bit = 33;
|
||||
|
||||
/* code word is all 1 at given bits, numbered from 1, MODE is always 3 */
|
||||
for (i = 0; i < ARRAY_SIZE(bits); i++)
|
||||
if (bitvec_get_uint(&bv, bits[i]) != mask(bits[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,259 +0,0 @@
|
|||
/*! \file gsm660.c
|
||||
* GSM 06.60 - GSM EFR Codec. */
|
||||
/*
|
||||
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
|
||||
/* GSM EFR - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 6.
|
||||
*
|
||||
* It converts between serial parameter output (as described in
|
||||
* GSM 06.60 Table 6 and GSM 05.03 Table 5) and the order needed
|
||||
* before channel encoding. CRC poly and bit repetition must be
|
||||
* applied prior to this table, as in GSM 05.03 3.1.1, to get 260
|
||||
* bits from a 244 bits raw EFR frame.
|
||||
*/
|
||||
const uint16_t gsm660_bitorder[260] = {
|
||||
38, 39, 40, 41, 42, 43, /* 0 -> LTP-LAG 1: b8..b3 */
|
||||
145, 146, 147, 148, 149, 150, /* 6 -> LTP-LAG 3: b8..b3 */
|
||||
93, 94, /* 12 -> LTP-LAG 2: b5..b4 */
|
||||
200, 201, /* 14 -> LTP-LAG 4: b5..b4 */
|
||||
47, /* 16 -> LTP-GAIN 1: b3 */
|
||||
88, /* 17 -> FCB-GAIN 1: b4 */
|
||||
99, /* 18 -> LTP-GAIN 2: b3 */
|
||||
140, /* 19 -> FCB-GAIN 2: b4 */
|
||||
44, /* 20 -> LTP-LAG 1: b2 */
|
||||
151, /* 21 -> LTP-LAG 3: b2 */
|
||||
95, /* 22 -> LTP-LAG 2: b3 */
|
||||
202, /* 23 -> LTP-LAG 4: b3 */
|
||||
1, 2, /* 24 -> LPC 1: b5..b4 */
|
||||
7, /* 26 -> LPC 2: b7 */
|
||||
9, /* 27 -> LPC 2: b5 */
|
||||
17, 18, /* 28 -> LPC 3: b6..b5 */
|
||||
23, /* 30 -> LPC 3: b0 */
|
||||
45, 46, /* 31 -> LTP-LAG 1: b1..b0 */
|
||||
152, 153, /* 33 -> LTP-LAG 3: b1..b0 */
|
||||
96, /* 35 -> LTP-LAG 2: b2 */
|
||||
203, /* 36 -> LTP-LAG 4: b2 */
|
||||
3, 4, /* 37 -> LPC 1: b3..b2 */
|
||||
10, 11, /* 39 -> LPC 2: b4..b3 */
|
||||
15, /* 41 -> LPC 3: b8 */
|
||||
8, /* 42 -> LPC 2: b6 */
|
||||
5, 6, /* 43 -> LPC 1: b1..b0 */
|
||||
12, /* 45 -> LPC 2: b2 */
|
||||
16, /* 46 -> LPC 3: b7 */
|
||||
19, /* 47 -> LPC 3: b4 */
|
||||
97, /* 48 -> LTP-LAG 2: b1 */
|
||||
204, /* 49 -> LTP-LAG 4: b1 */
|
||||
0, /* 50 -> LPC 1: b6 */
|
||||
13, 14, /* 51 -> LPC 2: b1..b0 */
|
||||
20, /* 53 -> LPC 3: b3 */
|
||||
24, 25, /* 54 -> LPC 4: b7..b6 */
|
||||
27, /* 56 -> LPC 4: b4 */
|
||||
154, /* 57 -> LTP-GAIN 3: b3 */
|
||||
206, /* 58 -> LTP-GAIN 4: b3 */
|
||||
195, /* 59 -> FCB-GAIN 3: b4 */
|
||||
247, /* 60 -> FCB-GAIN 4: b4 */
|
||||
89, /* 61 -> FCB-GAIN 1: b3 */
|
||||
141, /* 62 -> FCB-GAIN 2: b3 */
|
||||
196, /* 63 -> FCB-GAIN 3: b3 */
|
||||
248, /* 64 -> FCB-GAIN 4: b3 */
|
||||
252, 253, 254, 255, 256, 257, 258, 259, /* 65 -> CRC-POLY: b7..b0 */
|
||||
48, /* 73 -> LTP-GAIN 1: b2 */
|
||||
100, /* 74 -> LTP-GAIN 2: b2 */
|
||||
155, /* 75 -> LTP-GAIN 3: b2 */
|
||||
207, /* 76 -> LTP-GAIN 4: b2 */
|
||||
21, 22, /* 77 -> LPC 3: b2..b1 */
|
||||
26, /* 79 -> LPC 4: b5 */
|
||||
28, /* 80 -> LPC 4: b3 */
|
||||
51, /* 81 -> PULSE 1_1: b3 */
|
||||
55, /* 82 -> PULSE 1_2: b3 */
|
||||
59, /* 83 -> PULSE 1_3: b3 */
|
||||
63, /* 84 -> PULSE 1_4: b3 */
|
||||
67, /* 85 -> PULSE 1_5: b3 */
|
||||
103, /* 86 -> PULSE 2_1: b3 */
|
||||
107, /* 87 -> PULSE 2_2: b3 */
|
||||
111, /* 88 -> PULSE 2_3: b3 */
|
||||
115, /* 89 -> PULSE 2_4: b3 */
|
||||
119, /* 90 -> PULSE 2_5: b3 */
|
||||
158, /* 91 -> PULSE 3_1: b3 */
|
||||
162, /* 92 -> PULSE 3_2: b3 */
|
||||
166, /* 93 -> PULSE 3_3: b3 */
|
||||
170, /* 94 -> PULSE 3_4: b3 */
|
||||
174, /* 95 -> PULSE 3_5: b3 */
|
||||
210, /* 96 -> PULSE 4_1: b3 */
|
||||
214, /* 97 -> PULSE 4_2: b3 */
|
||||
218, /* 98 -> PULSE 4_3: b3 */
|
||||
222, /* 99 -> PULSE 4_4: b3 */
|
||||
226, /* 100 -> PULSE 4_5: b3 */
|
||||
90, /* 101 -> FCB-GAIN 1: b2 */
|
||||
142, /* 102 -> FCB-GAIN 2: b2 */
|
||||
197, /* 103 -> FCB-GAIN 3: b2 */
|
||||
249, /* 104 -> FCB-GAIN 4: b2 */
|
||||
49, /* 105 -> LTP-GAIN 1: b1 */
|
||||
101, /* 106 -> LTP-GAIN 2: b1 */
|
||||
156, /* 107 -> LTP-GAIN 3: b1 */
|
||||
208, /* 108 -> LTP-GAIN 4: b1 */
|
||||
29, 30, 31, /* 109 -> LPC 4: b2..b0 */
|
||||
32, 33, 34, 35, /* 112 -> LPC 5: b5..b2 */
|
||||
98, /* 116 -> LTP-LAG 2: b0 */
|
||||
205, /* 117 -> LTP-LAG 4: b0 */
|
||||
52, /* 118 -> PULSE 1_1: b2 */
|
||||
56, /* 119 -> PULSE 1_2: b2 */
|
||||
60, /* 120 -> PULSE 1_3: b2 */
|
||||
64, /* 121 -> PULSE 1_4: b2 */
|
||||
68, /* 122 -> PULSE 1_5: b2 */
|
||||
104, /* 123 -> PULSE 2_1: b2 */
|
||||
108, /* 124 -> PULSE 2_2: b2 */
|
||||
112, /* 125 -> PULSE 2_3: b2 */
|
||||
116, /* 126 -> PULSE 2_4: b2 */
|
||||
120, /* 127 -> PULSE 2_5: b2 */
|
||||
159, /* 128 -> PULSE 3_1: b2 */
|
||||
163, /* 129 -> PULSE 3_2: b2 */
|
||||
167, /* 130 -> PULSE 3_3: b2 */
|
||||
171, /* 131 -> PULSE 3_4: b2 */
|
||||
175, /* 132 -> PULSE 3_5: b2 */
|
||||
211, /* 133 -> PULSE 4_1: b2 */
|
||||
215, /* 134 -> PULSE 4_2: b2 */
|
||||
219, /* 135 -> PULSE 4_3: b2 */
|
||||
223, /* 136 -> PULSE 4_4: b2 */
|
||||
227, /* 137 -> PULSE 4_5: b2 */
|
||||
53, /* 138 -> PULSE 1_1: b1 */
|
||||
57, /* 139 -> PULSE 1_2: b1 */
|
||||
61, /* 140 -> PULSE 1_3: b1 */
|
||||
65, /* 141 -> PULSE 1_4: b1 */
|
||||
105, /* 142 -> PULSE 2_1: b1 */
|
||||
109, /* 143 -> PULSE 2_2: b1 */
|
||||
113, /* 144 -> PULSE 2_3: b1 */
|
||||
117, /* 145 -> PULSE 2_4: b1 */
|
||||
160, /* 146 -> PULSE 3_1: b1 */
|
||||
164, /* 147 -> PULSE 3_2: b1 */
|
||||
168, /* 148 -> PULSE 3_3: b1 */
|
||||
172, /* 149 -> PULSE 3_4: b1 */
|
||||
212, /* 150 -> PULSE 4_1: b1 */
|
||||
220, /* 151 -> PULSE 4_3: b1 */
|
||||
224, /* 152 -> PULSE 4_4: b1 */
|
||||
91, /* 153 -> FCB-GAIN 1: b1 */
|
||||
143, /* 154 -> FCB-GAIN 2: b1 */
|
||||
198, /* 155 -> FCB-GAIN 3: b1 */
|
||||
250, /* 156 -> FCB-GAIN 4: b1 */
|
||||
50, /* 157 -> LTP-GAIN 1: b0 */
|
||||
102, /* 158 -> LTP-GAIN 2: b0 */
|
||||
157, /* 159 -> LTP-GAIN 3: b0 */
|
||||
209, /* 160 -> LTP-GAIN 4: b0 */
|
||||
92, /* 161 -> FCB-GAIN 1: b0 */
|
||||
144, /* 162 -> FCB-GAIN 2: b0 */
|
||||
199, /* 163 -> FCB-GAIN 3: b0 */
|
||||
251, /* 164 -> FCB-GAIN 4: b0 */
|
||||
54, /* 165 -> PULSE 1_1: b0 */
|
||||
58, /* 166 -> PULSE 1_2: b0 */
|
||||
62, /* 167 -> PULSE 1_3: b0 */
|
||||
66, /* 168 -> PULSE 1_4: b0 */
|
||||
106, /* 169 -> PULSE 2_1: b0 */
|
||||
110, /* 170 -> PULSE 2_2: b0 */
|
||||
114, /* 171 -> PULSE 2_3: b0 */
|
||||
118, /* 172 -> PULSE 2_4: b0 */
|
||||
161, /* 173 -> PULSE 3_1: b0 */
|
||||
165, /* 174 -> PULSE 3_2: b0 */
|
||||
169, /* 175 -> PULSE 3_3: b0 */
|
||||
173, /* 176 -> PULSE 3_4: b0 */
|
||||
213, /* 177 -> PULSE 4_1: b0 */
|
||||
221, /* 178 -> PULSE 4_3: b0 */
|
||||
225, /* 179 -> PULSE 4_4: b0 */
|
||||
36, 37, /* 180 -> LPC 5: b1..b0 */
|
||||
69, /* 182 -> PULSE 1_5: b1 */
|
||||
71, 72, /* 183 -> PULSE 1_5: b1..b1 */
|
||||
121, /* 185 -> PULSE 2_5: b1 */
|
||||
123, 124, /* 186 -> PULSE 2_5: b1..b1 */
|
||||
176, /* 188 -> PULSE 3_5: b1 */
|
||||
178, 179, /* 189 -> PULSE 3_5: b1..b1 */
|
||||
228, /* 191 -> PULSE 4_5: b1 */
|
||||
230, 231, /* 192 -> PULSE 4_5: b1..b1 */
|
||||
216, 217, /* 194 -> PULSE 4_2: b1..b0 */
|
||||
70, /* 196 -> PULSE 1_5: b0 */
|
||||
122, /* 197 -> PULSE 2_5: b0 */
|
||||
177, /* 198 -> PULSE 3_5: b0 */
|
||||
229, /* 199 -> PULSE 4_5: b0 */
|
||||
73, /* 200 -> PULSE 1_6: b2 */
|
||||
76, /* 201 -> PULSE 1_7: b2 */
|
||||
79, /* 202 -> PULSE 1_8: b2 */
|
||||
82, /* 203 -> PULSE 1_9: b2 */
|
||||
85, /* 204 -> PULSE 1_10: b2 */
|
||||
125, /* 205 -> PULSE 2_6: b2 */
|
||||
128, /* 206 -> PULSE 2_7: b2 */
|
||||
131, /* 207 -> PULSE 2_8: b2 */
|
||||
134, /* 208 -> PULSE 2_9: b2 */
|
||||
137, /* 209 -> PULSE 2_10: b2 */
|
||||
180, /* 210 -> PULSE 3_6: b2 */
|
||||
183, /* 211 -> PULSE 3_7: b2 */
|
||||
186, /* 212 -> PULSE 3_8: b2 */
|
||||
189, /* 213 -> PULSE 3_9: b2 */
|
||||
192, /* 214 -> PULSE 3_10: b2 */
|
||||
232, /* 215 -> PULSE 4_6: b2 */
|
||||
235, /* 216 -> PULSE 4_7: b2 */
|
||||
238, /* 217 -> PULSE 4_8: b2 */
|
||||
241, /* 218 -> PULSE 4_9: b2 */
|
||||
244, /* 219 -> PULSE 4_10: b2 */
|
||||
74, /* 220 -> PULSE 1_6: b1 */
|
||||
77, /* 221 -> PULSE 1_7: b1 */
|
||||
80, /* 222 -> PULSE 1_8: b1 */
|
||||
83, /* 223 -> PULSE 1_9: b1 */
|
||||
86, /* 224 -> PULSE 1_10: b1 */
|
||||
126, /* 225 -> PULSE 2_6: b1 */
|
||||
129, /* 226 -> PULSE 2_7: b1 */
|
||||
132, /* 227 -> PULSE 2_8: b1 */
|
||||
135, /* 228 -> PULSE 2_9: b1 */
|
||||
138, /* 229 -> PULSE 2_10: b1 */
|
||||
181, /* 230 -> PULSE 3_6: b1 */
|
||||
184, /* 231 -> PULSE 3_7: b1 */
|
||||
187, /* 232 -> PULSE 3_8: b1 */
|
||||
190, /* 233 -> PULSE 3_9: b1 */
|
||||
193, /* 234 -> PULSE 3_10: b1 */
|
||||
233, /* 235 -> PULSE 4_6: b1 */
|
||||
236, /* 236 -> PULSE 4_7: b1 */
|
||||
239, /* 237 -> PULSE 4_8: b1 */
|
||||
242, /* 238 -> PULSE 4_9: b1 */
|
||||
245, /* 239 -> PULSE 4_10: b1 */
|
||||
75, /* 240 -> PULSE 1_6: b0 */
|
||||
78, /* 241 -> PULSE 1_7: b0 */
|
||||
81, /* 242 -> PULSE 1_8: b0 */
|
||||
84, /* 243 -> PULSE 1_9: b0 */
|
||||
87, /* 244 -> PULSE 1_10: b0 */
|
||||
127, /* 245 -> PULSE 2_6: b0 */
|
||||
130, /* 246 -> PULSE 2_7: b0 */
|
||||
133, /* 247 -> PULSE 2_8: b0 */
|
||||
136, /* 248 -> PULSE 2_9: b0 */
|
||||
139, /* 249 -> PULSE 2_10: b0 */
|
||||
182, /* 250 -> PULSE 3_6: b0 */
|
||||
185, /* 251 -> PULSE 3_7: b0 */
|
||||
188, /* 252 -> PULSE 3_8: b0 */
|
||||
191, /* 253 -> PULSE 3_9: b0 */
|
||||
194, /* 254 -> PULSE 3_10: b0 */
|
||||
234, /* 255 -> PULSE 4_6: b0 */
|
||||
237, /* 256 -> PULSE 4_7: b0 */
|
||||
240, /* 257 -> PULSE 4_8: b0 */
|
||||
243, /* 258 -> PULSE 4_9: b0 */
|
||||
246, /* 259 -> PULSE 4_10: b0 */
|
||||
};
|
|
@ -1,318 +0,0 @@
|
|||
/*! \file gsm690.c
|
||||
* GSM 06.90 - GSM AMR Codec. */
|
||||
/*
|
||||
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/codec/codec.h>
|
||||
/*
|
||||
* These table map between the raw encoder parameter output and
|
||||
* the format used before channel coding. Both in GSM and in various
|
||||
* file/network format (same tables used in several specs).
|
||||
*/
|
||||
|
||||
/* AMR 12.2 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 7
|
||||
* It's also TS 26.101 Table B.8
|
||||
*/
|
||||
const uint16_t gsm690_12_2_bitorder[244] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 23, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 24, 25, 26, 27, 28, 38,
|
||||
141, 39, 142, 40, 143, 41, 144, 42, 145, 43,
|
||||
146, 44, 147, 45, 148, 46, 149, 47, 97, 150,
|
||||
200, 48, 98, 151, 201, 49, 99, 152, 202, 86,
|
||||
136, 189, 239, 87, 137, 190, 240, 88, 138, 191,
|
||||
241, 91, 194, 92, 195, 93, 196, 94, 197, 95,
|
||||
198, 29, 30, 31, 32, 33, 34, 35, 50, 100,
|
||||
153, 203, 89, 139, 192, 242, 51, 101, 154, 204,
|
||||
55, 105, 158, 208, 90, 140, 193, 243, 59, 109,
|
||||
162, 212, 63, 113, 166, 216, 67, 117, 170, 220,
|
||||
36, 37, 54, 53, 52, 58, 57, 56, 62, 61,
|
||||
60, 66, 65, 64, 70, 69, 68, 104, 103, 102,
|
||||
108, 107, 106, 112, 111, 110, 116, 115, 114, 120,
|
||||
119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
|
||||
163, 169, 168, 167, 173, 172, 171, 207, 206, 205,
|
||||
211, 210, 209, 215, 214, 213, 219, 218, 217, 223,
|
||||
222, 221, 73, 72, 71, 76, 75, 74, 79, 78,
|
||||
77, 82, 81, 80, 85, 84, 83, 123, 122, 121,
|
||||
126, 125, 124, 129, 128, 127, 132, 131, 130, 135,
|
||||
134, 133, 176, 175, 174, 179, 178, 177, 182, 181,
|
||||
180, 185, 184, 183, 188, 187, 186, 226, 225, 224,
|
||||
229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
|
||||
237, 236, 96, 199,
|
||||
};
|
||||
|
||||
/* AMR 10.2 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 8
|
||||
* It's also TS 26.101 Table B.7
|
||||
*/
|
||||
const uint16_t gsm690_10_2_bitorder[204] = {
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 16, 15,
|
||||
14, 13, 12, 11, 10, 9, 8, 26, 27, 28,
|
||||
29, 30, 31, 115, 116, 117, 118, 119, 120, 72,
|
||||
73, 161, 162, 65, 68, 69, 108, 111, 112, 154,
|
||||
157, 158, 197, 200, 201, 32, 33, 121, 122, 74,
|
||||
75, 163, 164, 66, 109, 155, 198, 19, 23, 21,
|
||||
22, 18, 17, 20, 24, 25, 37, 36, 35, 34,
|
||||
80, 79, 78, 77, 126, 125, 124, 123, 169, 168,
|
||||
167, 166, 70, 67, 71, 113, 110, 114, 159, 156,
|
||||
160, 202, 199, 203, 76, 165, 81, 82, 92, 91,
|
||||
93, 83, 95, 85, 84, 94, 101, 102, 96, 104,
|
||||
86, 103, 87, 97, 127, 128, 138, 137, 139, 129,
|
||||
141, 131, 130, 140, 147, 148, 142, 150, 132, 149,
|
||||
133, 143, 170, 171, 181, 180, 182, 172, 184, 174,
|
||||
173, 183, 190, 191, 185, 193, 175, 192, 176, 186,
|
||||
38, 39, 49, 48, 50, 40, 52, 42, 41, 51,
|
||||
58, 59, 53, 61, 43, 60, 44, 54, 194, 179,
|
||||
189, 196, 177, 195, 178, 187, 188, 151, 136, 146,
|
||||
153, 134, 152, 135, 144, 145, 105, 90, 100, 107,
|
||||
88, 106, 89, 98, 99, 62, 47, 57, 64, 45,
|
||||
63, 46, 55, 56,
|
||||
};
|
||||
|
||||
/* AMR 7.95 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 9
|
||||
* It's also TS 26.101 Table B.6
|
||||
*/
|
||||
const uint16_t gsm690_7_95_bitorder[159] = {
|
||||
8, 7, 6, 5, 4, 3, 2, 14, 16, 9,
|
||||
10, 12, 13, 15, 11, 17, 20, 22, 24, 23,
|
||||
19, 18, 21, 56, 88, 122, 154, 57, 89, 123,
|
||||
155, 58, 90, 124, 156, 52, 84, 118, 150, 53,
|
||||
85, 119, 151, 27, 93, 28, 94, 29, 95, 30,
|
||||
96, 31, 97, 61, 127, 62, 128, 63, 129, 59,
|
||||
91, 125, 157, 32, 98, 64, 130, 1, 0, 25,
|
||||
26, 33, 99, 34, 100, 65, 131, 66, 132, 54,
|
||||
86, 120, 152, 60, 92, 126, 158, 55, 87, 121,
|
||||
153, 117, 116, 115, 46, 78, 112, 144, 43, 75,
|
||||
109, 141, 40, 72, 106, 138, 36, 68, 102, 134,
|
||||
114, 149, 148, 147, 146, 83, 82, 81, 80, 51,
|
||||
50, 49, 48, 47, 45, 44, 42, 39, 35, 79,
|
||||
77, 76, 74, 71, 67, 113, 111, 110, 108, 105,
|
||||
101, 145, 143, 142, 140, 137, 133, 41, 73, 107,
|
||||
139, 37, 69, 103, 135, 38, 70, 104, 136,
|
||||
};
|
||||
|
||||
/* AMR 7.4 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 10
|
||||
* It's also TS 26.101 Table B.5
|
||||
*/
|
||||
const uint16_t gsm690_7_4_bitorder[148] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 15, 16, 26, 87, 27,
|
||||
88, 28, 89, 29, 90, 30, 91, 51, 80, 112,
|
||||
141, 52, 81, 113, 142, 54, 83, 115, 144, 55,
|
||||
84, 116, 145, 58, 119, 59, 120, 21, 22, 23,
|
||||
17, 18, 19, 31, 60, 92, 121, 56, 85, 117,
|
||||
146, 20, 24, 25, 50, 79, 111, 140, 57, 86,
|
||||
118, 147, 49, 78, 110, 139, 48, 77, 53, 82,
|
||||
114, 143, 109, 138, 47, 76, 108, 137, 32, 33,
|
||||
61, 62, 93, 94, 122, 123, 41, 42, 43, 44,
|
||||
45, 46, 70, 71, 72, 73, 74, 75, 102, 103,
|
||||
104, 105, 106, 107, 131, 132, 133, 134, 135, 136,
|
||||
34, 63, 95, 124, 35, 64, 96, 125, 36, 65,
|
||||
97, 126, 37, 66, 98, 127, 38, 67, 99, 128,
|
||||
39, 68, 100, 129, 40, 69, 101, 130,
|
||||
};
|
||||
|
||||
/* AMR 6.7 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 11
|
||||
* It's also TS 26.101 Table B.4
|
||||
*/
|
||||
const uint16_t gsm690_6_7_bitorder[134] = {
|
||||
0, 1, 4, 3, 5, 6, 13, 7, 2, 8,
|
||||
9, 11, 15, 12, 14, 10, 28, 82, 29, 83,
|
||||
27, 81, 26, 80, 30, 84, 16, 55, 109, 56,
|
||||
110, 31, 85, 57, 111, 48, 73, 102, 127, 32,
|
||||
86, 51, 76, 105, 130, 52, 77, 106, 131, 58,
|
||||
112, 33, 87, 19, 23, 53, 78, 107, 132, 21,
|
||||
22, 18, 17, 20, 24, 25, 50, 75, 104, 129,
|
||||
47, 72, 101, 126, 54, 79, 108, 133, 46, 71,
|
||||
100, 125, 128, 103, 74, 49, 45, 70, 99, 124,
|
||||
42, 67, 96, 121, 39, 64, 93, 118, 38, 63,
|
||||
92, 117, 35, 60, 89, 114, 34, 59, 88, 113,
|
||||
44, 69, 98, 123, 43, 68, 97, 122, 41, 66,
|
||||
95, 120, 40, 65, 94, 119, 37, 62, 91, 116,
|
||||
36, 61, 90, 115,
|
||||
};
|
||||
|
||||
/* AMR 5.9 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 12
|
||||
* It's also TS 26.101 Table B.3
|
||||
*/
|
||||
const uint16_t gsm690_5_9_bitorder[118] = {
|
||||
0, 1, 4, 5, 3, 6, 7, 2, 13, 15,
|
||||
8, 9, 11, 12, 14, 10, 16, 28, 74, 29,
|
||||
75, 27, 73, 26, 72, 30, 76, 51, 97, 50,
|
||||
71, 96, 117, 31, 77, 52, 98, 49, 70, 95,
|
||||
116, 53, 99, 32, 78, 33, 79, 48, 69, 94,
|
||||
115, 47, 68, 93, 114, 46, 67, 92, 113, 19,
|
||||
21, 23, 22, 18, 17, 20, 24, 111, 43, 89,
|
||||
110, 64, 65, 44, 90, 25, 45, 66, 91, 112,
|
||||
54, 100, 40, 61, 86, 107, 39, 60, 85, 106,
|
||||
36, 57, 82, 103, 35, 56, 81, 102, 34, 55,
|
||||
80, 101, 42, 63, 88, 109, 41, 62, 87, 108,
|
||||
38, 59, 84, 105, 37, 58, 83, 104,
|
||||
};
|
||||
|
||||
/* AMR 5.15 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 13
|
||||
* It's also TS 26.101 Table B.2
|
||||
*/
|
||||
const uint16_t gsm690_5_15_bitorder[103] = {
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
|
||||
13, 12, 11, 10, 9, 8, 23, 24, 25, 26,
|
||||
27, 46, 65, 84, 45, 44, 43, 64, 63, 62,
|
||||
83, 82, 81, 102, 101, 100, 42, 61, 80, 99,
|
||||
28, 47, 66, 85, 18, 41, 60, 79, 98, 29,
|
||||
48, 67, 17, 20, 22, 40, 59, 78, 97, 21,
|
||||
30, 49, 68, 86, 19, 16, 87, 39, 38, 58,
|
||||
57, 77, 35, 54, 73, 92, 76, 96, 95, 36,
|
||||
55, 74, 93, 32, 51, 33, 52, 70, 71, 89,
|
||||
90, 31, 50, 69, 88, 37, 56, 75, 94, 34,
|
||||
53, 72, 91,
|
||||
};
|
||||
|
||||
/* AMR 4.75 kbits - subjective importance bit ordering */
|
||||
/* This array encodes GSM 05.03 Table 14
|
||||
* It's also TS 26.101 Table B.1
|
||||
*/
|
||||
const uint16_t gsm690_4_75_bitorder[95] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 15, 23, 24, 25, 26,
|
||||
27, 28, 48, 49, 61, 62, 82, 83, 47, 46,
|
||||
45, 44, 81, 80, 79, 78, 17, 18, 20, 22,
|
||||
77, 76, 75, 74, 29, 30, 43, 42, 41, 40,
|
||||
38, 39, 16, 19, 21, 50, 51, 59, 60, 63,
|
||||
64, 72, 73, 84, 85, 93, 94, 32, 33, 35,
|
||||
36, 53, 54, 56, 57, 66, 67, 69, 70, 87,
|
||||
88, 90, 91, 34, 55, 68, 89, 37, 58, 71,
|
||||
92, 31, 52, 65, 86,
|
||||
};
|
||||
|
||||
static const uint8_t amr_len_by_ft[16] = {
|
||||
12, 13, 15, 17, 19, 20, 26, 31, 7, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const struct value_string osmo_amr_type_names[] = {
|
||||
{ AMR_4_75, "AMR 4,75 kbits/s" },
|
||||
{ AMR_5_15, "AMR 5,15 kbit/s" },
|
||||
{ AMR_5_90, "AMR 5,90 kbit/s" },
|
||||
{ AMR_6_70, "AMR 6,70 kbit/s (PDC-EFR)" },
|
||||
{ AMR_7_40, "AMR 7,40 kbit/s (TDMA-EFR)" },
|
||||
{ AMR_7_95, "AMR 7,95 kbit/s" },
|
||||
{ AMR_10_2, "AMR 10,2 kbit/s" },
|
||||
{ AMR_12_2, "AMR 12,2 kbit/s (GSM-EFR)" },
|
||||
{ AMR_SID, "AMR SID" },
|
||||
{ AMR_GSM_EFR_SID, "GSM-EFR SID" },
|
||||
{ AMR_TDMA_EFR_SID, "TDMA-EFR SID" },
|
||||
{ AMR_PDC_EFR_SID, "PDC-EFR SID" },
|
||||
{ AMR_NO_DATA, "No Data/NA" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
/*! Decode various AMR parameters from RTP payload (RFC 4867) acording to
|
||||
* 3GPP TS 26.101
|
||||
* \param[in] rtppayload Payload from RTP packet
|
||||
* \param[in] payload_len length of rtppayload
|
||||
* \param[out] cmr AMR Codec Mode Request, not filled if NULL
|
||||
* \param[out] cmi AMR Codec Mode Indicator, -1 if not applicable for this type,
|
||||
* not filled if NULL
|
||||
* \param[out] ft AMR Frame Type, not filled if NULL
|
||||
* \param[out] bfi AMR Bad Frame Indicator, not filled if NULL
|
||||
* \param[out] sti AMR SID Type Indicator, -1 if not applicable for this type,
|
||||
* not filled if NULL
|
||||
* \returns length of AMR data or negative value on error
|
||||
*/
|
||||
int osmo_amr_rtp_dec(const uint8_t *rtppayload, int payload_len, uint8_t *cmr,
|
||||
int8_t *cmi, enum osmo_amr_type *ft,
|
||||
enum osmo_amr_quality *bfi, int8_t *sti)
|
||||
{
|
||||
if (payload_len < 2 || !rtppayload)
|
||||
return -EINVAL;
|
||||
|
||||
/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
|
||||
uint8_t type = (rtppayload[1] >> 3) & 0xf;
|
||||
|
||||
/* compound payloads are not supported */
|
||||
if (rtppayload[1] >> 7)
|
||||
return -ENOTSUP;
|
||||
|
||||
if (payload_len < amr_len_by_ft[type])
|
||||
return -ENOTSUP;
|
||||
|
||||
if (ft)
|
||||
*ft = type;
|
||||
|
||||
if (cmr)
|
||||
*cmr = rtppayload[0] >> 4;
|
||||
|
||||
if (bfi)
|
||||
*bfi = (rtppayload[1] >> 2) & 1;
|
||||
|
||||
/* Table 6 in 3GPP TS 26.101 */
|
||||
if (cmi)
|
||||
*cmi = (type == AMR_SID) ? ((rtppayload[6] >> 1) & 7) : -1;
|
||||
|
||||
if (sti)
|
||||
*sti = (type == AMR_SID) ? (rtppayload[6] & 0x10) : -1;
|
||||
|
||||
return 2 + amr_len_by_ft[type];
|
||||
}
|
||||
|
||||
/*! Encode various AMR parameters from RTP payload (RFC 4867)
|
||||
* \param[out] payload Payload for RTP packet, contains speech data (if any)
|
||||
* except for have 2 first bytes where header will be built
|
||||
* \param[in] cmr AMR codec Mode Request
|
||||
* \param[in] ft AMR Frame Type
|
||||
* \param[in] bfi AMR Bad Frame Indicator
|
||||
* \returns length of AMR data (header + ToC + speech data) or negative value
|
||||
* on error
|
||||
*
|
||||
* Note: only octet-aligned mode is supported so the header occupies 2 full
|
||||
* bytes. Optional interleaving header is not supported.
|
||||
*/
|
||||
int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
|
||||
enum osmo_amr_quality bfi)
|
||||
{
|
||||
if (cmr > 15)
|
||||
return -EINVAL;
|
||||
|
||||
if (ft > 15)
|
||||
return -ENOTSUP;
|
||||
|
||||
/* RFC 4867 § 4.3.1 payload header */
|
||||
payload[0] = cmr << 4;
|
||||
|
||||
/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
|
||||
payload[1] = (((uint8_t)ft) << 3) | (((uint8_t)bfi) << 2);
|
||||
|
||||
/* speech data */
|
||||
return 2 + amr_len_by_ft[ft];
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2011,2012 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GNU Radio
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
add_sources(
|
||||
gsm0503_conv.c
|
||||
gsm0503_coding.c
|
||||
gsm0503_interleaving.c
|
||||
gsm0503_mapping.c
|
||||
gsm0503_parity.c
|
||||
gsm0503_tables.c
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,85 +0,0 @@
|
|||
/*! \file gsm0503_coding.h
|
||||
* GSM TS 05.03 coding
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/defs.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
#include <stdbool.h> //!!
|
||||
|
||||
/*! \addtogroup coding
|
||||
* @{
|
||||
* \file gsm0503_coding.h */
|
||||
|
||||
#define GSM0503_GPRS_BURSTS_NBITS (116 * 4)
|
||||
#define GSM0503_EGPRS_BURSTS_NBITS (348 * 4)
|
||||
|
||||
enum gsm0503_egprs_mcs {
|
||||
EGPRS_MCS0,
|
||||
EGPRS_MCS1,
|
||||
EGPRS_MCS2,
|
||||
EGPRS_MCS3,
|
||||
EGPRS_MCS4,
|
||||
EGPRS_MCS5,
|
||||
EGPRS_MCS6,
|
||||
EGPRS_MCS7,
|
||||
EGPRS_MCS8,
|
||||
EGPRS_MCS9,
|
||||
EGPRS_NUM_MCS,
|
||||
};
|
||||
|
||||
int gsm0503_xcch_encode(ubit_t *bursts, const uint8_t *l2_data);
|
||||
int gsm0503_xcch_decode(uint8_t *l2_data, const sbit_t *bursts,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_pdtch_encode(ubit_t *bursts, const uint8_t *l2_data, uint8_t l2_len);
|
||||
int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_pdtch_egprs_encode(ubit_t *bursts, const uint8_t *l2_data,
|
||||
uint8_t l2_len);
|
||||
int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, const sbit_t *bursts,
|
||||
uint16_t nbits, uint8_t *usf_p, int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_fr_encode(ubit_t *bursts, const uint8_t *tch_data, int len,
|
||||
int net_order);
|
||||
int gsm0503_tch_fr_decode(uint8_t *tch_data, const sbit_t *bursts, int net_order,
|
||||
int efr, int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_hr_encode(ubit_t *bursts, const uint8_t *tch_data, int len);
|
||||
int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd,
|
||||
int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
|
||||
uint8_t cmr);
|
||||
int gsm0503_tch_afs_decode(uint8_t *tch_data, const sbit_t *bursts,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
|
||||
uint8_t *cmr, int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr);
|
||||
int gsm0503_tch_ahs_decode(uint8_t *tch_data, const sbit_t *bursts, int odd,
|
||||
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
|
||||
uint8_t *cmr, int *n_errors, int *n_bits_total);
|
||||
|
||||
//int gsm0503_rach_ext_encode(ubit_t *burst, uint16_t ra, uint8_t bsic, bool is_11bit);
|
||||
//int gsm0503_rach_encode(ubit_t *burst, const uint8_t *ra, uint8_t bsic) OSMO_DEPRECATED("Use gsm0503_rach_ext_encode() instead");
|
||||
|
||||
//int gsm0503_rach_decode(uint8_t *ra, const sbit_t *burst, uint8_t bsic)
|
||||
// OSMO_DEPRECATED("Use gsm0503_rach_decode_ber() instead");
|
||||
//int gsm0503_rach_decode_ber(uint8_t *ra, const sbit_t *burst, uint8_t bsic,
|
||||
//int *n_errors, int *n_bits_total);
|
||||
//int gsm0503_rach_ext_decode(uint16_t *ra, const sbit_t *burst, uint8_t bsic)
|
||||
// OSMO_DEPRECATED("Use gsm0503_rach_ext_decode_ber() instead");
|
||||
//int gsm0503_rach_ext_decode_ber(uint16_t *ra, const sbit_t *burst, uint8_t bsic,
|
||||
// int *n_errors, int *n_bits_total);
|
||||
|
||||
int gsm0503_sch_encode(ubit_t *burst, const uint8_t *sb_info);
|
||||
int gsm0503_sch_decode(uint8_t *sb_info, const sbit_t *burst);
|
||||
|
||||
/*! @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,685 +0,0 @@
|
|||
/*
|
||||
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
|
||||
* (C) 2017 by Hrald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/coding/gsm0503_tables.h>
|
||||
#include <osmocom/coding/gsm0503_interleaving.h>
|
||||
|
||||
/*! \addtogroup interleaving
|
||||
* @{
|
||||
* GSM TS 05.03 interleaving
|
||||
*
|
||||
* This module contains interleaving / de-interleaving routines for
|
||||
* various channel types, as defined in 3GPP TS 05.03 / 45.003.
|
||||
*
|
||||
* GSM xCCH interleaving and burst mapping:
|
||||
*
|
||||
* Interleaving:
|
||||
*
|
||||
* Given 456 coded input bits, form 4 blocks of 114 bits:
|
||||
*
|
||||
* i(B, j) = c(n, k) k = 0, ..., 455
|
||||
* n = 0, ..., N, N + 1, ...
|
||||
* B = B_0 + 4n + (k mod 4)
|
||||
* j = 2(49k mod 57) + ((k mod 8) div 4)
|
||||
*
|
||||
* Mapping on Burst:
|
||||
*
|
||||
* e(B, j) = i(B, j)
|
||||
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
|
||||
* e(B, 57) = h_l(B)
|
||||
* e(B, 58) = h_n(B)
|
||||
*
|
||||
* Where hl(B) and hn(B) are bits in burst B indicating flags.
|
||||
*
|
||||
* GSM TCH HR/AHS interleaving and burst mapping:
|
||||
*
|
||||
* Interleaving:
|
||||
*
|
||||
* Given 288 coded input bits, form 4 blocks of 114 bits,
|
||||
* where even bits of the first 2 blocks and odd bits of the last 2 blocks
|
||||
* are used:
|
||||
*
|
||||
* i(B, j) = c(n, k) k = 0, ..., 227
|
||||
* n = 0, ..., N, N + 1, ...
|
||||
* B = B_0 + 2n + b
|
||||
* j, b = table[k];
|
||||
*
|
||||
* Mapping on Burst:
|
||||
*
|
||||
* e(B, j) = i(B, j)
|
||||
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
|
||||
* e(B, 57) = h_l(B)
|
||||
* e(B, 58) = h_n(B)
|
||||
*
|
||||
* Where hl(B) and hn(B) are bits in burst B indicating flags.
|
||||
*
|
||||
* \file gsm0503_interleaving.c */
|
||||
|
||||
/*! De-Interleave burst bits according to TS 05.03 4.1.4
|
||||
* \param[out] cB caller-allocated output buffer for 456 soft coded bits
|
||||
* \param[in] iB 456 soft input bits */
|
||||
void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 456; k++) {
|
||||
B = k & 3;
|
||||
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
|
||||
cB[k] = iB[B * 114 + j];
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave burst bits according to TS 05.03 4.1.4
|
||||
* \param[out] iB caller-allocated output buffer for 456 soft interleaved bits
|
||||
* \param[in] cB 456 soft input coded bits */
|
||||
void gsm0503_xcch_interleave(const ubit_t *cB, ubit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 456; k++) {
|
||||
B = k & 3;
|
||||
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
|
||||
iB[B * 114 + j] = cB[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.1.5
|
||||
* \param[out] u caller-allocated output buffer for 12 soft coded bits
|
||||
* \param[out] hc caller-allocated output buffer for 68 soft coded bits
|
||||
* \param[out] dc caller-allocated output buffer for 372 soft coded bits
|
||||
* \param[in] iB 452 interleaved soft input bits */
|
||||
void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
|
||||
sbit_t *dc, const sbit_t *iB)
|
||||
{
|
||||
int k;
|
||||
sbit_t c[452];
|
||||
sbit_t cp[456];
|
||||
|
||||
gsm0503_xcch_deinterleave(cp, iB);
|
||||
|
||||
for (k = 0; k < 25; k++)
|
||||
c[k] = cp[k];
|
||||
for (k = 26; k < 82; k++)
|
||||
c[k - 1] = cp[k];
|
||||
for (k = 83; k < 139; k++)
|
||||
c[k - 2] = cp[k];
|
||||
for (k = 140; k < 424; k++)
|
||||
c[k - 3] = cp[k];
|
||||
for (k = 425; k < 456; k++)
|
||||
c[k - 4] = cp[k];
|
||||
|
||||
if (u) {
|
||||
for (k = 0; k < 12; k++)
|
||||
u[k] = c[k];
|
||||
}
|
||||
|
||||
if (hc) {
|
||||
for (k = 12; k < 80; k++)
|
||||
hc[k - 12] = c[k];
|
||||
}
|
||||
|
||||
if (dc) {
|
||||
for (k = 80; k < 452; k++)
|
||||
dc[k - 80] = c[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.1.5
|
||||
* \param[in] up 12 input soft coded bits (usf)
|
||||
* \param[in] hc 68 input soft coded bits (header)
|
||||
* \param[in] dc 372 input soft bits (data)
|
||||
* \param[out] iB 456 interleaved soft output bits */
|
||||
void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
|
||||
const ubit_t *dc, ubit_t *iB)
|
||||
{
|
||||
int k;
|
||||
ubit_t c[452];
|
||||
ubit_t cp[456];
|
||||
|
||||
for (k = 0; k < 12; k++)
|
||||
c[k] = up[k];
|
||||
for (k = 12; k < 80; k++)
|
||||
c[k] = hc[k - 12];
|
||||
for (k = 80; k < 452; k++)
|
||||
c[k] = dc[k - 80];
|
||||
|
||||
for (k = 0; k < 25; k++)
|
||||
cp[k] = c[k];
|
||||
for (k = 26; k < 82; k++)
|
||||
cp[k] = c[k - 1];
|
||||
for (k = 83; k < 139; k++)
|
||||
cp[k] = c[k - 2];
|
||||
for (k = 140; k < 424; k++)
|
||||
cp[k] = c[k - 3];
|
||||
for (k = 425; k < 456; k++)
|
||||
cp[k] = c[k - 4];
|
||||
|
||||
cp[25] = 0;
|
||||
cp[82] = 0;
|
||||
cp[139] = 0;
|
||||
cp[424] = 0;
|
||||
|
||||
gsm0503_xcch_interleave(cp, iB);
|
||||
}
|
||||
|
||||
/*! Interleave MCS1 UL burst bits according to TS 05.03 5.1.5.2.4
|
||||
* \param[out] hc caller-allocated output buffer for 80 soft coded header bits
|
||||
* \param[out] dc caller-allocated output buffer for 372 soft coded data bits
|
||||
* \param[in] iB 456 interleaved soft input bits */
|
||||
void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB)
|
||||
{
|
||||
int k;
|
||||
sbit_t c[452];
|
||||
sbit_t cp[456];
|
||||
|
||||
gsm0503_xcch_deinterleave(cp, iB);
|
||||
|
||||
for (k = 0; k < 25; k++)
|
||||
c[k] = cp[k];
|
||||
for (k = 26; k < 82; k++)
|
||||
c[k - 1] = cp[k];
|
||||
for (k = 83; k < 139; k++)
|
||||
c[k - 2] = cp[k];
|
||||
for (k = 140; k < 424; k++)
|
||||
c[k - 3] = cp[k];
|
||||
for (k = 425; k < 456; k++)
|
||||
c[k - 4] = cp[k];
|
||||
|
||||
if (hc) {
|
||||
for (k = 0; k < 80; k++)
|
||||
hc[k] = c[k];
|
||||
}
|
||||
|
||||
if (dc) {
|
||||
for (k = 80; k < 452; k++)
|
||||
dc[k - 80] = c[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.2.4
|
||||
* \param[in] hc 80 input coded bits (header)
|
||||
* \param[in] dc 372 input bits (data)
|
||||
* \param[out] iB 456 interleaved output bits */
|
||||
void gsm0503_mcs1_ul_interleave(const ubit_t *hc, const ubit_t *dc, ubit_t *iB)
|
||||
{
|
||||
int k;
|
||||
ubit_t c[452];
|
||||
ubit_t cp[456];
|
||||
|
||||
for (k = 0; k < 80; k++)
|
||||
c[k] = hc[k];
|
||||
for (k = 80; k < 452; k++)
|
||||
c[k] = dc[k - 80];
|
||||
|
||||
for (k = 0; k < 25; k++)
|
||||
cp[k] = c[k];
|
||||
for (k = 26; k < 82; k++)
|
||||
cp[k] = c[k - 1];
|
||||
for (k = 83; k < 139; k++)
|
||||
cp[k] = c[k - 2];
|
||||
for (k = 140; k < 424; k++)
|
||||
cp[k] = c[k - 3];
|
||||
for (k = 425; k < 456; k++)
|
||||
cp[k] = c[k - 4];
|
||||
|
||||
cp[25] = 0;
|
||||
cp[82] = 0;
|
||||
cp[139] = 0;
|
||||
cp[424] = 0;
|
||||
|
||||
gsm0503_xcch_interleave(cp, iB);
|
||||
}
|
||||
|
||||
/*! Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.2.4
|
||||
* \param[in] hc 136 soft coded header input bits
|
||||
* \param[in] dc 1248 soft coded data input bits
|
||||
* \param[out] hi 136 interleaved header output bits
|
||||
* \param[out] di 1248 interleaved data output bits */
|
||||
void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
|
||||
ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 136; k++) {
|
||||
j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1248; k++) {
|
||||
j = gsm0503_interleave_mcs5[k];
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.2.4
|
||||
* \param[out] hc caller-allocated output buffer for 136 soft coded header bits
|
||||
* \param[out] dc caller-allocated output buffer for 1248 soft coded data bits
|
||||
* \param[in] iB interleaved soft input bits */
|
||||
void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 136; k++) {
|
||||
j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (dc) {
|
||||
for (k = 0; k < 1248; k++) {
|
||||
j = gsm0503_interleave_mcs5[k];
|
||||
dc[k] = di[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS5 DL burst bits according to TS 05.03 5.1.9.1.5
|
||||
* \param[in] hc 100 soft coded header input bits
|
||||
* \param[in] dc 1248 soft coded data input bits
|
||||
* \param[out] hi 100 interleaved header output bits
|
||||
* \param[out] di 1248 interleaved data output bits */
|
||||
void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
|
||||
ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 100; k++) {
|
||||
j = 25 * (k % 4) + ((17 * k) % 25);
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1248; k++) {
|
||||
j = gsm0503_interleave_mcs5[k];
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.1.5
|
||||
* \param[out] hc caller-allocated output buffer for 100 soft coded header bits
|
||||
* \param[out] dc caller-allocated output buffer for 1248 soft coded data bits
|
||||
* \param[in] iB interleaved soft input bits */
|
||||
void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 100; k++) {
|
||||
j = 25 * (k % 4) + ((17 * k) % 25);
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (dc) {
|
||||
for (k = 0; k < 1248; k++) {
|
||||
j = gsm0503_interleave_mcs5[k];
|
||||
dc[k] = di[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS7 DL burst bits according to TS 05.03 5.1.11.1.5
|
||||
* \param[in] hc 124 soft coded header input bits
|
||||
* \param[in] c1 612 soft coded data input bits
|
||||
* \param[in] c2 612 soft coded data input bits
|
||||
* \param[out] hi 124 interleaved header output bits
|
||||
* \param[out] di 1224 interleaved data output bits */
|
||||
void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 124; k++) {
|
||||
j = 31 * (k % 4) + ((17 * k) % 31);
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
memcpy(&dc[0], c1, 612);
|
||||
memcpy(&dc[612], c2, 612);
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
|
||||
(k + 2 - k / 408) % 3;
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS7 DL burst bits according to TS 05.03 5.1.11.1.5
|
||||
* \param[out] hc caller-allocated output buffer for 124 soft coded header bits
|
||||
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[in] hi interleaved soft input header bits
|
||||
* \param[in] di interleaved soft input data bits */
|
||||
void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 124; k++) {
|
||||
j = 31 * (k % 4) + ((17 * k) % 31);
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (c1 && c2) {
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
|
||||
(k + 2 - k / 408) % 3;
|
||||
dc[k] = di[j];
|
||||
}
|
||||
|
||||
memcpy(c1, &dc[0], 612);
|
||||
memcpy(c2, &dc[612], 612);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS7 UL burst bits according to TS 05.03 5.1.11.2.4
|
||||
* \param[in] hc 124 soft coded header input bits
|
||||
* \param[in] c1 612 soft coded data input bits
|
||||
* \param[in] c2 612 soft coded data input bits
|
||||
* \param[out] hi 124 interleaved header output bits
|
||||
* \param[out] di 1224 interleaved data output bits */
|
||||
void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 160; k++) {
|
||||
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
memcpy(&dc[0], c1, 612);
|
||||
memcpy(&dc[612], c2, 612);
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
|
||||
(k + 2 - k / 408) % 3;
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS7 UL burst bits according to TS 05.03 5.1.11.2.4
|
||||
* \param[out] hc caller-allocated output buffer for 160 soft coded header bits
|
||||
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[in] hi interleaved soft input header bits
|
||||
* \param[in] di interleaved soft input data bits */
|
||||
void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 160; k++) {
|
||||
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (c1 && c2) {
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
|
||||
(k + 2 - k / 408) % 3;
|
||||
dc[k] = di[j];
|
||||
}
|
||||
|
||||
memcpy(c1, &dc[0], 612);
|
||||
memcpy(c2, &dc[612], 612);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS8 UL burst bits according to TS 05.03 5.1.12.2.4
|
||||
* \param[in] hc 160 soft coded header input bits
|
||||
* \param[in] c1 612 soft coded data input bits
|
||||
* \param[in] c2 612 soft coded data input bits
|
||||
* \param[out] hi 160 interleaved header output bits
|
||||
* \param[out] di 1224 interleaved data output bits */
|
||||
void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 160; k++) {
|
||||
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
memcpy(&dc[0], c1, 612);
|
||||
memcpy(&dc[612], c2, 612);
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (2 * (k / 612) + (k % 2)) +
|
||||
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! De-Interleave MCS8 UL burst bits according to TS 05.03 5.1.12.2.4
|
||||
* \param[out] hc caller-allocated output buffer for 160 soft coded header bits
|
||||
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[in] hi interleaved soft input header bits
|
||||
* \param[in] di interleaved soft input data bits */
|
||||
void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 160; k++) {
|
||||
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (c1 && c2) {
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (2 * (k / 612) + (k % 2)) +
|
||||
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
|
||||
dc[k] = di[j];
|
||||
}
|
||||
|
||||
memcpy(c1, &dc[0], 612);
|
||||
memcpy(c2, &dc[612], 612);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Interleave MCS8 DL burst bits according to TS 05.03 5.1.12.1.5
|
||||
* \param[in] hc 124 soft coded header input bits
|
||||
* \param[in] c1 612 soft coded data input bits
|
||||
* \param[in] c2 612 soft coded data input bits
|
||||
* \param[out] hi 124 interleaved header output bits
|
||||
* \param[out] di 1224 interleaved data output bits */
|
||||
void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
for (k = 0; k < 124; k++) {
|
||||
j = 31 * (k % 4) + ((17 * k) % 31);
|
||||
hi[j] = hc[k];
|
||||
}
|
||||
|
||||
memcpy(&dc[0], c1, 612);
|
||||
memcpy(&dc[612], c2, 612);
|
||||
|
||||
/* Data */
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (2 * (k / 612) + (k % 2)) +
|
||||
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
|
||||
di[j] = dc[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! De-Interleave MCS8 DL burst bits according to TS 05.03 5.1.12.1.5
|
||||
* \param[out] hc caller-allocated output buffer for 124 soft coded header bits
|
||||
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
|
||||
* \param[in] hi interleaved soft input header bits
|
||||
* \param[in] di interleaved soft input data bits */
|
||||
void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di)
|
||||
{
|
||||
int j, k;
|
||||
ubit_t dc[1224];
|
||||
|
||||
/* Header */
|
||||
if (hc) {
|
||||
for (k = 0; k < 124; k++) {
|
||||
j = 31 * (k % 4) + ((17 * k) % 31);
|
||||
hc[k] = hi[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Data */
|
||||
if (c1 && c2) {
|
||||
for (k = 0; k < 1224; k++) {
|
||||
j = 306 * (2 * (k / 612) + (k % 2)) +
|
||||
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
|
||||
dc[k] = di[j];
|
||||
}
|
||||
|
||||
memcpy(c1, &dc[0], 612);
|
||||
memcpy(c2, &dc[612], 612);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GSM TCH FR/EFR/AFS interleaving and burst mapping
|
||||
*
|
||||
* Interleaving:
|
||||
*
|
||||
* Given 456 coded input bits, form 8 blocks of 114 bits,
|
||||
* where even bits of the first 4 blocks and odd bits of the last 4 blocks
|
||||
* are used:
|
||||
*
|
||||
* i(B, j) = c(n, k) k = 0, ..., 455
|
||||
* n = 0, ..., N, N + 1, ...
|
||||
* B = B_0 + 4n + (k mod 8)
|
||||
* j = 2(49k mod 57) + ((k mod 8) div 4)
|
||||
*
|
||||
* Mapping on Burst:
|
||||
*
|
||||
* e(B, j) = i(B, j)
|
||||
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
|
||||
* e(B, 57) = h_l(B)
|
||||
* e(B, 58) = h_n(B)
|
||||
*
|
||||
* Where hl(B) and hn(B) are bits in burst B indicating flags.
|
||||
*/
|
||||
|
||||
/*! GSM TCH FR/EFR/AFS De-Interleaving and burst mapping
|
||||
* \param[out] cB caller-allocated buffer for 456 unpacked output bits
|
||||
* \param[in] iB 456 unpacked interleaved input bits */
|
||||
void gsm0503_tch_fr_deinterleave(sbit_t *cB, const sbit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 456; k++) {
|
||||
B = k & 7;
|
||||
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
|
||||
cB[k] = iB[B * 114 + j];
|
||||
}
|
||||
}
|
||||
|
||||
/*! GSM TCH FR/EFR/AFS Interleaving and burst mapping
|
||||
* \param[in] cB caller-allocated buffer for 456 unpacked input bits
|
||||
* \param[out] iB 456 unpacked interleaved output bits */
|
||||
void gsm0503_tch_fr_interleave(const ubit_t *cB, ubit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 456; k++) {
|
||||
B = k & 7;
|
||||
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
|
||||
iB[B * 114 + j] = cB[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! GSM TCH HR/AHS De-Interleaving and burst mapping
|
||||
* \param[out] cB caller-allocated buffer for 228 unpacked output bits
|
||||
* \param[in] iB 228 unpacked interleaved input bits */
|
||||
void gsm0503_tch_hr_deinterleave(sbit_t *cB, const sbit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 228; k++) {
|
||||
B = gsm0503_tch_hr_interleaving[k][1];
|
||||
j = gsm0503_tch_hr_interleaving[k][0];
|
||||
cB[k] = iB[B * 114 + j];
|
||||
}
|
||||
}
|
||||
|
||||
/*! GSM TCH HR/AHS Interleaving and burst mapping
|
||||
* \param[in] cB caller-allocated buffer for 228 unpacked input bits
|
||||
* \param[out] iB 228 unpacked interleaved output bits */
|
||||
void gsm0503_tch_hr_interleave(const ubit_t *cB, ubit_t *iB)
|
||||
{
|
||||
int j, k, B;
|
||||
|
||||
for (k = 0; k < 228; k++) {
|
||||
B = gsm0503_tch_hr_interleaving[k][1];
|
||||
j = gsm0503_tch_hr_interleaving[k][0];
|
||||
iB[B * 114 + j] = cB[k];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,61 +0,0 @@
|
|||
/*! \file gsm0503_interleaving.h
|
||||
* GSM TS 05.03 interleaving.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
/*! \addtogroup interleaving
|
||||
* @{
|
||||
* \file gsm0503_interleaving.h */
|
||||
|
||||
void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB);
|
||||
void gsm0503_xcch_interleave(const ubit_t *cB, ubit_t *iB);
|
||||
|
||||
void gsm0503_tch_fr_deinterleave(sbit_t *cB, const sbit_t *iB);
|
||||
void gsm0503_tch_fr_interleave(const ubit_t *cB, ubit_t *iB);
|
||||
|
||||
void gsm0503_tch_hr_deinterleave(sbit_t *cB, const sbit_t *iB);
|
||||
void gsm0503_tch_hr_interleave(const ubit_t *cB, ubit_t *iB);
|
||||
|
||||
void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB);
|
||||
void gsm0503_mcs1_ul_interleave(const ubit_t *hc,
|
||||
const ubit_t *dc, ubit_t *iB);
|
||||
|
||||
void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
|
||||
sbit_t *dc, const sbit_t *iB);
|
||||
void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
|
||||
const ubit_t *dc, ubit_t *iB);
|
||||
|
||||
void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
|
||||
ubit_t *hi, ubit_t *di);
|
||||
|
||||
void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
|
||||
ubit_t *hi, ubit_t *di);
|
||||
|
||||
void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di);
|
||||
|
||||
void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di);
|
||||
|
||||
void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di);
|
||||
|
||||
void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
|
||||
const sbit_t *hi, const sbit_t *di);
|
||||
void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
|
||||
const ubit_t *c2, ubit_t *hi, ubit_t *di);
|
||||
|
||||
/*! @} */
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/coding/gsm0503_mapping.h>
|
||||
|
||||
/*! \addtogroup mapping
|
||||
* @{
|
||||
*
|
||||
* GSM TS 05.03 burst mapping
|
||||
*
|
||||
* This module contains burst mapping routines as specified in 3GPP TS
|
||||
* 05.03 / 45.003.
|
||||
*
|
||||
* \file gsm0503_mapping.c */
|
||||
|
||||
void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
|
||||
sbit_t *hl, sbit_t *hn)
|
||||
{
|
||||
memcpy(iB, eB, 57);
|
||||
memcpy(iB + 57, eB + 59, 57);
|
||||
|
||||
if (hl)
|
||||
*hl = eB[57];
|
||||
|
||||
if (hn)
|
||||
*hn = eB[58];
|
||||
}
|
||||
|
||||
void gsm0503_xcch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *hl,
|
||||
const ubit_t *hn)
|
||||
{
|
||||
memcpy(eB, iB, 57);
|
||||
memcpy(eB + 59, iB + 57, 57);
|
||||
|
||||
if (hl)
|
||||
eB[57] = *hl;
|
||||
if (hn)
|
||||
eB[58] = *hn;
|
||||
}
|
||||
|
||||
void gsm0503_tch_burst_unmap(sbit_t *iB, const sbit_t *eB, sbit_t *h, int odd)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* brainfuck: only copy even or odd bits */
|
||||
if (iB) {
|
||||
for (i = odd; i < 57; i += 2)
|
||||
iB[i] = eB[i];
|
||||
for (i = 58 - odd; i < 114; i += 2)
|
||||
iB[i] = eB[i + 2];
|
||||
}
|
||||
|
||||
if (h) {
|
||||
if (!odd)
|
||||
*h = eB[58];
|
||||
else
|
||||
*h = eB[57];
|
||||
}
|
||||
}
|
||||
|
||||
void gsm0503_tch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* brainfuck: only copy even or odd bits */
|
||||
if (eB) {
|
||||
for (i = odd; i < 57; i += 2)
|
||||
eB[i] = iB[i];
|
||||
for (i = 58 - odd; i < 114; i += 2)
|
||||
eB[i + 2] = iB[i];
|
||||
if (h)
|
||||
eB[odd ? 57 : 58] = *h;
|
||||
}
|
||||
}
|
||||
|
||||
void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, const ubit_t *up, int B)
|
||||
{
|
||||
int j;
|
||||
int q[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
|
||||
|
||||
for (j = 0; j < 156; j++)
|
||||
eB[j] = di[312 * B + j];
|
||||
for (j = 156; j < 168; j++)
|
||||
eB[j] = hi[25 * B + j - 156];
|
||||
for (j = 168; j < 174; j++)
|
||||
eB[j] = up[9 * B + j - 168];
|
||||
for (j = 174; j < 176; j++)
|
||||
eB[j] = q[2 * B + j - 174];
|
||||
for (j = 176; j < 179; j++)
|
||||
eB[j] = up[9 * B + j - 170];
|
||||
for (j = 179; j < 192; j++)
|
||||
eB[j] = hi[25 * B + j - 167];
|
||||
for (j = 192; j < 348; j++)
|
||||
eB[j] = di[312 * B + j - 36];
|
||||
}
|
||||
|
||||
void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, sbit_t *up, int B)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 156; j++)
|
||||
di[312 * B + j] = eB[j];
|
||||
for (j = 156; j < 168; j++)
|
||||
hi[25 * B + j - 156] = eB[j];
|
||||
for (j = 168; j < 174; j++)
|
||||
up[9 * B + j - 168] = eB[j];
|
||||
|
||||
for (j = 176; j < 179; j++)
|
||||
up[9 * B + j - 170] = eB[j];
|
||||
for (j = 179; j < 192; j++)
|
||||
hi[25 * B + j - 167] = eB[j];
|
||||
for (j = 192; j < 348; j++)
|
||||
di[312 * B + j - 36] = eB[j];
|
||||
}
|
||||
|
||||
void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, int B)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 156; j++)
|
||||
eB[j] = di[312 * B + j];
|
||||
for (j = 156; j < 174; j++)
|
||||
eB[j] = hi[34 * B + j - 156];
|
||||
for (j = 174; j < 176; j++)
|
||||
eB[j] = 0;
|
||||
for (j = 176; j < 192; j++)
|
||||
eB[j] = hi[34 * B + j - 158];
|
||||
for (j = 192; j < 348; j++)
|
||||
eB[j] = di[312 * B + j - 36];
|
||||
}
|
||||
|
||||
void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, int B)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 156; j++)
|
||||
di[312 * B + j] = eB[j];
|
||||
for (j = 156; j < 174; j++)
|
||||
hi[34 * B + j - 156] = eB[j];
|
||||
for (j = 176; j < 192; j++)
|
||||
hi[34 * B + j - 158] = eB[j];
|
||||
for (j = 192; j < 348; j++)
|
||||
di[312 * B + j - 36] = eB[j];
|
||||
}
|
||||
|
||||
void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, const ubit_t *up, int B)
|
||||
{
|
||||
int j;
|
||||
int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
|
||||
|
||||
for (j = 0; j < 153; j++)
|
||||
eB[j] = di[306 * B + j];
|
||||
for (j = 153; j < 168; j++)
|
||||
eB[j] = hi[31 * B + j - 153];
|
||||
for (j = 168; j < 174; j++)
|
||||
eB[j] = up[9 * B + j - 168];
|
||||
for (j = 174; j < 176; j++)
|
||||
eB[j] = q[2 * B + j - 174];
|
||||
for (j = 176; j < 179; j++)
|
||||
eB[j] = up[9 * B + j - 170];
|
||||
for (j = 179; j < 195; j++)
|
||||
eB[j] = hi[31 * B + j - 164];
|
||||
for (j = 195; j < 348; j++)
|
||||
eB[j] = di[306 * B + j - 42];
|
||||
}
|
||||
|
||||
void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, sbit_t *up, int B)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 153; j++)
|
||||
di[306 * B + j] = eB[j];
|
||||
for (j = 153; j < 168; j++)
|
||||
hi[31 * B + j - 153] = eB[j];
|
||||
for (j = 168; j < 174; j++)
|
||||
up[9 * B + j - 168] = eB[j];
|
||||
|
||||
for (j = 176; j < 179; j++)
|
||||
up[9 * B + j - 170] = eB[j];
|
||||
for (j = 179; j < 195; j++)
|
||||
hi[31 * B + j - 164] = eB[j];
|
||||
for (j = 195; j < 348; j++)
|
||||
di[306 * B + j - 42] = eB[j];
|
||||
}
|
||||
|
||||
void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, int B)
|
||||
{
|
||||
int j;
|
||||
int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
|
||||
|
||||
for (j = 0; j < 153; j++)
|
||||
eB[j] = di[306 * B + j];
|
||||
for (j = 153; j < 174; j++)
|
||||
eB[j] = hi[40 * B + j - 153];
|
||||
for (j = 174; j < 176; j++)
|
||||
eB[j] = q[2 * B + j - 174];
|
||||
for (j = 176; j < 195; j++)
|
||||
eB[j] = hi[40 * B + j - 155];
|
||||
for (j = 195; j < 348; j++)
|
||||
eB[j] = di[306 * B + j - 42];
|
||||
}
|
||||
|
||||
void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, int B)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 153; j++)
|
||||
di[306 * B + j] = eB[j];
|
||||
for (j = 153; j < 174; j++)
|
||||
hi[40 * B + j - 153] = eB[j];
|
||||
|
||||
for (j = 176; j < 195; j++)
|
||||
hi[40 * B + j - 155] = eB[j];
|
||||
for (j = 195; j < 348; j++)
|
||||
di[306 * B + j - 42] = eB[j];
|
||||
}
|
||||
|
||||
void gsm0503_mcs5_burst_swap(sbit_t *eB)
|
||||
{
|
||||
sbit_t t[14];
|
||||
|
||||
t[0] = eB[155];
|
||||
t[1] = eB[158];
|
||||
t[2] = eB[161];
|
||||
t[3] = eB[164];
|
||||
t[4] = eB[167];
|
||||
t[5] = eB[170];
|
||||
t[6] = eB[173];
|
||||
t[7] = eB[195];
|
||||
t[8] = eB[196];
|
||||
t[9] = eB[198];
|
||||
t[10] = eB[199];
|
||||
t[11] = eB[201];
|
||||
t[12] = eB[202];
|
||||
t[13] = eB[204];
|
||||
|
||||
eB[155] = eB[142];
|
||||
eB[158] = eB[144];
|
||||
eB[161] = eB[145];
|
||||
eB[164] = eB[147];
|
||||
eB[167] = eB[148];
|
||||
eB[170] = eB[150];
|
||||
eB[173] = eB[151];
|
||||
eB[195] = eB[176];
|
||||
eB[196] = eB[179];
|
||||
eB[198] = eB[182];
|
||||
eB[199] = eB[185];
|
||||
eB[201] = eB[188];
|
||||
eB[202] = eB[191];
|
||||
eB[204] = eB[194];
|
||||
|
||||
eB[142] = t[0];
|
||||
eB[144] = t[1];
|
||||
eB[145] = t[2];
|
||||
eB[147] = t[3];
|
||||
eB[148] = t[4];
|
||||
eB[150] = t[5];
|
||||
eB[151] = t[6];
|
||||
eB[176] = t[7];
|
||||
eB[179] = t[8];
|
||||
eB[182] = t[9];
|
||||
eB[185] = t[10];
|
||||
eB[188] = t[11];
|
||||
eB[191] = t[12];
|
||||
eB[194] = t[13];
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,44 +0,0 @@
|
|||
/*! \file gsm0503_mapping.c
|
||||
* GSM TS 05.03 burst mapping.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
//#include "bits.h"
|
||||
|
||||
/*! \addtogroup mapping
|
||||
* @{
|
||||
* \file gsm0503_mapping.h */
|
||||
|
||||
void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
|
||||
sbit_t *hl, sbit_t *hn);
|
||||
void gsm0503_xcch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *hl,
|
||||
const ubit_t *hn);
|
||||
|
||||
void gsm0503_tch_burst_unmap(sbit_t *iB, const sbit_t *eB, sbit_t *h, int odd);
|
||||
void gsm0503_tch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd);
|
||||
|
||||
void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, int B);
|
||||
void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, int B);
|
||||
|
||||
void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, int B);
|
||||
void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, int B);
|
||||
|
||||
void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, const ubit_t *up, int B);
|
||||
void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, sbit_t *up, int B);
|
||||
|
||||
void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
|
||||
const ubit_t *hi, const ubit_t *up, int B);
|
||||
void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
|
||||
sbit_t *hi, sbit_t *up, int B);
|
||||
|
||||
void gsm0503_mcs5_burst_swap(sbit_t *eB);
|
||||
|
||||
/*! @} */
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/crcgen.h>
|
||||
#include <osmocom/coding/gsm0503_parity.h>
|
||||
|
||||
/*! \addtogroup parity
|
||||
* @{
|
||||
*
|
||||
* GSM TS 05.03 parity
|
||||
*
|
||||
* This module contains parity/crc code definitions for the various
|
||||
* parity/crc schemes as defined in 3GPP TS 05.03 / 45.003
|
||||
*
|
||||
* \file gsm0503_parity.c */
|
||||
|
||||
/*! GSM (SACCH) parity (FIRE code)
|
||||
*
|
||||
* g(x) = (x^23 + 1)(x^17 + x^3 + 1)
|
||||
* = x^40 + x^26 + x^23 + x^17 + x^3 + a1
|
||||
*/
|
||||
const struct osmo_crc64gen_code gsm0503_fire_crc40 = {
|
||||
.bits = 40,
|
||||
.poly = 0x0004820009ULL,
|
||||
.init = 0x0000000000ULL,
|
||||
.remainder = 0xffffffffffULL,
|
||||
};
|
||||
|
||||
/*! GSM PDTCH CS-2, CS-3, CS-4 parity
|
||||
*
|
||||
* g(x) = x^16 + x^12 + x^5 + 1
|
||||
*/
|
||||
const struct osmo_crc16gen_code gsm0503_cs234_crc16 = {
|
||||
.bits = 16,
|
||||
.poly = 0x1021,
|
||||
.init = 0x0000,
|
||||
.remainder = 0xffff,
|
||||
};
|
||||
|
||||
/*! EDGE MCS header parity
|
||||
*
|
||||
*/
|
||||
const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr = {
|
||||
.bits = 8,
|
||||
.poly = 0x49,
|
||||
.init = 0x00,
|
||||
.remainder = 0xff,
|
||||
};
|
||||
|
||||
/*! EDGE MCS data parity
|
||||
*
|
||||
*/
|
||||
const struct osmo_crc16gen_code gsm0503_mcs_crc12 = {
|
||||
.bits = 12,
|
||||
.poly = 0x0d31,
|
||||
.init = 0x0000,
|
||||
.remainder = 0x0fff,
|
||||
};
|
||||
|
||||
/*! GSM RACH parity
|
||||
*
|
||||
* g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
|
||||
*/
|
||||
const struct osmo_crc8gen_code gsm0503_rach_crc6 = {
|
||||
.bits = 6,
|
||||
.poly = 0x2f,
|
||||
.init = 0x00,
|
||||
.remainder = 0x3f,
|
||||
};
|
||||
|
||||
/*! GSM SCH parity
|
||||
*
|
||||
* g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
|
||||
*/
|
||||
const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
|
||||
.bits = 10,
|
||||
.poly = 0x175,
|
||||
.init = 0x000,
|
||||
.remainder = 0x3ff,
|
||||
};
|
||||
|
||||
/*! GSM TCH FR/HR/EFR parity
|
||||
*
|
||||
* g(x) = x^3 + x + 1
|
||||
*/
|
||||
const struct osmo_crc8gen_code gsm0503_tch_fr_crc3 = {
|
||||
.bits = 3,
|
||||
.poly = 0x3,
|
||||
.init = 0x0,
|
||||
.remainder = 0x7,
|
||||
};
|
||||
|
||||
/*! GSM TCH EFR parity
|
||||
*
|
||||
* g(x) = x^8 + x^4 + x^3 + x^2 + 1
|
||||
*/
|
||||
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8 = {
|
||||
.bits = 8,
|
||||
.poly = 0x1d,
|
||||
.init = 0x00,
|
||||
.remainder = 0x00,
|
||||
};
|
||||
|
||||
/*! GSM AMR parity
|
||||
*
|
||||
* g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
|
||||
*/
|
||||
const struct osmo_crc8gen_code gsm0503_amr_crc6 = {
|
||||
.bits = 6,
|
||||
.poly = 0x2f,
|
||||
.init = 0x00,
|
||||
.remainder = 0x3f,
|
||||
};
|
||||
|
||||
/*! @} */
|
|
@ -1,23 +0,0 @@
|
|||
/*! \file gsm0503_parity.h
|
||||
* GSM TS 05.03 parity.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/crcgen.h>
|
||||
|
||||
/*! \addtogroup parity
|
||||
* @{
|
||||
* \file gsm0503_parity.h */
|
||||
|
||||
const struct osmo_crc64gen_code gsm0503_fire_crc40;
|
||||
const struct osmo_crc16gen_code gsm0503_cs234_crc16;
|
||||
const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr;
|
||||
const struct osmo_crc16gen_code gsm0503_mcs_crc12;
|
||||
const struct osmo_crc8gen_code gsm0503_rach_crc6;
|
||||
const struct osmo_crc16gen_code gsm0503_sch_crc10;
|
||||
const struct osmo_crc8gen_code gsm0503_tch_fr_crc3;
|
||||
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8;
|
||||
const struct osmo_crc8gen_code gsm0503_amr_crc6;
|
||||
|
||||
/*! @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,61 +0,0 @@
|
|||
/*! \file gsm0503_tables.h
|
||||
* GSM TS 05.03 tables.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
//#include "bits.h"
|
||||
|
||||
/*! \addtogroup tables
|
||||
* @{
|
||||
* \file gsm0503_tables.h */
|
||||
|
||||
extern const ubit_t gsm0503_pdtch_hl_hn_ubit[4][8];
|
||||
extern const ubit_t gsm0503_pdtch_edge_hl_hn_ubit[3][8];
|
||||
extern const sbit_t gsm0503_pdtch_hl_hn_sbit[4][8];
|
||||
extern const sbit_t gsm0503_pdtch_edge_hl_hn_sbit[3][8];
|
||||
extern const ubit_t gsm0503_usf2six[8][6];
|
||||
extern const ubit_t gsm0503_usf2twelve_ubit[8][12];
|
||||
extern const sbit_t gsm0503_usf2twelve_sbit[8][12];
|
||||
extern const uint8_t gsm0503_puncture_cs2[588];
|
||||
extern const uint8_t gsm0503_puncture_cs3[676];
|
||||
extern const uint8_t gsm0503_puncture_mcs1_dl_hdr[108];
|
||||
extern const uint8_t gsm0503_puncture_mcs1_ul_hdr[117];
|
||||
extern const uint8_t gsm0503_puncture_mcs1_p1[588];
|
||||
extern const uint8_t gsm0503_puncture_mcs1_p2[588];
|
||||
extern const uint8_t gsm0503_puncture_mcs2_p1[732];
|
||||
extern const uint8_t gsm0503_puncture_mcs2_p2[732];
|
||||
extern const uint8_t gsm0503_puncture_mcs3_p1[948];
|
||||
extern const uint8_t gsm0503_puncture_mcs3_p2[948];
|
||||
extern const uint8_t gsm0503_puncture_mcs3_p3[948];
|
||||
extern const uint8_t gsm0503_puncture_mcs4_p1[1116];
|
||||
extern const uint8_t gsm0503_puncture_mcs4_p2[1116];
|
||||
extern const uint8_t gsm0503_puncture_mcs4_p3[1116];
|
||||
extern const uint8_t gsm0503_puncture_mcs5_p1[1404];
|
||||
extern const uint8_t gsm0503_puncture_mcs5_p2[1404];
|
||||
extern const uint8_t gsm0503_puncture_mcs6_p1[1836];
|
||||
extern const uint8_t gsm0503_puncture_mcs6_p2[1836];
|
||||
extern const uint8_t gsm0503_puncture_mcs7_dl_hdr[135];
|
||||
extern const uint8_t gsm0503_puncture_mcs7_ul_hdr[162];
|
||||
extern const uint8_t gsm0503_puncture_mcs7_p1[1404];
|
||||
extern const uint8_t gsm0503_puncture_mcs7_p2[1404];
|
||||
extern const uint8_t gsm0503_puncture_mcs7_p3[1404];
|
||||
extern const uint8_t gsm0503_puncture_mcs8_p1[1692];
|
||||
extern const uint8_t gsm0503_puncture_mcs8_p2[1692];
|
||||
extern const uint8_t gsm0503_puncture_mcs8_p3[1692];
|
||||
extern const uint8_t gsm0503_puncture_mcs9_p1[1836];
|
||||
extern const uint8_t gsm0503_puncture_mcs9_p2[1836];
|
||||
extern const uint8_t gsm0503_puncture_mcs9_p3[1836];
|
||||
extern const uint16_t gsm0503_interleave_mcs5[1248];
|
||||
extern const uint8_t gsm0503_gsm_fr_map[76];
|
||||
extern const uint8_t gsm0503_gsm_efr_protected_bits[65];
|
||||
extern const ubit_t gsm0503_afs_ic_ubit[4][8];
|
||||
extern const sbit_t gsm0503_afs_ic_sbit[4][8];
|
||||
extern const ubit_t gsm0503_ahs_ic_ubit[4][4];
|
||||
extern const sbit_t gsm0503_ahs_ic_sbit[4][4];
|
||||
extern const uint8_t gsm0503_tch_hr_interleaving[228][2];
|
||||
extern const ubit_t gsm0503_mcs5_usf_precode_table[8][36];
|
||||
|
||||
/*! @} */
|
|
@ -1,11 +0,0 @@
|
|||
add_sources(
|
||||
bits.c
|
||||
bitvec.c
|
||||
conv_acc.c
|
||||
conv_acc_generic.c
|
||||
conv.c
|
||||
crc16gen.c
|
||||
crc64gen.c
|
||||
crc8gen.c
|
||||
panic.c
|
||||
)
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* bit16gen.h
|
||||
*
|
||||
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint16_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 16 bit unsigned integer
|
||||
*/
|
||||
static inline uint16_t osmo_load16le_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint16_t)q[i] << (8 * i)), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint16_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 16 bit unsigned integer
|
||||
*/
|
||||
static inline uint16_t osmo_load16be_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint16_t)q[i] << (16 - 8* (1 + i))), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint16_t
|
||||
* \param[in] x unsigned 16 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store16le_ext(uint16_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint16_t
|
||||
* \param[in] x unsigned 16 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store16be_ext(uint16_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
|
||||
}
|
||||
|
||||
|
||||
/* Convenience function for most-used cases */
|
||||
|
||||
|
||||
/*! \brief load unaligned 16-bit integer (little-endian encoding) */
|
||||
static inline uint16_t osmo_load16le(const void *p)
|
||||
{
|
||||
return osmo_load16le_ext(p, 16 / 8);
|
||||
}
|
||||
|
||||
/*! \brief load unaligned 16-bit integer (big-endian encoding) */
|
||||
static inline uint16_t osmo_load16be(const void *p)
|
||||
{
|
||||
return osmo_load16be_ext(p, 16 / 8);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned 16-bit integer (little-endian encoding) */
|
||||
static inline void osmo_store16le(uint16_t x, void *p)
|
||||
{
|
||||
osmo_store16le_ext(x, p, 16 / 8);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned 16-bit integer (big-endian encoding) */
|
||||
static inline void osmo_store16be(uint16_t x, void *p)
|
||||
{
|
||||
osmo_store16be_ext(x, p, 16 / 8);
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* bit32gen.h
|
||||
*
|
||||
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint32_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 32 bit unsigned integer
|
||||
*/
|
||||
static inline uint32_t osmo_load32le_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint32_t)q[i] << (8 * i)), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint32_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 32 bit unsigned integer
|
||||
*/
|
||||
static inline uint32_t osmo_load32be_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint32_t)q[i] << (32 - 8* (1 + i))), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint32_t
|
||||
* \param[in] x unsigned 32 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store32le_ext(uint32_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint32_t
|
||||
* \param[in] x unsigned 32 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store32be_ext(uint32_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
|
||||
}
|
||||
|
||||
|
||||
/* Convenience function for most-used cases */
|
||||
|
||||
|
||||
/*! \brief load unaligned 32-bit integer (little-endian encoding) */
|
||||
static inline uint32_t osmo_load32le(const void *p)
|
||||
{
|
||||
return osmo_load32le_ext(p, 32 / 8);
|
||||
}
|
||||
|
||||
/*! \brief load unaligned 32-bit integer (big-endian encoding) */
|
||||
static inline uint32_t osmo_load32be(const void *p)
|
||||
{
|
||||
return osmo_load32be_ext(p, 32 / 8);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned 32-bit integer (little-endian encoding) */
|
||||
static inline void osmo_store32le(uint32_t x, void *p)
|
||||
{
|
||||
osmo_store32le_ext(x, p, 32 / 8);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned 32-bit integer (big-endian encoding) */
|
||||
static inline void osmo_store32be(uint32_t x, void *p)
|
||||
{
|
||||
osmo_store32be_ext(x, p, 32 / 8);
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* bit64gen.h
|
||||
*
|
||||
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint64_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 64 bit unsigned integer
|
||||
*/
|
||||
static inline uint64_t osmo_load64le_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint64_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint64_t)q[i] << (8 * i)), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint64_t
|
||||
* \param[in] p Buffer where integer is stored
|
||||
* \param[in] n Number of bytes stored in p
|
||||
* \returns 64 bit unsigned integer
|
||||
*/
|
||||
static inline uint64_t osmo_load64be_ext(const void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint64_t r = 0;
|
||||
const uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; r |= ((uint64_t)q[i] << (64 - 8* (1 + i))), i++);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint64_t
|
||||
* \param[in] x unsigned 64 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store64le_ext(uint64_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint64_t
|
||||
* \param[in] x unsigned 64 bit integer
|
||||
* \param[out] p Buffer to store integer
|
||||
* \param[in] n Number of bytes to store
|
||||
*/
|
||||
static inline void osmo_store64be_ext(uint64_t x, void *p, uint8_t n)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t *q = (uint8_t *)p;
|
||||
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
|
||||
}
|
||||
|
||||
|
||||
/* Convenience function for most-used cases */
|
||||
|
||||
|
||||
/*! \brief load unaligned 64-bit integer (little-endian encoding) */
|
||||
static inline uint64_t osmo_load64le(const void *p)
|
||||
{
|
||||
return osmo_load64le_ext(p, 64 / 8);
|
||||
}
|
||||
|
||||
/*! \brief load unaligned 64-bit integer (big-endian encoding) */
|
||||
static inline uint64_t osmo_load64be(const void *p)
|
||||
{
|
||||
return osmo_load64be_ext(p, 64 / 8);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief store unaligned 64-bit integer (little-endian encoding) */
|
||||
static inline void osmo_store64le(uint64_t x, void *p)
|
||||
{
|
||||
osmo_store64le_ext(x, p, 64 / 8);
|
||||
}
|
||||
|
||||
/*! \brief store unaligned 64-bit integer (big-endian encoding) */
|
||||
static inline void osmo_store64be(uint64_t x, void *p)
|
||||
{
|
||||
osmo_store64be_ext(x, p, 64 / 8);
|
||||
}
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2011 by Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
/*! \addtogroup bits
|
||||
* @{
|
||||
* Osmocom bit level support code.
|
||||
*
|
||||
* This module implements the notion of different bit-fields, such as
|
||||
* - unpacked bits (\ref ubit_t), i.e. 1 bit per byte
|
||||
* - packed bits (\ref pbit_t), i.e. 8 bits per byte
|
||||
* - soft bits (\ref sbit_t), 1 bit per byte from -127 to 127
|
||||
*
|
||||
* \file bits.c */
|
||||
|
||||
/*! convert unpacked bits to packed bits, return length in bytes
|
||||
* \param[out] out output buffer of packed bits
|
||||
* \param[in] in input buffer of unpacked bits
|
||||
* \param[in] num_bits number of bits
|
||||
*/
|
||||
int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t curbyte = 0;
|
||||
pbit_t *outptr = out;
|
||||
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
uint8_t bitnum = 7 - (i % 8);
|
||||
|
||||
curbyte |= (in[i] << bitnum);
|
||||
|
||||
if(i % 8 == 7){
|
||||
*outptr++ = curbyte;
|
||||
curbyte = 0;
|
||||
}
|
||||
}
|
||||
/* we have a non-modulo-8 bitcount */
|
||||
if (i % 8)
|
||||
*outptr++ = curbyte;
|
||||
|
||||
return outptr - out;
|
||||
}
|
||||
|
||||
/*! Shift unaligned input to octet-aligned output
|
||||
* \param[out] out output buffer, unaligned
|
||||
* \param[in] in input buffer, octet-aligned
|
||||
* \param[in] num_nibbles number of nibbles
|
||||
*/
|
||||
void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
|
||||
unsigned int num_nibbles)
|
||||
{
|
||||
unsigned int i, num_whole_bytes = num_nibbles / 2;
|
||||
if (!num_whole_bytes)
|
||||
return;
|
||||
|
||||
/* first byte: upper nibble empty, lower nibble from src */
|
||||
out[0] = (in[0] >> 4);
|
||||
|
||||
/* bytes 1.. */
|
||||
for (i = 1; i < num_whole_bytes; i++)
|
||||
out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
|
||||
|
||||
/* shift the last nibble, in case there's an odd count */
|
||||
i = num_whole_bytes;
|
||||
if (num_nibbles & 1)
|
||||
out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
|
||||
else
|
||||
out[i] = (in[i - 1] & 0xF) << 4;
|
||||
}
|
||||
|
||||
/*! Shift unaligned input to octet-aligned output
|
||||
* \param[out] out output buffer, octet-aligned
|
||||
* \param[in] in input buffer, unaligned
|
||||
* \param[in] num_nibbles number of nibbles
|
||||
*/
|
||||
void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
|
||||
unsigned int num_nibbles)
|
||||
{
|
||||
unsigned int i, num_whole_bytes = num_nibbles / 2;
|
||||
if (!num_whole_bytes)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_whole_bytes; i++)
|
||||
out[i] = ((in[i] & 0xF) << 4) | (in[i + 1] >> 4);
|
||||
|
||||
/* shift the last nibble, in case there's an odd count */
|
||||
i = num_whole_bytes;
|
||||
if (num_nibbles & 1)
|
||||
out[i] = (in[i] & 0xF) << 4;
|
||||
}
|
||||
|
||||
/*! convert unpacked bits to soft bits
|
||||
* \param[out] out output buffer of soft bits
|
||||
* \param[in] in input buffer of unpacked bits
|
||||
* \param[in] num_bits number of bits
|
||||
*/
|
||||
void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < num_bits; i++)
|
||||
out[i] = in[i] ? -127 : 127;
|
||||
}
|
||||
|
||||
/*! convert soft bits to unpacked bits
|
||||
* \param[out] out output buffer of unpacked bits
|
||||
* \param[in] in input buffer of soft bits
|
||||
* \param[in] num_bits number of bits
|
||||
*/
|
||||
void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < num_bits; i++)
|
||||
out[i] = in[i] < 0;
|
||||
}
|
||||
|
||||
/*! convert packed bits to unpacked bits, return length in bytes
|
||||
* \param[out] out output buffer of unpacked bits
|
||||
* \param[in] in input buffer of packed bits
|
||||
* \param[in] num_bits number of bits
|
||||
* \return number of bytes used in \ref out
|
||||
*/
|
||||
int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits)
|
||||
{
|
||||
unsigned int i;
|
||||
ubit_t *cur = out;
|
||||
ubit_t *limit = out + num_bits;
|
||||
|
||||
for (i = 0; i < (num_bits/8)+1; i++) {
|
||||
pbit_t byte = in[i];
|
||||
*cur++ = (byte >> 7) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 6) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 5) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 4) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 3) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 2) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 1) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
*cur++ = (byte >> 0) & 1;
|
||||
if (cur >= limit)
|
||||
break;
|
||||
}
|
||||
return cur - out;
|
||||
}
|
||||
|
||||
/*! convert unpacked bits to packed bits (extended options)
|
||||
* \param[out] out output buffer of packed bits
|
||||
* \param[in] out_ofs offset into output buffer
|
||||
* \param[in] in input buffer of unpacked bits
|
||||
* \param[in] in_ofs offset into input buffer
|
||||
* \param[in] num_bits number of bits
|
||||
* \param[in] lsb_mode Encode bits in LSB orde instead of MSB
|
||||
* \returns length in bytes (max written offset of output buffer + 1)
|
||||
*/
|
||||
int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
|
||||
const ubit_t *in, unsigned int in_ofs,
|
||||
unsigned int num_bits, int lsb_mode)
|
||||
{
|
||||
int i, op, bn;
|
||||
for (i=0; i<num_bits; i++) {
|
||||
op = out_ofs + i;
|
||||
bn = lsb_mode ? (op&7) : (7-(op&7));
|
||||
if (in[in_ofs+i])
|
||||
out[op>>3] |= 1 << bn;
|
||||
else
|
||||
out[op>>3] &= ~(1 << bn);
|
||||
}
|
||||
return ((out_ofs + num_bits - 1) >> 3) + 1;
|
||||
}
|
||||
|
||||
/*! convert packed bits to unpacked bits (extended options)
|
||||
* \param[out] out output buffer of unpacked bits
|
||||
* \param[in] out_ofs offset into output buffer
|
||||
* \param[in] in input buffer of packed bits
|
||||
* \param[in] in_ofs offset into input buffer
|
||||
* \param[in] num_bits number of bits
|
||||
* \param[in] lsb_mode Encode bits in LSB orde instead of MSB
|
||||
* \returns length in bytes (max written offset of output buffer + 1)
|
||||
*/
|
||||
int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
|
||||
const pbit_t *in, unsigned int in_ofs,
|
||||
unsigned int num_bits, int lsb_mode)
|
||||
{
|
||||
int i, ip, bn;
|
||||
for (i=0; i<num_bits; i++) {
|
||||
ip = in_ofs + i;
|
||||
bn = lsb_mode ? (ip&7) : (7-(ip&7));
|
||||
out[out_ofs+i] = !!(in[ip>>3] & (1<<bn));
|
||||
}
|
||||
return out_ofs + num_bits;
|
||||
}
|
||||
|
||||
/*! generalized bit reversal function
|
||||
* \param[in] x the 32bit value to be reversed
|
||||
* \param[in] k the type of reversal requested
|
||||
* \returns the reversed 32bit dword
|
||||
*
|
||||
* This function reverses the bit order within a 32bit word. Depending
|
||||
* on "k", it either reverses all bits in a 32bit dword, or the bytes in
|
||||
* the dword, or the bits in each byte of a dword, or simply swaps the
|
||||
* two 16bit words in a dword. See Chapter 7 "Hackers Delight"
|
||||
*/
|
||||
uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k)
|
||||
{
|
||||
if (k & 1) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
|
||||
if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
|
||||
if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
|
||||
if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
|
||||
if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*! reverse the bit-order in each byte of a dword
|
||||
* \param[in] x 32bit input value
|
||||
* \returns 32bit value where bits of each byte have been reversed
|
||||
*
|
||||
* See Chapter 7 "Hackers Delight"
|
||||
*/
|
||||
uint32_t osmo_revbytebits_32(uint32_t x)
|
||||
{
|
||||
x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
|
||||
x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
|
||||
x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*! reverse the bit order in a byte
|
||||
* \param[in] x 8bit input value
|
||||
* \returns 8bit value where bits order has been reversed
|
||||
*
|
||||
* See Chapter 7 "Hackers Delight"
|
||||
*/
|
||||
uint32_t osmo_revbytebits_8(uint8_t x)
|
||||
{
|
||||
x = (x & 0x55) << 1 | (x & 0xAA) >> 1;
|
||||
x = (x & 0x33) << 2 | (x & 0xCC) >> 2;
|
||||
x = (x & 0x0F) << 4 | (x & 0xF0) >> 4;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*! reverse bit-order of each byte in a buffer
|
||||
* \param[in] buf buffer containing bytes to be bit-reversed
|
||||
* \param[in] len length of buffer in bytes
|
||||
*
|
||||
* This function reverses the bits in each byte of the buffer
|
||||
*/
|
||||
void osmo_revbytebits_buf(uint8_t *buf, int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int unaligned_cnt;
|
||||
int len_remain = len;
|
||||
|
||||
unaligned_cnt = ((unsigned long)buf & 3);
|
||||
for (i = 0; i < unaligned_cnt; i++) {
|
||||
buf[i] = osmo_revbytebits_8(buf[i]);
|
||||
len_remain--;
|
||||
if (len_remain <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = unaligned_cnt; i + 3 < len; i += 4) {
|
||||
osmo_store32be(osmo_revbytebits_32(osmo_load32be(buf + i)), buf + i);
|
||||
len_remain -= 4;
|
||||
}
|
||||
|
||||
for (i = len - len_remain; i < len; i++) {
|
||||
buf[i] = osmo_revbytebits_8(buf[i]);
|
||||
len_remain--;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,122 +0,0 @@
|
|||
/*! \file bits.h
|
||||
* Osmocom bit level support code.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <osmocom/core/bit16gen.h>
|
||||
#include <osmocom/core/bit32gen.h>
|
||||
#include <osmocom/core/bit64gen.h>
|
||||
|
||||
/*! \defgroup bits soft, unpacked and packed bits
|
||||
* @{
|
||||
* \file bits.h */
|
||||
|
||||
/*! soft bit with value (-127...127), as commonly used in
|
||||
* communications receivers such as [viterbi] decoders */
|
||||
typedef int8_t sbit_t;
|
||||
|
||||
/*! unpacked bit (0 or 1): 1 bit per byte */
|
||||
typedef uint8_t ubit_t;
|
||||
|
||||
/*! packed bits (8 bits in a byte).
|
||||
* NOTE on the endian-ness of \ref pbit_t:
|
||||
* - Bits in a \ref pbit_t are ordered MSB first, i.e. 0x80 is the first bit.
|
||||
* - Bit i in a \ref pbit_t array is array[i/8] & (1<<(7-i%8)) */
|
||||
typedef uint8_t pbit_t;
|
||||
|
||||
/*! determine how many bytes we would need for \a num_bits packed bits
|
||||
* \param[in] num_bits Number of packed bits
|
||||
* \returns number of bytes needed for \a num_bits packed bits
|
||||
*/
|
||||
static inline unsigned int osmo_pbit_bytesize(unsigned int num_bits)
|
||||
{
|
||||
unsigned int pbit_bytesize = num_bits / 8;
|
||||
|
||||
if (num_bits % 8)
|
||||
pbit_bytesize++;
|
||||
|
||||
return pbit_bytesize;
|
||||
}
|
||||
|
||||
int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits);
|
||||
|
||||
int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits);
|
||||
|
||||
void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
|
||||
unsigned int num_nibbles);
|
||||
void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
|
||||
unsigned int num_nibbles);
|
||||
|
||||
void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits);
|
||||
void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits);
|
||||
|
||||
int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
|
||||
const ubit_t *in, unsigned int in_ofs,
|
||||
unsigned int num_bits, int lsb_mode);
|
||||
|
||||
int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
|
||||
const pbit_t *in, unsigned int in_ofs,
|
||||
unsigned int num_bits, int lsb_mode);
|
||||
|
||||
#define OSMO_BIN_SPEC "%d%d%d%d%d%d%d%d"
|
||||
#define OSMO_BIN_PRINT(byte) \
|
||||
(byte & 0x80 ? 1 : 0), \
|
||||
(byte & 0x40 ? 1 : 0), \
|
||||
(byte & 0x20 ? 1 : 0), \
|
||||
(byte & 0x10 ? 1 : 0), \
|
||||
(byte & 0x08 ? 1 : 0), \
|
||||
(byte & 0x04 ? 1 : 0), \
|
||||
(byte & 0x02 ? 1 : 0), \
|
||||
(byte & 0x01 ? 1 : 0)
|
||||
|
||||
#define OSMO_BIT_SPEC "%c%c%c%c%c%c%c%c"
|
||||
#define OSMO_BIT_PRINT_EX(byte, ch) \
|
||||
(byte & 0x80 ? ch : '.'), \
|
||||
(byte & 0x40 ? ch : '.'), \
|
||||
(byte & 0x20 ? ch : '.'), \
|
||||
(byte & 0x10 ? ch : '.'), \
|
||||
(byte & 0x08 ? ch : '.'), \
|
||||
(byte & 0x04 ? ch : '.'), \
|
||||
(byte & 0x02 ? ch : '.'), \
|
||||
(byte & 0x01 ? ch : '.')
|
||||
|
||||
#define OSMO_BIT_PRINT(byte) OSMO_BIT_PRINT_EX(byte, '1')
|
||||
|
||||
/* BIT REVERSAL */
|
||||
|
||||
/*! bit-reversal mode for osmo_bit_reversal() */
|
||||
enum osmo_br_mode {
|
||||
/*! reverse all bits in a 32bit dword */
|
||||
OSMO_BR_BITS_IN_DWORD = 31,
|
||||
/*! reverse byte order in a 32bit dword */
|
||||
OSMO_BR_BYTES_IN_DWORD = 24,
|
||||
/*! reverse bits of each byte in a 32bit dword */
|
||||
OSMO_BR_BITS_IN_BYTE = 7,
|
||||
/*! swap the two 16bit words in a 32bit dword */
|
||||
OSMO_BR_WORD_SWAP = 16,
|
||||
};
|
||||
|
||||
uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k);
|
||||
|
||||
uint32_t osmo_revbytebits_32(uint32_t x);
|
||||
|
||||
uint32_t osmo_revbytebits_8(uint8_t x);
|
||||
|
||||
void osmo_revbytebits_buf(uint8_t *buf, int len);
|
||||
|
||||
/*! left circular shift
|
||||
* \param[in] in The 16 bit unsigned integer to be rotated
|
||||
* \param[in] shift Number of bits to shift \a in to, [0;16] bits
|
||||
* \returns shifted value
|
||||
*/
|
||||
static inline uint16_t osmo_rol16(uint16_t in, unsigned shift)
|
||||
{
|
||||
return (in << shift) | (in >> (16 - shift));
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,709 +0,0 @@
|
|||
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2012 Ivan Klyuchnikov
|
||||
* (C) 2015 by sysmocom - s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \addtogroup bitvec
|
||||
* @{
|
||||
* Osmocom bit vector abstraction utility routines.
|
||||
*
|
||||
* These functions assume a MSB (most significant bit) first layout of the
|
||||
* bits, so that for instance the 5 bit number abcde (a is MSB) can be
|
||||
* embedded into a byte sequence like in xxxxxxab cdexxxxx. The bit count
|
||||
* starts with the MSB, so the bits in a byte are numbered (MSB) 01234567 (LSB).
|
||||
* Note that there are other incompatible encodings, like it is used
|
||||
* for the EGPRS RLC data block headers (there the bits are numbered from LSB
|
||||
* to MSB).
|
||||
*
|
||||
* \file bitvec.c */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/bitvec.h>
|
||||
|
||||
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
|
||||
|
||||
static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
|
||||
{
|
||||
unsigned int bytenum = bitnum / 8;
|
||||
|
||||
return bytenum;
|
||||
}
|
||||
|
||||
/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
|
||||
static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
|
||||
{
|
||||
int bitval;
|
||||
|
||||
switch (bit) {
|
||||
case ZERO:
|
||||
bitval = (0 << bitnum);
|
||||
break;
|
||||
case ONE:
|
||||
bitval = (1 << bitnum);
|
||||
break;
|
||||
case L:
|
||||
bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
|
||||
break;
|
||||
case H:
|
||||
bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return bitval;
|
||||
}
|
||||
|
||||
/*! check if the bit is 0 or 1 for a given position inside a bitvec
|
||||
* \param[in] bv the bit vector on which to check
|
||||
* \param[in] bitnr the bit number inside the bit vector to check
|
||||
* \return value of the requested bit
|
||||
*/
|
||||
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
|
||||
{
|
||||
unsigned int bytenum = bytenum_from_bitnum(bitnr);
|
||||
unsigned int bitnum = 7 - (bitnr % 8);
|
||||
uint8_t bitval;
|
||||
|
||||
if (bytenum >= bv->data_len)
|
||||
return -EINVAL;
|
||||
|
||||
bitval = bitval2mask(ONE, bitnum);
|
||||
|
||||
if (bv->data[bytenum] & bitval)
|
||||
return ONE;
|
||||
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
/*! check if the bit is L or H for a given position inside a bitvec
|
||||
* \param[in] bv the bit vector on which to check
|
||||
* \param[in] bitnr the bit number inside the bit vector to check
|
||||
* \return value of the requested bit
|
||||
*/
|
||||
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
|
||||
unsigned int bitnr)
|
||||
{
|
||||
unsigned int bytenum = bytenum_from_bitnum(bitnr);
|
||||
unsigned int bitnum = 7 - (bitnr % 8);
|
||||
uint8_t bitval;
|
||||
|
||||
if (bytenum >= bv->data_len)
|
||||
return -EINVAL;
|
||||
|
||||
bitval = bitval2mask(H, bitnum);
|
||||
|
||||
if ((bv->data[bytenum] & (1 << bitnum)) == bitval)
|
||||
return H;
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
/*! get the Nth set bit inside the bit vector
|
||||
* \param[in] bv the bit vector to use
|
||||
* \param[in] n the bit number to get
|
||||
* \returns the bit number (offset) of the Nth set bit in \a bv
|
||||
*/
|
||||
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
|
||||
{
|
||||
unsigned int i, k = 0;
|
||||
|
||||
for (i = 0; i < bv->data_len*8; i++) {
|
||||
if (bitvec_get_bit_pos(bv, i) == ONE) {
|
||||
k++;
|
||||
if (k == n)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! set a bit at given position in a bit vector
|
||||
* \param[in] bv bit vector on which to operate
|
||||
* \param[in] bitnr number of bit to be set
|
||||
* \param[in] bit value to which the bit is to be set
|
||||
* \returns 0 on success, negative value on error
|
||||
*/
|
||||
inline int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
|
||||
enum bit_value bit)
|
||||
{
|
||||
unsigned int bytenum = bytenum_from_bitnum(bitnr);
|
||||
unsigned int bitnum = 7 - (bitnr % 8);
|
||||
uint8_t bitval;
|
||||
|
||||
if (bytenum >= bv->data_len)
|
||||
return -EINVAL;
|
||||
|
||||
/* first clear the bit */
|
||||
bitval = bitval2mask(ONE, bitnum);
|
||||
bv->data[bytenum] &= ~bitval;
|
||||
|
||||
/* then set it to desired value */
|
||||
bitval = bitval2mask(bit, bitnum);
|
||||
bv->data[bytenum] |= bitval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! set the next bit inside a bitvec
|
||||
* \param[in] bv bit vector to be used
|
||||
* \param[in] bit value of the bit to be set
|
||||
* \returns 0 on success, negative value on error
|
||||
*/
|
||||
inline int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
|
||||
if (!rc)
|
||||
bv->cur_bit++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! get the next bit (low/high) inside a bitvec
|
||||
* \return value of th next bit in the vector */
|
||||
int bitvec_get_bit_high(struct bitvec *bv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
|
||||
if (rc >= 0)
|
||||
bv->cur_bit++;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! set multiple bits (based on array of bitvals) at current pos
|
||||
* \param[in] bv bit vector
|
||||
* \param[in] bits array of \ref bit_value
|
||||
* \param[in] count number of bits to set
|
||||
* \return 0 on success; negative in case of error */
|
||||
int bitvec_set_bits(struct bitvec *bv, const enum bit_value *bits, unsigned int count)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = bitvec_set_bit(bv, bits[i]);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! set multiple bits (based on numeric value) at current pos.
|
||||
* \param[in] bv bit vector.
|
||||
* \param[in] v mask representing which bits needs to be set.
|
||||
* \param[in] num_bits number of meaningful bits in the mask.
|
||||
* \param[in] use_lh whether to interpret the bits as L/H values or as 0/1.
|
||||
* \return 0 on success; negative in case of error. */
|
||||
int bitvec_set_u64(struct bitvec *bv, uint64_t v, uint8_t num_bits, bool use_lh)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (num_bits > 64)
|
||||
return -E2BIG;
|
||||
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
int rc;
|
||||
enum bit_value bit = use_lh ? L : 0;
|
||||
|
||||
if (v & ((uint64_t)1 << (num_bits - i - 1)))
|
||||
bit = use_lh ? H : 1;
|
||||
|
||||
rc = bitvec_set_bit(bv, bit);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! set multiple bits (based on numeric value) at current pos.
|
||||
* \return 0 in case of success; negative in case of error. */
|
||||
int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
|
||||
{
|
||||
return bitvec_set_u64(bv, ui, num_bits, false);
|
||||
}
|
||||
|
||||
/*! get multiple bits (num_bits) from beginning of vector (MSB side)
|
||||
* \return 16bit signed integer retrieved from bit vector */
|
||||
int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits)
|
||||
{
|
||||
if (num_bits > 15 || bv->cur_bit < num_bits)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_bits < 9)
|
||||
return bv->data[0] >> (8 - num_bits);
|
||||
|
||||
return osmo_load16be(bv->data) >> (16 - num_bits);
|
||||
}
|
||||
|
||||
/*! get multiple bits (based on numeric value) from current pos
|
||||
* \return integer value retrieved from bit vector */
|
||||
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
|
||||
{
|
||||
int i;
|
||||
unsigned int ui = 0;
|
||||
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
|
||||
if (bit < 0)
|
||||
return bit;
|
||||
if (bit)
|
||||
ui |= (1 << (num_bits - i - 1));
|
||||
bv->cur_bit++;
|
||||
}
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
/*! fill num_bits with \fill starting from the current position
|
||||
* \return 0 on success; negative otherwise (out of vector boundary)
|
||||
*/
|
||||
int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
|
||||
{
|
||||
unsigned i, stop = bv->cur_bit + num_bits;
|
||||
for (i = bv->cur_bit; i < stop; i++)
|
||||
if (bitvec_set_bit(bv, fill) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! pad all remaining bits up to num_bits
|
||||
* \return 0 on success; negative otherwise */
|
||||
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
|
||||
{
|
||||
int n = up_to_bit - bv->cur_bit + 1;
|
||||
if (n < 1)
|
||||
return 0;
|
||||
|
||||
return bitvec_fill(bv, n, L);
|
||||
}
|
||||
|
||||
/*! find first bit set in bit vector
|
||||
* \return 0 on success; negative otherwise */
|
||||
int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n,
|
||||
enum bit_value val)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = n; i < bv->data_len*8; i++) {
|
||||
if (bitvec_get_bit_pos(bv, i) == val)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! get multiple bytes from current pos
|
||||
* Assumes MSB first encoding.
|
||||
* \param[in] bv bit vector
|
||||
* \param[in] bytes array
|
||||
* \param[in] count number of bytes to copy
|
||||
* \return 0 on success; negative otherwise
|
||||
*/
|
||||
int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count)
|
||||
{
|
||||
int byte_offs = bytenum_from_bitnum(bv->cur_bit);
|
||||
int bit_offs = bv->cur_bit % 8;
|
||||
uint8_t c, last_c;
|
||||
int i;
|
||||
uint8_t *src;
|
||||
|
||||
if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (bit_offs == 0) {
|
||||
memcpy(bytes, bv->data + byte_offs, count);
|
||||
} else {
|
||||
src = bv->data + byte_offs;
|
||||
last_c = *(src++);
|
||||
for (i = count; i > 0; i--) {
|
||||
c = *(src++);
|
||||
*(bytes++) =
|
||||
(last_c << bit_offs) |
|
||||
(c >> (8 - bit_offs));
|
||||
last_c = c;
|
||||
}
|
||||
}
|
||||
|
||||
bv->cur_bit += count * 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! set multiple bytes at current pos
|
||||
* Assumes MSB first encoding.
|
||||
* \param[in] bv bit vector
|
||||
* \param[in] bytes array
|
||||
* \param[in] count number of bytes to copy
|
||||
* \return 0 on success; negative otherwise
|
||||
*/
|
||||
int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count)
|
||||
{
|
||||
int byte_offs = bytenum_from_bitnum(bv->cur_bit);
|
||||
int bit_offs = bv->cur_bit % 8;
|
||||
uint8_t c, last_c;
|
||||
int i;
|
||||
uint8_t *dst;
|
||||
|
||||
if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (bit_offs == 0) {
|
||||
memcpy(bv->data + byte_offs, bytes, count);
|
||||
} else if (count > 0) {
|
||||
dst = bv->data + byte_offs;
|
||||
/* Get lower bits of first dst byte */
|
||||
last_c = *dst >> (8 - bit_offs);
|
||||
for (i = count; i > 0; i--) {
|
||||
c = *(bytes++);
|
||||
*(dst++) =
|
||||
(last_c << (8 - bit_offs)) |
|
||||
(c >> bit_offs);
|
||||
last_c = c;
|
||||
}
|
||||
/* Overwrite lower bits of N+1 dst byte */
|
||||
*dst = (*dst & ((1 << (8 - bit_offs)) - 1)) |
|
||||
(last_c << (8 - bit_offs));
|
||||
}
|
||||
|
||||
bv->cur_bit += count * 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Allocate a bit vector
|
||||
* \param[in] size Number of bits in the vector
|
||||
* \param[in] ctx Context from which to allocate
|
||||
* \return pointer to allocated vector; NULL in case of error /
|
||||
struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
|
||||
{
|
||||
struct bitvec *bv = talloc_zero(ctx, struct bitvec);
|
||||
if (!bv)
|
||||
return NULL;
|
||||
|
||||
bv->data = talloc_zero_array(bv, uint8_t, size);
|
||||
if (!(bv->data)) {
|
||||
talloc_free(bv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bv->data_len = size;
|
||||
bv->cur_bit = 0;
|
||||
return bv;
|
||||
}
|
||||
|
||||
/*! Free a bit vector (release its memory)
|
||||
* \param[in] bit vector to free *
|
||||
void bitvec_free(struct bitvec *bv)
|
||||
{
|
||||
talloc_free(bv->data);
|
||||
talloc_free(bv);
|
||||
}
|
||||
*/
|
||||
/*! Export a bit vector to a buffer
|
||||
* \param[in] bitvec (unpacked bits)
|
||||
* \param[out] buffer for the unpacked bits
|
||||
* \return number of bytes (= bits) copied */
|
||||
unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < bv->data_len; i++)
|
||||
buffer[i] = bv->data[i];
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*! Copy buffer of unpacked bits into bit vector
|
||||
* \param[in] buffer unpacked input bits
|
||||
* \param[out] bv unpacked bit vector
|
||||
* \return number of bytes (= bits) copied */
|
||||
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < bv->data_len; i++)
|
||||
bv->data[i] = buffer[i];
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*! read hexadecimap string into a bit vector
|
||||
* \param[in] src string containing hex digits
|
||||
* \param[out] bv unpacked bit vector
|
||||
* \return 0 in case of success; 1 in case of error
|
||||
*/
|
||||
int bitvec_unhex(struct bitvec *bv, const char *src)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned val;
|
||||
unsigned write_index = 0;
|
||||
unsigned digits = bv->data_len * 2;
|
||||
|
||||
for (i = 0; i < digits; i++) {
|
||||
if (sscanf(src + i, "%1x", &val) < 1) {
|
||||
return 1;
|
||||
}
|
||||
bitvec_write_field(bv, &write_index, val, 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! read part of the vector
|
||||
* \param[in] bv The boolean vector to work on
|
||||
* \param[in,out] read_index Where reading supposed to start in the vector
|
||||
* \param[in] len How many bits to read from vector
|
||||
* \returns read bits or negative value on error
|
||||
*/
|
||||
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t ui = 0;
|
||||
bv->cur_bit = *read_index;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
|
||||
if (bit < 0)
|
||||
return bit;
|
||||
if (bit)
|
||||
ui |= ((uint64_t)1 << (len - i - 1));
|
||||
bv->cur_bit++;
|
||||
}
|
||||
*read_index += len;
|
||||
return ui;
|
||||
}
|
||||
|
||||
/*! write into the vector
|
||||
* \param[in] bv The boolean vector to work on
|
||||
* \param[in,out] write_index Where writing supposed to start in the vector
|
||||
* \param[in] len How many bits to write
|
||||
* \returns next write index or negative value on error
|
||||
*/
|
||||
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
bv->cur_bit = *write_index;
|
||||
|
||||
rc = bitvec_set_u64(bv, val, len, false);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
*write_index += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! convert enum to corresponding character
|
||||
* \param v input value (bit)
|
||||
* \return single character, either 0, 1, L or H */
|
||||
char bit_value_to_char(enum bit_value v)
|
||||
{
|
||||
switch (v) {
|
||||
case ZERO: return '0';
|
||||
case ONE: return '1';
|
||||
case L: return 'L';
|
||||
case H: return 'H';
|
||||
default: abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*! prints bit vector to provided string
|
||||
* It's caller's responsibility to ensure that we won't shoot him in the foot:
|
||||
* the provided buffer should be at lest cur_bit + 1 bytes long
|
||||
*/
|
||||
void bitvec_to_string_r(const struct bitvec *bv, char *str)
|
||||
{
|
||||
unsigned i, pos = 0;
|
||||
char *cur = str;
|
||||
for (i = 0; i < bv->cur_bit; i++) {
|
||||
if (0 == i % 8)
|
||||
*cur++ = ' ';
|
||||
*cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i));
|
||||
pos++;
|
||||
}
|
||||
*cur = 0;
|
||||
}
|
||||
|
||||
/* we assume that x have at least 1 non-b bit */
|
||||
static inline unsigned leading_bits(uint8_t x, bool b)
|
||||
{
|
||||
if (b) {
|
||||
if (x < 0x80) return 0;
|
||||
if (x < 0xC0) return 1;
|
||||
if (x < 0xE0) return 2;
|
||||
if (x < 0xF0) return 3;
|
||||
if (x < 0xF8) return 4;
|
||||
if (x < 0xFC) return 5;
|
||||
if (x < 0xFE) return 6;
|
||||
} else {
|
||||
if (x > 0x7F) return 0;
|
||||
if (x > 0x3F) return 1;
|
||||
if (x > 0x1F) return 2;
|
||||
if (x > 0xF) return 3;
|
||||
if (x > 7) return 4;
|
||||
if (x > 3) return 5;
|
||||
if (x > 1) return 6;
|
||||
}
|
||||
return 7;
|
||||
}
|
||||
/*! force bit vector to all 0 and current bit to the beginnig of the vector */
|
||||
void bitvec_zero(struct bitvec *bv)
|
||||
{
|
||||
bv->cur_bit = 0;
|
||||
memset(bv->data, 0, bv->data_len);
|
||||
}
|
||||
|
||||
/*! Return number (bits) of uninterrupted bit run in vector starting from the MSB
|
||||
* \param[in] bv The boolean vector to work on
|
||||
* \param[in] b The boolean, sequence of which is looked at from the vector start
|
||||
* \returns Number of consecutive bits of \p b in \p bv
|
||||
*/
|
||||
unsigned bitvec_rl(const struct bitvec *bv, bool b)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) {
|
||||
if ( (b ? 0xFF : 0) != bv->data[i])
|
||||
return i * 8 + leading_bits(bv->data[i], b);
|
||||
}
|
||||
|
||||
return bv->cur_bit;
|
||||
}
|
||||
|
||||
/*! Return number (bits) of uninterrupted bit run in vector
|
||||
* starting from the current bit
|
||||
* \param[in] bv The boolean vector to work on
|
||||
* \param[in] b The boolean, sequence of 1's or 0's to be checked
|
||||
* \param[in] max_bits Total Number of Uncmopresed bits
|
||||
* \returns Number of consecutive bits of \p b in \p bv and cur_bit will
|
||||
* \go to cur_bit + number of consecutive bit
|
||||
*/
|
||||
unsigned bitvec_rl_curbit(struct bitvec *bv, bool b, int max_bits)
|
||||
{
|
||||
unsigned i = 0;
|
||||
unsigned j = 8;
|
||||
int temp_res = 0;
|
||||
int count = 0;
|
||||
unsigned readIndex = bv->cur_bit;
|
||||
unsigned remaining_bits = max_bits % 8;
|
||||
unsigned remaining_bytes = max_bits / 8;
|
||||
unsigned byte_mask = 0xFF;
|
||||
|
||||
if (readIndex % 8) {
|
||||
for (j -= (readIndex % 8) ; j > 0 ; j--) {
|
||||
if (readIndex < max_bits && bitvec_read_field(bv, &readIndex, 1) == b)
|
||||
temp_res++;
|
||||
else {
|
||||
bv->cur_bit--;
|
||||
return temp_res;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = (readIndex / 8);
|
||||
i < (remaining_bits ? remaining_bytes + 1 : remaining_bytes);
|
||||
i++, count++) {
|
||||
if ((b ? byte_mask : 0) != bv->data[i]) {
|
||||
bv->cur_bit = (count * 8 +
|
||||
leading_bits(bv->data[i], b) + readIndex);
|
||||
return count * 8 +
|
||||
leading_bits(bv->data[i], b) + temp_res;
|
||||
}
|
||||
}
|
||||
bv->cur_bit = (temp_res + (count * 8)) + readIndex;
|
||||
if (bv->cur_bit > max_bits)
|
||||
bv->cur_bit = max_bits;
|
||||
return (bv->cur_bit - readIndex + temp_res);
|
||||
}
|
||||
|
||||
/*! Shifts bitvec to the left, n MSB bits lost */
|
||||
void bitvec_shiftl(struct bitvec *bv, unsigned n)
|
||||
{
|
||||
if (0 == n)
|
||||
return;
|
||||
if (n >= bv->cur_bit) {
|
||||
bitvec_zero(bv);
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8);
|
||||
|
||||
uint8_t tmp[2];
|
||||
unsigned i;
|
||||
for (i = 0; i < bv->data_len - 2; i++) {
|
||||
uint16_t t = osmo_load16be(bv->data + i);
|
||||
osmo_store16be(t << (n % 8), &tmp);
|
||||
bv->data[i] = tmp[0];
|
||||
}
|
||||
|
||||
bv->data[bv->data_len - 1] <<= (n % 8);
|
||||
bv->cur_bit -= n;
|
||||
}
|
||||
|
||||
/*! Add given array to bitvec
|
||||
* \param[in,out] bv bit vector to work with
|
||||
* \param[in] array elements to be added
|
||||
* \param[in] array_len length of array
|
||||
* \param[in] dry_run indicates whether to return number of bits required
|
||||
* instead of adding anything to bv for real
|
||||
* \param[in] num_bits number of bits to consider in each element of array
|
||||
* \returns number of bits necessary to add array elements if dry_run is true,
|
||||
* 0 otherwise (only in this case bv is actually changed)
|
||||
*
|
||||
* N. B: no length checks are performed on bv - it's caller's job to ensure
|
||||
* enough space is available - for example by calling with dry_run = true first.
|
||||
*
|
||||
* Useful for common pattern in CSN.1 spec which looks like:
|
||||
* { 1 < XXX : bit (num_bits) > } ** 0
|
||||
* which means repeat any times (between 0 and infinity),
|
||||
* start each repetition with 1, mark end of repetitions with 0 bit
|
||||
* see app. note in 3GPP TS 24.007 § B.2.1 Rule A2
|
||||
*/
|
||||
unsigned int bitvec_add_array(struct bitvec *bv, const uint32_t *array,
|
||||
unsigned int array_len, bool dry_run,
|
||||
unsigned int num_bits)
|
||||
{
|
||||
unsigned i, bits = 1; /* account for stop bit */
|
||||
for (i = 0; i < array_len; i++) {
|
||||
if (dry_run) {
|
||||
bits += (1 + num_bits);
|
||||
} else {
|
||||
bitvec_set_bit(bv, 1);
|
||||
bitvec_set_uint(bv, array[i], num_bits);
|
||||
}
|
||||
}
|
||||
|
||||
if (dry_run)
|
||||
return bits;
|
||||
|
||||
bitvec_set_bit(bv, 0); /* stop bit - end of the sequence */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,87 +0,0 @@
|
|||
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2012 Ivan Klyuchnikov
|
||||
* (C) 2015 sysmocom - s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \defgroup bitvec Bit vectors
|
||||
* @{
|
||||
* \file bitvec.h */
|
||||
|
||||
#include <stdint.h>
|
||||
//#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/defs.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*! A single GSM bit
|
||||
*
|
||||
* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are
|
||||
* defined relative to the 0x2b padding pattern */
|
||||
enum bit_value {
|
||||
ZERO = 0, /*!< A zero (0) bit */
|
||||
ONE = 1, /*!< A one (1) bit */
|
||||
L = 2, /*!< A CSN.1 "L" bit */
|
||||
H = 3, /*!< A CSN.1 "H" bit */
|
||||
};
|
||||
|
||||
/*! structure describing a bit vector */
|
||||
struct bitvec {
|
||||
unsigned int cur_bit; /*!< cursor to the next unused bit */
|
||||
unsigned int data_len; /*!< length of data array in bytes */
|
||||
uint8_t *data; /*!< pointer to data array */
|
||||
};
|
||||
|
||||
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
|
||||
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
|
||||
unsigned int bitnr);
|
||||
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
|
||||
int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
|
||||
enum bit_value bit);
|
||||
int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
|
||||
int bitvec_get_bit_high(struct bitvec *bv);
|
||||
int bitvec_set_bits(struct bitvec *bv, const enum bit_value *bits, unsigned int count);
|
||||
int bitvec_set_u64(struct bitvec *bv, uint64_t v, uint8_t num_bits, bool use_lh);
|
||||
int bitvec_set_uint(struct bitvec *bv, unsigned int in, unsigned int count);
|
||||
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits);
|
||||
int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val);
|
||||
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
|
||||
int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count);
|
||||
int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count);
|
||||
/*struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *bvctx);*/
|
||||
/*void bitvec_free(struct bitvec *bv);*/
|
||||
int bitvec_unhex(struct bitvec *bv, const char *src);
|
||||
unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer);
|
||||
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer);
|
||||
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len);
|
||||
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len);
|
||||
int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill);
|
||||
char bit_value_to_char(enum bit_value v);
|
||||
void bitvec_to_string_r(const struct bitvec *bv, char *str);
|
||||
void bitvec_zero(struct bitvec *bv);
|
||||
unsigned bitvec_rl(const struct bitvec *bv, bool b);
|
||||
unsigned bitvec_rl_curbit(struct bitvec *bv, bool b, int max_bits);
|
||||
void bitvec_shiftl(struct bitvec *bv, unsigned int n);
|
||||
int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits);
|
||||
unsigned int bitvec_add_array(struct bitvec *bv, const uint32_t *array,
|
||||
unsigned int array_len, bool dry_run,
|
||||
unsigned int num_bits);
|
||||
|
||||
/*! @} */
|
|
@ -1,644 +0,0 @@
|
|||
/*! \file conv.c
|
||||
* Generic convolutional encoding / decoding. */
|
||||
/*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \addtogroup conv
|
||||
* @{
|
||||
* Osmocom convolutional encoder and decoder.
|
||||
*
|
||||
* \file conv.c */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/conv.h>
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Common */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int
|
||||
osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
|
||||
{
|
||||
return len <= 0 ? code->len : len;
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
|
||||
{
|
||||
int pbits, in_len, out_len;
|
||||
|
||||
/* Input length */
|
||||
in_len = osmo_conv_get_input_length(code, len);
|
||||
|
||||
/* Output length */
|
||||
out_len = in_len * code->N;
|
||||
|
||||
if (code->term == CONV_TERM_FLUSH)
|
||||
out_len += code->N * (code->K - 1);
|
||||
|
||||
/* Count punctured bits */
|
||||
if (code->puncture) {
|
||||
for (pbits=0; code->puncture[pbits] >= 0; pbits++);
|
||||
out_len -= pbits;
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Encoding */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/*! Initialize a convolutional encoder
|
||||
* \param[in,out] encoder Encoder state to initialize
|
||||
* \param[in] code Description of convolutional code
|
||||
*/
|
||||
void
|
||||
osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
|
||||
const struct osmo_conv_code *code)
|
||||
{
|
||||
memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
|
||||
encoder->code = code;
|
||||
}
|
||||
|
||||
void
|
||||
osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
|
||||
const ubit_t *input)
|
||||
{
|
||||
int i;
|
||||
uint8_t state = 0;
|
||||
|
||||
for (i=0; i<(encoder->code->K-1); i++)
|
||||
state = (state << 1) | input[i];
|
||||
|
||||
encoder->state = state;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_conv_encode_do_output(struct osmo_conv_encoder *encoder,
|
||||
uint8_t out, ubit_t *output)
|
||||
{
|
||||
const struct osmo_conv_code *code = encoder->code;
|
||||
int o_idx = 0;
|
||||
int j;
|
||||
|
||||
if (code->puncture) {
|
||||
for (j=0; j<code->N; j++)
|
||||
{
|
||||
int bit_no = code->N - j - 1;
|
||||
int r_idx = encoder->i_idx * code->N + j;
|
||||
|
||||
if (code->puncture[encoder->p_idx] == r_idx)
|
||||
encoder->p_idx++;
|
||||
else
|
||||
output[o_idx++] = (out >> bit_no) & 1;
|
||||
}
|
||||
} else {
|
||||
for (j=0; j<code->N; j++)
|
||||
{
|
||||
int bit_no = code->N - j - 1;
|
||||
output[o_idx++] = (out >> bit_no) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
return o_idx;
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
|
||||
const ubit_t *input, ubit_t *output, int n)
|
||||
{
|
||||
const struct osmo_conv_code *code = encoder->code;
|
||||
uint8_t state;
|
||||
int i;
|
||||
int o_idx;
|
||||
|
||||
o_idx = 0;
|
||||
state = encoder->state;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
int bit = input[i];
|
||||
uint8_t out;
|
||||
|
||||
out = code->next_output[state][bit];
|
||||
state = code->next_state[state][bit];
|
||||
|
||||
o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
|
||||
|
||||
encoder->i_idx++;
|
||||
}
|
||||
|
||||
encoder->state = state;
|
||||
|
||||
return o_idx;
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
|
||||
ubit_t *output)
|
||||
{
|
||||
const struct osmo_conv_code *code = encoder->code;
|
||||
uint8_t state;
|
||||
int n;
|
||||
int i;
|
||||
int o_idx;
|
||||
|
||||
n = code->K - 1;
|
||||
|
||||
o_idx = 0;
|
||||
state = encoder->state;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
uint8_t out;
|
||||
|
||||
if (code->next_term_output) {
|
||||
out = code->next_term_output[state];
|
||||
state = code->next_term_state[state];
|
||||
} else {
|
||||
out = code->next_output[state][0];
|
||||
state = code->next_state[state][0];
|
||||
}
|
||||
|
||||
o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
|
||||
|
||||
encoder->i_idx++;
|
||||
}
|
||||
|
||||
encoder->state = state;
|
||||
|
||||
return o_idx;
|
||||
}
|
||||
|
||||
/*! All-in-one convolutional encoding function
|
||||
* \param[in] code description of convolutional code to be used
|
||||
* \param[in] input array of unpacked bits (uncoded)
|
||||
* \param[out] output array of unpacked bits (encoded)
|
||||
* \return Number of produced output bits
|
||||
*
|
||||
* This is an all-in-one function, taking care of
|
||||
* \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
|
||||
* \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
|
||||
*/
|
||||
int
|
||||
osmo_conv_encode(const struct osmo_conv_code *code,
|
||||
const ubit_t *input, ubit_t *output)
|
||||
{
|
||||
struct osmo_conv_encoder encoder;
|
||||
int l;
|
||||
|
||||
osmo_conv_encode_init(&encoder, code);
|
||||
|
||||
if (code->term == CONV_TERM_TAIL_BITING) {
|
||||
int eidx = code->len - code->K + 1;
|
||||
osmo_conv_encode_load_state(&encoder, &input[eidx]);
|
||||
}
|
||||
|
||||
l = osmo_conv_encode_raw(&encoder, input, output, code->len);
|
||||
|
||||
if (code->term == CONV_TERM_FLUSH)
|
||||
l += osmo_conv_encode_flush(&encoder, &output[l]);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Decoding (viterbi) */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define MAX_AE 0x00ffffff
|
||||
|
||||
/* Forward declaration for accerlated decoding with certain codes */
|
||||
int
|
||||
osmo_conv_decode_acc(const struct osmo_conv_code *code,
|
||||
const sbit_t *input, ubit_t *output);
|
||||
|
||||
void
|
||||
osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
|
||||
const struct osmo_conv_code *code, int len, int start_state)
|
||||
{
|
||||
int n_states;
|
||||
|
||||
/* Init */
|
||||
if (len <= 0)
|
||||
len = code->len;
|
||||
|
||||
n_states = 1 << (code->K - 1);
|
||||
|
||||
memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
|
||||
|
||||
decoder->code = code;
|
||||
decoder->n_states = n_states;
|
||||
decoder->len = len;
|
||||
|
||||
/* Allocate arrays */
|
||||
decoder->ae = malloc(sizeof(unsigned int) * n_states);
|
||||
decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
|
||||
|
||||
decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
|
||||
|
||||
/* Classic reset */
|
||||
osmo_conv_decode_reset(decoder, start_state);
|
||||
}
|
||||
|
||||
void
|
||||
osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Reset indexes */
|
||||
decoder->o_idx = 0;
|
||||
decoder->p_idx = 0;
|
||||
|
||||
/* Initial error */
|
||||
if (start_state < 0) {
|
||||
/* All states possible */
|
||||
memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
|
||||
} else {
|
||||
/* Fixed start state */
|
||||
for (i=0; i<decoder->n_states; i++) {
|
||||
decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
|
||||
{
|
||||
int i;
|
||||
unsigned int min_ae = MAX_AE;
|
||||
|
||||
/* Reset indexes */
|
||||
decoder->o_idx = 0;
|
||||
decoder->p_idx = 0;
|
||||
|
||||
/* Initial error normalize (remove constant) */
|
||||
for (i=0; i<decoder->n_states; i++) {
|
||||
if (decoder->ae[i] < min_ae)
|
||||
min_ae = decoder->ae[i];
|
||||
}
|
||||
|
||||
for (i=0; i<decoder->n_states; i++)
|
||||
decoder->ae[i] -= min_ae;
|
||||
}
|
||||
|
||||
void
|
||||
osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
|
||||
{
|
||||
free(decoder->ae);
|
||||
free(decoder->ae_next);
|
||||
free(decoder->state_history);
|
||||
|
||||
memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
|
||||
const sbit_t *input, int n)
|
||||
{
|
||||
const struct osmo_conv_code *code = decoder->code;
|
||||
|
||||
int i, s, b, j;
|
||||
|
||||
int n_states;
|
||||
unsigned int *ae;
|
||||
unsigned int *ae_next;
|
||||
uint8_t *state_history;
|
||||
sbit_t *in_sym;
|
||||
|
||||
int i_idx, p_idx;
|
||||
|
||||
/* Prepare */
|
||||
n_states = decoder->n_states;
|
||||
|
||||
ae = decoder->ae;
|
||||
ae_next = decoder->ae_next;
|
||||
state_history = &decoder->state_history[n_states * decoder->o_idx];
|
||||
|
||||
in_sym = malloc(sizeof(sbit_t) * code->N);
|
||||
|
||||
i_idx = 0;
|
||||
p_idx = decoder->p_idx;
|
||||
|
||||
/* Scan the treillis */
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
/* Reset next accumulated error */
|
||||
for (s=0; s<n_states; s++) {
|
||||
ae_next[s] = MAX_AE;
|
||||
}
|
||||
|
||||
/* Get input */
|
||||
if (code->puncture) {
|
||||
/* Hard way ... */
|
||||
for (j=0; j<code->N; j++) {
|
||||
int idx = ((decoder->o_idx + i) * code->N) + j;
|
||||
if (idx == code->puncture[p_idx]) {
|
||||
in_sym[j] = 0; /* Undefined */
|
||||
p_idx++;
|
||||
} else {
|
||||
in_sym[j] = input[i_idx];
|
||||
i_idx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Easy, just copy N bits */
|
||||
memcpy(in_sym, &input[i_idx], code->N);
|
||||
i_idx += code->N;
|
||||
}
|
||||
|
||||
/* Scan all state */
|
||||
for (s=0; s<n_states; s++)
|
||||
{
|
||||
/* Scan possible input bits */
|
||||
for (b=0; b<2; b++)
|
||||
{
|
||||
int nae, ov, e;
|
||||
uint8_t m;
|
||||
|
||||
/* Next output and state */
|
||||
uint8_t out = code->next_output[s][b];
|
||||
uint8_t state = code->next_state[s][b];
|
||||
|
||||
/* New error for this path */
|
||||
nae = ae[s]; /* start from last error */
|
||||
m = 1 << (code->N - 1); /* mask for 'out' bit selection */
|
||||
|
||||
for (j=0; j<code->N; j++) {
|
||||
int is = (int)in_sym[j];
|
||||
if (is) {
|
||||
ov = (out & m) ? -127 : 127; /* sbit_t value for it */
|
||||
e = is - ov; /* raw error for this bit */
|
||||
nae += (e * e) >> 9; /* acc the squared/scaled value */
|
||||
}
|
||||
m >>= 1; /* next mask bit */
|
||||
}
|
||||
|
||||
/* Is it survivor ? */
|
||||
if (ae_next[state] > nae) {
|
||||
ae_next[state] = nae;
|
||||
state_history[(n_states * i) + state] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy accumulated error */
|
||||
memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
|
||||
}
|
||||
|
||||
/* Update decoder state */
|
||||
decoder->p_idx = p_idx;
|
||||
decoder->o_idx += n;
|
||||
|
||||
free(in_sym);
|
||||
return i_idx;
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
|
||||
const sbit_t *input)
|
||||
{
|
||||
const struct osmo_conv_code *code = decoder->code;
|
||||
|
||||
int i, s, j;
|
||||
|
||||
int n_states;
|
||||
unsigned int *ae;
|
||||
unsigned int *ae_next;
|
||||
uint8_t *state_history;
|
||||
sbit_t *in_sym;
|
||||
|
||||
int i_idx, p_idx;
|
||||
|
||||
/* Prepare */
|
||||
n_states = decoder->n_states;
|
||||
|
||||
ae = decoder->ae;
|
||||
ae_next = decoder->ae_next;
|
||||
state_history = &decoder->state_history[n_states * decoder->o_idx];
|
||||
|
||||
in_sym = malloc(sizeof(sbit_t) * code->N);
|
||||
|
||||
i_idx = 0;
|
||||
p_idx = decoder->p_idx;
|
||||
|
||||
/* Scan the treillis */
|
||||
for (i=0; i<code->K-1; i++)
|
||||
{
|
||||
/* Reset next accumulated error */
|
||||
for (s=0; s<n_states; s++) {
|
||||
ae_next[s] = MAX_AE;
|
||||
}
|
||||
|
||||
/* Get input */
|
||||
if (code->puncture) {
|
||||
/* Hard way ... */
|
||||
for (j=0; j<code->N; j++) {
|
||||
int idx = ((decoder->o_idx + i) * code->N) + j;
|
||||
if (idx == code->puncture[p_idx]) {
|
||||
in_sym[j] = 0; /* Undefined */
|
||||
p_idx++;
|
||||
} else {
|
||||
in_sym[j] = input[i_idx];
|
||||
i_idx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Easy, just copy N bits */
|
||||
memcpy(in_sym, &input[i_idx], code->N);
|
||||
i_idx += code->N;
|
||||
}
|
||||
|
||||
/* Scan all state */
|
||||
for (s=0; s<n_states; s++)
|
||||
{
|
||||
int nae, ov, e;
|
||||
uint8_t m;
|
||||
|
||||
/* Next output and state */
|
||||
uint8_t out;
|
||||
uint8_t state;
|
||||
|
||||
if (code->next_term_output) {
|
||||
out = code->next_term_output[s];
|
||||
state = code->next_term_state[s];
|
||||
} else {
|
||||
out = code->next_output[s][0];
|
||||
state = code->next_state[s][0];
|
||||
}
|
||||
|
||||
/* New error for this path */
|
||||
nae = ae[s]; /* start from last error */
|
||||
m = 1 << (code->N - 1); /* mask for 'out' bit selection */
|
||||
|
||||
for (j=0; j<code->N; j++) {
|
||||
int is = (int)in_sym[j];
|
||||
if (is) {
|
||||
ov = (out & m) ? -127 : 127; /* sbit_t value for it */
|
||||
e = is - ov; /* raw error for this bit */
|
||||
nae += (e * e) >> 9; /* acc the squared/scaled value */
|
||||
}
|
||||
m >>= 1; /* next mask bit */
|
||||
}
|
||||
|
||||
/* Is it survivor ? */
|
||||
if (ae_next[state] > nae) {
|
||||
ae_next[state] = nae;
|
||||
state_history[(n_states * i) + state] = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy accumulated error */
|
||||
memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
|
||||
}
|
||||
|
||||
/* Update decoder state */
|
||||
decoder->p_idx = p_idx;
|
||||
decoder->o_idx += code->K - 1;
|
||||
|
||||
free(in_sym);
|
||||
return i_idx;
|
||||
}
|
||||
|
||||
int
|
||||
osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
|
||||
ubit_t *output, int has_flush, int end_state)
|
||||
{
|
||||
const struct osmo_conv_code *code = decoder->code;
|
||||
|
||||
int min_ae;
|
||||
uint8_t min_state, cur_state;
|
||||
int i, s, n;
|
||||
|
||||
uint8_t *sh_ptr;
|
||||
|
||||
/* End state ? */
|
||||
if (end_state < 0) {
|
||||
/* Find state with least error */
|
||||
min_ae = MAX_AE;
|
||||
min_state = 0xff;
|
||||
|
||||
for (s=0; s<decoder->n_states; s++)
|
||||
{
|
||||
if (decoder->ae[s] < min_ae) {
|
||||
min_ae = decoder->ae[s];
|
||||
min_state = s;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_state == 0xff)
|
||||
return -1;
|
||||
} else {
|
||||
min_state = (uint8_t) end_state;
|
||||
min_ae = decoder->ae[end_state];
|
||||
}
|
||||
|
||||
/* Traceback */
|
||||
cur_state = min_state;
|
||||
|
||||
n = decoder->o_idx;
|
||||
|
||||
sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
|
||||
|
||||
/* No output for the K-1 termination input bits */
|
||||
if (has_flush) {
|
||||
for (i=0; i<code->K-1; i++) {
|
||||
cur_state = sh_ptr[cur_state];
|
||||
sh_ptr -= decoder->n_states;
|
||||
}
|
||||
n -= code->K - 1;
|
||||
}
|
||||
|
||||
/* Generate output backward */
|
||||
for (i=n-1; i>=0; i--)
|
||||
{
|
||||
min_state = cur_state;
|
||||
cur_state = sh_ptr[cur_state];
|
||||
|
||||
sh_ptr -= decoder->n_states;
|
||||
|
||||
if (code->next_state[cur_state][0] == min_state)
|
||||
output[i] = 0;
|
||||
else
|
||||
output[i] = 1;
|
||||
}
|
||||
|
||||
return min_ae;
|
||||
}
|
||||
|
||||
/*! All-in-one convolutional decoding function
|
||||
* \param[in] code description of convolutional code to be used
|
||||
* \param[in] input array of soft bits (coded)
|
||||
* \param[out] output array of unpacked bits (decoded)
|
||||
*
|
||||
* This is an all-in-one function, taking care of
|
||||
* \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
|
||||
* \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
|
||||
* \ref osmo_conv_decode_deinit.
|
||||
*/
|
||||
int
|
||||
osmo_conv_decode(const struct osmo_conv_code *code,
|
||||
const sbit_t *input, ubit_t *output)
|
||||
{
|
||||
struct osmo_conv_decoder decoder;
|
||||
int rv, l;
|
||||
|
||||
/* Use accelerated implementation for supported codes */
|
||||
if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
|
||||
return osmo_conv_decode_acc(code, input, output);
|
||||
|
||||
osmo_conv_decode_init(&decoder, code, 0, 0);
|
||||
|
||||
if (code->term == CONV_TERM_TAIL_BITING) {
|
||||
osmo_conv_decode_scan(&decoder, input, code->len);
|
||||
osmo_conv_decode_rewind(&decoder);
|
||||
}
|
||||
|
||||
l = osmo_conv_decode_scan(&decoder, input, code->len);
|
||||
|
||||
if (code->term == CONV_TERM_FLUSH)
|
||||
osmo_conv_decode_flush(&decoder, &input[l]);
|
||||
|
||||
rv = osmo_conv_decode_get_output(&decoder, output,
|
||||
code->term == CONV_TERM_FLUSH, /* has_flush */
|
||||
code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
|
||||
);
|
||||
|
||||
osmo_conv_decode_deinit(&decoder);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,139 +0,0 @@
|
|||
/*! \file conv.h
|
||||
* Osmocom convolutional encoder and decoder. */
|
||||
/*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \defgroup conv Convolutional encoding and decoding routines
|
||||
* @{
|
||||
* \file conv.h */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
/*! possibe termination types
|
||||
*
|
||||
* The termination type will determine which state the encoder/decoder
|
||||
* can start/end with. This is mostly taken care of in the high level API
|
||||
* call. So if you use the low level API, you must take care of making the
|
||||
* proper calls yourself.
|
||||
*/
|
||||
enum osmo_conv_term {
|
||||
CONV_TERM_FLUSH = 0, /*!< Flush encoder state */
|
||||
CONV_TERM_TRUNCATION, /*!< Direct truncation */
|
||||
CONV_TERM_TAIL_BITING, /*!< Tail biting */
|
||||
};
|
||||
|
||||
/*! structure describing a given convolutional code
|
||||
*
|
||||
* The only required fields are N,K and the next_output/next_state arrays. The
|
||||
* other can be left to default value of zero depending on what the code does.
|
||||
* If 'len' is left at 0 then only the low level API can be used.
|
||||
*/
|
||||
struct osmo_conv_code {
|
||||
int N; /*!< Inverse of code rate */
|
||||
int K; /*!< Constraint length */
|
||||
int len; /*!< # of data bits */
|
||||
|
||||
enum osmo_conv_term term; /*!< Termination type */
|
||||
|
||||
const uint8_t (*next_output)[2];/*!< Next output array */
|
||||
const uint8_t (*next_state)[2]; /*!< Next state array */
|
||||
|
||||
const uint8_t *next_term_output;/*!< Flush termination output */
|
||||
const uint8_t *next_term_state; /*!< Flush termination state */
|
||||
|
||||
const int *puncture; /*!< Punctured bits indexes */
|
||||
};
|
||||
|
||||
|
||||
/* Common */
|
||||
|
||||
int osmo_conv_get_input_length(const struct osmo_conv_code *code, int len);
|
||||
int osmo_conv_get_output_length(const struct osmo_conv_code *code, int len);
|
||||
|
||||
|
||||
/* Encoding */
|
||||
|
||||
/* Low level API */
|
||||
|
||||
/*! convolutional encoder state */
|
||||
struct osmo_conv_encoder {
|
||||
const struct osmo_conv_code *code; /*!< for which code? */
|
||||
int i_idx; /*!< Next input bit index */
|
||||
int p_idx; /*!< Current puncture index */
|
||||
uint8_t state; /*!< Current state */
|
||||
};
|
||||
|
||||
void osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
|
||||
const struct osmo_conv_code *code);
|
||||
void osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
|
||||
const ubit_t *input);
|
||||
int osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
|
||||
const ubit_t *input, ubit_t *output, int n);
|
||||
int osmo_conv_encode_flush(struct osmo_conv_encoder *encoder, ubit_t *output);
|
||||
|
||||
/* All-in-one */
|
||||
int osmo_conv_encode(const struct osmo_conv_code *code,
|
||||
const ubit_t *input, ubit_t *output);
|
||||
|
||||
|
||||
/* Decoding */
|
||||
|
||||
/* Low level API */
|
||||
|
||||
/*! convolutional decoder state */
|
||||
struct osmo_conv_decoder {
|
||||
const struct osmo_conv_code *code; /*!< for which code? */
|
||||
|
||||
int n_states; /*!< number of states */
|
||||
|
||||
int len; /*!< Max o_idx (excl. termination) */
|
||||
|
||||
int o_idx; /*!< output index */
|
||||
int p_idx; /*!< puncture index */
|
||||
|
||||
unsigned int *ae; /*!< accumulated error */
|
||||
unsigned int *ae_next; /*!< next accumulated error (tmp in scan) */
|
||||
uint8_t *state_history; /*!< state history [len][n_states] */
|
||||
};
|
||||
|
||||
void osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
|
||||
const struct osmo_conv_code *code,
|
||||
int len, int start_state);
|
||||
void osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state);
|
||||
void osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder);
|
||||
void osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder);
|
||||
|
||||
int osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
|
||||
const sbit_t *input, int n);
|
||||
int osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
|
||||
const sbit_t *input);
|
||||
int osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
|
||||
ubit_t *output, int has_flush, int end_state);
|
||||
|
||||
/* All-in-one */
|
||||
int osmo_conv_decode(const struct osmo_conv_code *code,
|
||||
const sbit_t *input, ubit_t *output);
|
||||
|
||||
|
||||
/*! @} */
|
|
@ -1,720 +0,0 @@
|
|||
/*! \file conv_acc.c
|
||||
* Accelerated Viterbi decoder implementation. */
|
||||
/*
|
||||
* Copyright (C) 2013, 2014 Thomas Tsou <tom@tsou.cc>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define __attribute__(_arg_)
|
||||
|
||||
#include <osmocom/core/conv.h>
|
||||
|
||||
#define BIT2NRZ(REG,N) (((REG >> N) & 0x01) * 2 - 1) * -1
|
||||
#define NUM_STATES(K) (K == 7 ? 64 : 16)
|
||||
|
||||
#define INIT_POINTERS(simd) \
|
||||
{ \
|
||||
osmo_conv_metrics_k5_n2 = osmo_conv_##simd##_metrics_k5_n2; \
|
||||
osmo_conv_metrics_k5_n3 = osmo_conv_##simd##_metrics_k5_n3; \
|
||||
osmo_conv_metrics_k5_n4 = osmo_conv_##simd##_metrics_k5_n4; \
|
||||
osmo_conv_metrics_k7_n2 = osmo_conv_##simd##_metrics_k7_n2; \
|
||||
osmo_conv_metrics_k7_n3 = osmo_conv_##simd##_metrics_k7_n3; \
|
||||
osmo_conv_metrics_k7_n4 = osmo_conv_##simd##_metrics_k7_n4; \
|
||||
vdec_malloc = &osmo_conv_##simd##_vdec_malloc; \
|
||||
vdec_free = &osmo_conv_##simd##_vdec_free; \
|
||||
}
|
||||
|
||||
static int init_complete = 0;
|
||||
|
||||
__attribute__ ((visibility("hidden"))) int avx2_supported = 0;
|
||||
__attribute__ ((visibility("hidden"))) int ssse3_supported = 0;
|
||||
__attribute__ ((visibility("hidden"))) int sse41_supported = 0;
|
||||
|
||||
/**
|
||||
* These pointers are being initialized at runtime by the
|
||||
* osmo_conv_init() depending on supported SIMD extensions.
|
||||
*/
|
||||
static int16_t *(*vdec_malloc)(size_t n);
|
||||
static void (*vdec_free)(int16_t *ptr);
|
||||
|
||||
void (*osmo_conv_metrics_k5_n2)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
void (*osmo_conv_metrics_k5_n3)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
void (*osmo_conv_metrics_k5_n4)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
void (*osmo_conv_metrics_k7_n2)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
void (*osmo_conv_metrics_k7_n3)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
void (*osmo_conv_metrics_k7_n4)(const int8_t *seq,
|
||||
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
|
||||
|
||||
/* Forward malloc wrappers */
|
||||
int16_t *osmo_conv_gen_vdec_malloc(size_t n);
|
||||
void osmo_conv_gen_vdec_free(int16_t *ptr);
|
||||
|
||||
#if defined(HAVE_SSSE3)
|
||||
int16_t *osmo_conv_sse_vdec_malloc(size_t n);
|
||||
void osmo_conv_sse_vdec_free(int16_t *ptr);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
|
||||
int16_t *osmo_conv_sse_avx_vdec_malloc(size_t n);
|
||||
void osmo_conv_sse_avx_vdec_free(int16_t *ptr);
|
||||
#endif
|
||||
|
||||
/* Forward Metric Units */
|
||||
void osmo_conv_gen_metrics_k5_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_gen_metrics_k5_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_gen_metrics_k5_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_gen_metrics_k7_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_gen_metrics_k7_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_gen_metrics_k7_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
|
||||
#if defined(HAVE_SSSE3)
|
||||
void osmo_conv_sse_metrics_k5_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_metrics_k5_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_metrics_k5_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_metrics_k7_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_metrics_k7_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_metrics_k7_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
|
||||
void osmo_conv_sse_avx_metrics_k5_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_avx_metrics_k5_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_avx_metrics_k5_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_avx_metrics_k7_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_avx_metrics_k7_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
void osmo_conv_sse_avx_metrics_k7_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm);
|
||||
#endif
|
||||
|
||||
/* Trellis State
|
||||
* state - Internal lshift register value
|
||||
* prev - Register values of previous 0 and 1 states
|
||||
*/
|
||||
struct vstate {
|
||||
unsigned state;
|
||||
unsigned prev[2];
|
||||
};
|
||||
|
||||
/* Trellis Object
|
||||
* num_states - Number of states in the trellis
|
||||
* sums - Accumulated path metrics
|
||||
* outputs - Trellis output values
|
||||
* vals - Input value that led to each state
|
||||
*/
|
||||
struct vtrellis {
|
||||
int num_states;
|
||||
int16_t *sums;
|
||||
int16_t *outputs;
|
||||
uint8_t *vals;
|
||||
};
|
||||
|
||||
/* Viterbi Decoder
|
||||
* n - Code order
|
||||
* k - Constraint length
|
||||
* len - Horizontal length of trellis
|
||||
* recursive - Set to '1' if the code is recursive
|
||||
* intrvl - Normalization interval
|
||||
* trellis - Trellis object
|
||||
* paths - Trellis paths
|
||||
*/
|
||||
struct vdecoder {
|
||||
int n;
|
||||
int k;
|
||||
int len;
|
||||
int recursive;
|
||||
int intrvl;
|
||||
struct vtrellis trellis;
|
||||
int16_t **paths;
|
||||
|
||||
void (*metric_func)(const int8_t *, const int16_t *,
|
||||
int16_t *, int16_t *, int);
|
||||
};
|
||||
|
||||
/* Accessor calls */
|
||||
static inline int conv_code_recursive(const struct osmo_conv_code *code)
|
||||
{
|
||||
return code->next_term_output ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Left shift and mask for finding the previous state */
|
||||
static unsigned vstate_lshift(unsigned reg, int k, int val)
|
||||
{
|
||||
unsigned mask;
|
||||
|
||||
if (k == 5)
|
||||
mask = 0x0e;
|
||||
else if (k == 7)
|
||||
mask = 0x3e;
|
||||
else
|
||||
mask = 0;
|
||||
|
||||
return ((reg << 1) & mask) | val;
|
||||
}
|
||||
|
||||
/* Bit endian manipulators */
|
||||
static inline unsigned bitswap2(unsigned v)
|
||||
{
|
||||
return ((v & 0x02) >> 1) | ((v & 0x01) << 1);
|
||||
}
|
||||
|
||||
static inline unsigned bitswap3(unsigned v)
|
||||
{
|
||||
return ((v & 0x04) >> 2) | ((v & 0x02) >> 0) |
|
||||
((v & 0x01) << 2);
|
||||
}
|
||||
|
||||
static inline unsigned bitswap4(unsigned v)
|
||||
{
|
||||
return ((v & 0x08) >> 3) | ((v & 0x04) >> 1) |
|
||||
((v & 0x02) << 1) | ((v & 0x01) << 3);
|
||||
}
|
||||
|
||||
static inline unsigned bitswap5(unsigned v)
|
||||
{
|
||||
return ((v & 0x10) >> 4) | ((v & 0x08) >> 2) | ((v & 0x04) >> 0) |
|
||||
((v & 0x02) << 2) | ((v & 0x01) << 4);
|
||||
}
|
||||
|
||||
static inline unsigned bitswap6(unsigned v)
|
||||
{
|
||||
return ((v & 0x20) >> 5) | ((v & 0x10) >> 3) | ((v & 0x08) >> 1) |
|
||||
((v & 0x04) << 1) | ((v & 0x02) << 3) | ((v & 0x01) << 5);
|
||||
}
|
||||
|
||||
static unsigned bitswap(unsigned v, unsigned n)
|
||||
{
|
||||
switch (n) {
|
||||
case 1:
|
||||
return v;
|
||||
case 2:
|
||||
return bitswap2(v);
|
||||
case 3:
|
||||
return bitswap3(v);
|
||||
case 4:
|
||||
return bitswap4(v);
|
||||
case 5:
|
||||
return bitswap5(v);
|
||||
case 6:
|
||||
return bitswap6(v);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate non-recursive state output from generator state table
|
||||
* Note that the shift register moves right (i.e. the most recent bit is
|
||||
* shifted into the register at k-1 bit of the register), which is typical
|
||||
* textbook representation. The API transition table expects the most recent
|
||||
* bit in the low order bit, or left shift. A bitswap operation is required
|
||||
* to accommodate the difference.
|
||||
*/
|
||||
static unsigned gen_output(struct vstate *state, int val,
|
||||
const struct osmo_conv_code *code)
|
||||
{
|
||||
unsigned out, prev;
|
||||
|
||||
prev = bitswap(state->prev[0], code->K - 1);
|
||||
out = code->next_output[prev][val];
|
||||
out = bitswap(out, code->N);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Populate non-recursive trellis state
|
||||
* For a given state defined by the k-1 length shift register, find the
|
||||
* value of the input bit that drove the trellis to that state. Also
|
||||
* generate the N outputs of the generator polynomial at that state.
|
||||
*/
|
||||
static int gen_state_info(uint8_t *val, unsigned reg,
|
||||
int16_t *output, const struct osmo_conv_code *code)
|
||||
{
|
||||
int i;
|
||||
unsigned out;
|
||||
struct vstate state;
|
||||
|
||||
/* Previous '0' state */
|
||||
state.state = reg;
|
||||
state.prev[0] = vstate_lshift(reg, code->K, 0);
|
||||
state.prev[1] = vstate_lshift(reg, code->K, 1);
|
||||
|
||||
*val = (reg >> (code->K - 2)) & 0x01;
|
||||
|
||||
/* Transition output */
|
||||
out = gen_output(&state, *val, code);
|
||||
|
||||
/* Unpack to NRZ */
|
||||
for (i = 0; i < code->N; i++)
|
||||
output[i] = BIT2NRZ(out, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate recursive state output from generator state table */
|
||||
static unsigned gen_recursive_output(struct vstate *state,
|
||||
uint8_t *val, unsigned reg,
|
||||
const struct osmo_conv_code *code, int pos)
|
||||
{
|
||||
int val0, val1;
|
||||
unsigned out, prev;
|
||||
|
||||
/* Previous '0' state */
|
||||
prev = vstate_lshift(reg, code->K, 0);
|
||||
prev = bitswap(prev, code->K - 1);
|
||||
|
||||
/* Input value */
|
||||
val0 = (reg >> (code->K - 2)) & 0x01;
|
||||
val1 = (code->next_term_output[prev] >> pos) & 0x01;
|
||||
*val = val0 == val1 ? 0 : 1;
|
||||
|
||||
/* Wrapper for osmocom state access */
|
||||
prev = bitswap(state->prev[0], code->K - 1);
|
||||
|
||||
/* Compute the transition output */
|
||||
out = code->next_output[prev][*val];
|
||||
out = bitswap(out, code->N);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Populate recursive trellis state
|
||||
* The bit position of the systematic bit is not explicitly marked by the
|
||||
* API, so it must be extracted from the generator table. Otherwise,
|
||||
* populate the trellis similar to the non-recursive version.
|
||||
* Non-systematic recursive codes are not supported.
|
||||
*/
|
||||
static int gen_recursive_state_info(uint8_t *val,
|
||||
unsigned reg, int16_t *output, const struct osmo_conv_code *code)
|
||||
{
|
||||
int i, j, pos = -1;
|
||||
int ns = NUM_STATES(code->K);
|
||||
unsigned out;
|
||||
struct vstate state;
|
||||
|
||||
/* Previous '0' and '1' states */
|
||||
state.state = reg;
|
||||
state.prev[0] = vstate_lshift(reg, code->K, 0);
|
||||
state.prev[1] = vstate_lshift(reg, code->K, 1);
|
||||
|
||||
/* Find recursive bit location */
|
||||
for (i = 0; i < code->N; i++) {
|
||||
for (j = 0; j < ns; j++) {
|
||||
if ((code->next_output[j][0] >> i) & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == ns) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-systematic recursive code not supported */
|
||||
if (pos < 0)
|
||||
return -EPROTO;
|
||||
|
||||
/* Transition output */
|
||||
out = gen_recursive_output(&state, val, reg, code, pos);
|
||||
|
||||
/* Unpack to NRZ */
|
||||
for (i = 0; i < code->N; i++)
|
||||
output[i] = BIT2NRZ(out, i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Release the trellis */
|
||||
static void free_trellis(struct vtrellis *trellis)
|
||||
{
|
||||
if (!trellis)
|
||||
return;
|
||||
|
||||
vdec_free(trellis->outputs);
|
||||
vdec_free(trellis->sums);
|
||||
free(trellis->vals);
|
||||
}
|
||||
|
||||
/* Initialize the trellis object
|
||||
* Initialization consists of generating the outputs and output value of a
|
||||
* given state. Due to trellis symmetry and anti-symmetry, only one of the
|
||||
* transition paths is utilized by the butterfly operation in the forward
|
||||
* recursion, so only one set of N outputs is required per state variable.
|
||||
*/
|
||||
static int generate_trellis(struct vdecoder *dec,
|
||||
const struct osmo_conv_code *code)
|
||||
{
|
||||
struct vtrellis *trellis = &dec->trellis;
|
||||
int16_t *outputs;
|
||||
int i, rc;
|
||||
|
||||
int ns = NUM_STATES(code->K);
|
||||
int olen = (code->N == 2) ? 2 : 4;
|
||||
|
||||
trellis->num_states = ns;
|
||||
trellis->sums = vdec_malloc(ns);
|
||||
trellis->outputs = vdec_malloc(ns * olen);
|
||||
trellis->vals = (uint8_t *) malloc(ns * sizeof(uint8_t));
|
||||
|
||||
if (!trellis->sums || !trellis->outputs || !trellis->vals) {
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Populate the trellis state objects */
|
||||
for (i = 0; i < ns; i++) {
|
||||
outputs = &trellis->outputs[olen * i];
|
||||
if (dec->recursive) {
|
||||
rc = gen_recursive_state_info(&trellis->vals[i],
|
||||
i, outputs, code);
|
||||
} else {
|
||||
rc = gen_state_info(&trellis->vals[i],
|
||||
i, outputs, code);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* Set accumulated path metrics to zero */
|
||||
trellis->sums[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For termination other than tail-biting, initialize the zero state
|
||||
* as the encoder starting state. Initialize with the maximum
|
||||
* accumulated sum at length equal to the constraint length.
|
||||
*/
|
||||
if (code->term != CONV_TERM_TAIL_BITING)
|
||||
trellis->sums[0] = INT8_MAX * code->N * code->K;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free_trellis(trellis);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void _traceback(struct vdecoder *dec,
|
||||
unsigned state, uint8_t *out, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned path;
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
path = dec->paths[i][state] + 1;
|
||||
out[i] = dec->trellis.vals[state];
|
||||
state = vstate_lshift(state, dec->k, path);
|
||||
}
|
||||
}
|
||||
|
||||
static void _traceback_rec(struct vdecoder *dec,
|
||||
unsigned state, uint8_t *out, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned path;
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
path = dec->paths[i][state] + 1;
|
||||
out[i] = path ^ dec->trellis.vals[state];
|
||||
state = vstate_lshift(state, dec->k, path);
|
||||
}
|
||||
}
|
||||
|
||||
/* Traceback and generate decoded output
|
||||
* Find the largest accumulated path metric at the final state except for
|
||||
* the zero terminated case, where we assume the final state is always zero.
|
||||
*/
|
||||
static int traceback(struct vdecoder *dec, uint8_t *out, int term, int len)
|
||||
{
|
||||
int i, sum, max = -1;
|
||||
unsigned path, state = 0;
|
||||
|
||||
if (term != CONV_TERM_FLUSH) {
|
||||
for (i = 0; i < dec->trellis.num_states; i++) {
|
||||
sum = dec->trellis.sums[i];
|
||||
if (sum > max) {
|
||||
max = sum;
|
||||
state = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (max < 0)
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
for (i = dec->len - 1; i >= len; i--) {
|
||||
path = dec->paths[i][state] + 1;
|
||||
state = vstate_lshift(state, dec->k, path);
|
||||
}
|
||||
|
||||
if (dec->recursive)
|
||||
_traceback_rec(dec, state, out, len);
|
||||
else
|
||||
_traceback(dec, state, out, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Release decoder object */
|
||||
static void vdec_deinit(struct vdecoder *dec)
|
||||
{
|
||||
if (!dec)
|
||||
return;
|
||||
|
||||
free_trellis(&dec->trellis);
|
||||
|
||||
if (dec->paths != NULL) {
|
||||
vdec_free(dec->paths[0]);
|
||||
free(dec->paths);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize decoder object with code specific params
|
||||
* Subtract the constraint length K on the normalization interval to
|
||||
* accommodate the initialization path metric at state zero.
|
||||
*/
|
||||
static int vdec_init(struct vdecoder *dec, const struct osmo_conv_code *code)
|
||||
{
|
||||
int i, ns, rc;
|
||||
|
||||
ns = NUM_STATES(code->K);
|
||||
|
||||
dec->n = code->N;
|
||||
dec->k = code->K;
|
||||
dec->recursive = conv_code_recursive(code);
|
||||
dec->intrvl = INT16_MAX / (dec->n * INT8_MAX) - dec->k;
|
||||
|
||||
if (dec->k == 5) {
|
||||
switch (dec->n) {
|
||||
case 2:
|
||||
dec->metric_func = osmo_conv_metrics_k5_n2;
|
||||
break;
|
||||
case 3:
|
||||
dec->metric_func = osmo_conv_metrics_k5_n3;
|
||||
break;
|
||||
case 4:
|
||||
dec->metric_func = osmo_conv_metrics_k5_n4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (dec->k == 7) {
|
||||
switch (dec->n) {
|
||||
case 2:
|
||||
dec->metric_func = osmo_conv_metrics_k7_n2;
|
||||
break;
|
||||
case 3:
|
||||
dec->metric_func = osmo_conv_metrics_k7_n3;
|
||||
break;
|
||||
case 4:
|
||||
dec->metric_func = osmo_conv_metrics_k7_n4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (code->term == CONV_TERM_FLUSH)
|
||||
dec->len = code->len + code->K - 1;
|
||||
else
|
||||
dec->len = code->len;
|
||||
|
||||
rc = generate_trellis(dec, code);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dec->paths = (int16_t **) malloc(sizeof(int16_t *) * dec->len);
|
||||
if (!dec->paths)
|
||||
goto enomem;
|
||||
|
||||
dec->paths[0] = vdec_malloc(ns * dec->len);
|
||||
if (!dec->paths[0])
|
||||
goto enomem;
|
||||
|
||||
for (i = 1; i < dec->len; i++)
|
||||
dec->paths[i] = &dec->paths[0][i * ns];
|
||||
|
||||
return 0;
|
||||
|
||||
enomem:
|
||||
vdec_deinit(dec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Depuncture sequence with nagative value terminated puncturing matrix */
|
||||
static int depuncture(const int8_t *in, const int *punc, int8_t *out, int len)
|
||||
{
|
||||
int i, n = 0, m = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i == punc[n]) {
|
||||
out[i] = 0;
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
out[i] = in[m++];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward trellis recursion
|
||||
* Generate branch metrics and path metrics with a combined function. Only
|
||||
* accumulated path metric sums and path selections are stored. Normalize on
|
||||
* the interval specified by the decoder.
|
||||
*/
|
||||
static void forward_traverse(struct vdecoder *dec, const int8_t *seq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dec->len; i++) {
|
||||
dec->metric_func(&seq[dec->n * i],
|
||||
dec->trellis.outputs,
|
||||
dec->trellis.sums,
|
||||
dec->paths[i],
|
||||
!(i % dec->intrvl));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convolutional decode with a decoder object
|
||||
* Initial puncturing run if necessary followed by the forward recursion.
|
||||
* For tail-biting perform a second pass before running the backward
|
||||
* traceback operation.
|
||||
*/
|
||||
static int conv_decode(struct vdecoder *dec, const int8_t *seq,
|
||||
const int *punc, uint8_t *out, int len, int term)
|
||||
{
|
||||
//int8_t depunc[dec->len * dec->n]; //!! this isn't portable, in strict C you can't use size of an array that is not known at compile time
|
||||
int8_t * depunc = malloc(sizeof(int8_t)*dec->len * dec->n);
|
||||
|
||||
|
||||
if (punc) {
|
||||
depuncture(seq, punc, depunc, dec->len * dec->n);
|
||||
seq = depunc;
|
||||
}
|
||||
|
||||
/* Propagate through the trellis with interval normalization */
|
||||
forward_traverse(dec, seq);
|
||||
|
||||
if (term == CONV_TERM_TAIL_BITING)
|
||||
forward_traverse(dec, seq);
|
||||
|
||||
free(depunc);
|
||||
return traceback(dec, out, term, len);
|
||||
}
|
||||
|
||||
static void osmo_conv_init(void)
|
||||
{
|
||||
init_complete = 1;
|
||||
|
||||
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
|
||||
/* Detect CPU capabilities */
|
||||
#ifdef HAVE_AVX2
|
||||
avx2_supported = __builtin_cpu_supports("avx2");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSSE3
|
||||
ssse3_supported = __builtin_cpu_supports("ssse3");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSE4_1
|
||||
sse41_supported = __builtin_cpu_supports("sse4.1");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Usage of curly braces is mandatory,
|
||||
* because we use multi-line define.
|
||||
*/
|
||||
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
|
||||
if (ssse3_supported && avx2_supported) {
|
||||
INIT_POINTERS(sse_avx);
|
||||
} else if (ssse3_supported) {
|
||||
INIT_POINTERS(sse);
|
||||
} else {
|
||||
INIT_POINTERS(gen);
|
||||
}
|
||||
#elif defined(HAVE_SSSE3)
|
||||
if (ssse3_supported) {
|
||||
INIT_POINTERS(sse);
|
||||
} else {
|
||||
INIT_POINTERS(gen);
|
||||
}
|
||||
#else
|
||||
INIT_POINTERS(gen);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* All-in-one Viterbi decoding */
|
||||
int osmo_conv_decode_acc(const struct osmo_conv_code *code,
|
||||
const sbit_t *input, ubit_t *output)
|
||||
{
|
||||
int rc;
|
||||
struct vdecoder dec;
|
||||
|
||||
if (!init_complete)
|
||||
osmo_conv_init();
|
||||
|
||||
if ((code->N < 2) || (code->N > 4) || (code->len < 1) ||
|
||||
((code->K != 5) && (code->K != 7)))
|
||||
return -EINVAL;
|
||||
|
||||
rc = vdec_init(&dec, code);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = conv_decode(&dec, input, code->puncture,
|
||||
output, code->len, code->term);
|
||||
|
||||
vdec_deinit(&dec);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
/*! \file conv_acc_generic.c
|
||||
* Accelerated Viterbi decoder implementation
|
||||
* for generic architectures without SSE support. */
|
||||
/*
|
||||
* Copyright (C) 2013, 2014 Thomas Tsou <tom@tsou.cc>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __attribute__(_arg_)
|
||||
|
||||
/* Add-Compare-Select (ACS-Butterfly)
|
||||
* Compute 4 accumulated path metrics and 4 path selections. Note that path
|
||||
* selections are store as -1 and 0 rather than 0 and 1. This is to match
|
||||
* the output format of the SSE packed compare instruction 'pmaxuw'.
|
||||
*/
|
||||
|
||||
static void acs_butterfly(int state, int num_states,
|
||||
int16_t metric, int16_t *sum,
|
||||
int16_t *new_sum, int16_t *path)
|
||||
{
|
||||
int state0, state1;
|
||||
int sum0, sum1, sum2, sum3;
|
||||
|
||||
state0 = *(sum + (2 * state + 0));
|
||||
state1 = *(sum + (2 * state + 1));
|
||||
|
||||
sum0 = state0 + metric;
|
||||
sum1 = state1 - metric;
|
||||
sum2 = state0 - metric;
|
||||
sum3 = state1 + metric;
|
||||
|
||||
if (sum0 >= sum1) {
|
||||
*new_sum = sum0;
|
||||
*path = -1;
|
||||
} else {
|
||||
*new_sum = sum1;
|
||||
*path = 0;
|
||||
}
|
||||
|
||||
if (sum2 >= sum3) {
|
||||
*(new_sum + num_states / 2) = sum2;
|
||||
*(path + num_states / 2) = -1;
|
||||
} else {
|
||||
*(new_sum + num_states / 2) = sum3;
|
||||
*(path + num_states / 2) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Branch metrics unit N=2 */
|
||||
static void gen_branch_metrics_n2(int num_states, const int8_t *seq,
|
||||
const int16_t *out, int16_t *metrics)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_states / 2; i++) {
|
||||
metrics[i] = seq[0] * out[2 * i + 0] +
|
||||
seq[1] * out[2 * i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Branch metrics unit N=3 */
|
||||
static void gen_branch_metrics_n3(int num_states, const int8_t *seq,
|
||||
const int16_t *out, int16_t *metrics)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_states / 2; i++) {
|
||||
metrics[i] = seq[0] * out[4 * i + 0] +
|
||||
seq[1] * out[4 * i + 1] +
|
||||
seq[2] * out[4 * i + 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Branch metrics unit N=4 */
|
||||
static void gen_branch_metrics_n4(int num_states, const int8_t *seq,
|
||||
const int16_t *out, int16_t *metrics)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_states / 2; i++) {
|
||||
metrics[i] = seq[0] * out[4 * i + 0] +
|
||||
seq[1] * out[4 * i + 1] +
|
||||
seq[2] * out[4 * i + 2] +
|
||||
seq[3] * out[4 * i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
/* Path metric unit */
|
||||
static void gen_path_metrics(int num_states, int16_t *sums,
|
||||
int16_t *metrics, int16_t *paths, int norm)
|
||||
{
|
||||
int i;
|
||||
int16_t min;
|
||||
int16_t * new_sums = malloc(sizeof(int16_t)*num_states);
|
||||
|
||||
for (i = 0; i < num_states / 2; i++)
|
||||
acs_butterfly(i, num_states, metrics[i],
|
||||
sums, &new_sums[i], &paths[i]);
|
||||
|
||||
if (norm) {
|
||||
min = new_sums[0];
|
||||
|
||||
for (i = 1; i < num_states; i++)
|
||||
if (new_sums[i] < min)
|
||||
min = new_sums[i];
|
||||
|
||||
for (i = 0; i < num_states; i++)
|
||||
new_sums[i] -= min;
|
||||
}
|
||||
|
||||
memcpy(sums, new_sums, num_states * sizeof(int16_t));
|
||||
free(new_sums);
|
||||
|
||||
}
|
||||
|
||||
/* Not-aligned Memory Allocator */
|
||||
__attribute__ ((visibility("hidden")))
|
||||
int16_t *osmo_conv_gen_vdec_malloc(size_t n)
|
||||
{
|
||||
return (int16_t *) malloc(sizeof(int16_t) * n);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_vdec_free(int16_t *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/* 16-state branch-path metrics units (K=5) */
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k5_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[8];
|
||||
|
||||
gen_branch_metrics_n2(16, seq, out, metrics);
|
||||
gen_path_metrics(16, sums, metrics, paths, norm);
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k5_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[8];
|
||||
|
||||
gen_branch_metrics_n3(16, seq, out, metrics);
|
||||
gen_path_metrics(16, sums, metrics, paths, norm);
|
||||
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k5_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[8];
|
||||
|
||||
gen_branch_metrics_n4(16, seq, out, metrics);
|
||||
gen_path_metrics(16, sums, metrics, paths, norm);
|
||||
|
||||
}
|
||||
|
||||
/* 64-state branch-path metrics units (K=7) */
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k7_n2(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[32];
|
||||
|
||||
gen_branch_metrics_n2(64, seq, out, metrics);
|
||||
gen_path_metrics(64, sums, metrics, paths, norm);
|
||||
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k7_n3(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[32];
|
||||
|
||||
gen_branch_metrics_n3(64, seq, out, metrics);
|
||||
gen_path_metrics(64, sums, metrics, paths, norm);
|
||||
|
||||
}
|
||||
|
||||
__attribute__ ((visibility("hidden")))
|
||||
void osmo_conv_gen_metrics_k7_n4(const int8_t *seq, const int16_t *out,
|
||||
int16_t *sums, int16_t *paths, int norm)
|
||||
{
|
||||
int16_t metrics[32];
|
||||
|
||||
gen_branch_metrics_n4(64, seq, out, metrics);
|
||||
gen_path_metrics(64, sums, metrics, paths, norm);
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* crc16gen.c
|
||||
*
|
||||
* Generic CRC routines (for max 16 bits poly)
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc16gen.c
|
||||
* Osmocom generic CRC routines (for max 16 bits poly)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/crc16gen.h>
|
||||
|
||||
|
||||
/*! \brief Compute the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \returns The CRC value
|
||||
*/
|
||||
uint16_t
|
||||
osmo_crc16gen_compute_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len)
|
||||
{
|
||||
const uint16_t poly = code->poly;
|
||||
uint16_t crc = code->init;
|
||||
int i, n = code->bits-1;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
uint16_t bit = in[i] & 1;
|
||||
crc ^= (bit << n);
|
||||
if (crc & ((uint16_t)1 << n)) {
|
||||
crc <<= 1;
|
||||
crc ^= poly;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
crc &= ((uint16_t)1 << code->bits) - 1;
|
||||
}
|
||||
|
||||
crc ^= code->remainder;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Checks the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits with the alleged CRC
|
||||
* \returns 0 if CRC matches. 1 in case of error.
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
int
|
||||
osmo_crc16gen_check_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits)
|
||||
{
|
||||
uint16_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc16gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Computes and writes the CRC value of a given array of bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits to write the computed CRC to
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
void
|
||||
osmo_crc16gen_set_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits)
|
||||
{
|
||||
uint16_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc16gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* crc16gen.h
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc16gen.h
|
||||
* Osmocom generic CRC routines (for max 16 bits poly) header
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
|
||||
/*! \brief structure describing a given CRC code of max 16 bits */
|
||||
struct osmo_crc16gen_code {
|
||||
int bits; /*!< \brief Actual number of bits of the CRC */
|
||||
uint16_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
|
||||
uint16_t init; /*!< \brief Initialization value of the CRC state */
|
||||
uint16_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
|
||||
};
|
||||
|
||||
uint16_t osmo_crc16gen_compute_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len);
|
||||
int osmo_crc16gen_check_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits);
|
||||
void osmo_crc16gen_set_bits(const struct osmo_crc16gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits);
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* crc32gen.h
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc32gen.h
|
||||
* Osmocom generic CRC routines (for max 32 bits poly) header
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
|
||||
/*! \brief structure describing a given CRC code of max 32 bits */
|
||||
struct osmo_crc32gen_code {
|
||||
int bits; /*!< \brief Actual number of bits of the CRC */
|
||||
uint32_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
|
||||
uint32_t init; /*!< \brief Initialization value of the CRC state */
|
||||
uint32_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
|
||||
};
|
||||
|
||||
uint32_t osmo_crc32gen_compute_bits(const struct osmo_crc32gen_code *code,
|
||||
const ubit_t *in, int len);
|
||||
int osmo_crc32gen_check_bits(const struct osmo_crc32gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits);
|
||||
void osmo_crc32gen_set_bits(const struct osmo_crc32gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits);
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* crc64gen.c
|
||||
*
|
||||
* Generic CRC routines (for max 64 bits poly)
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc64gen.c
|
||||
* Osmocom generic CRC routines (for max 64 bits poly)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/crc64gen.h>
|
||||
|
||||
|
||||
/*! \brief Compute the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \returns The CRC value
|
||||
*/
|
||||
uint64_t
|
||||
osmo_crc64gen_compute_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len)
|
||||
{
|
||||
const uint64_t poly = code->poly;
|
||||
uint64_t crc = code->init;
|
||||
int i, n = code->bits-1;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
uint64_t bit = in[i] & 1;
|
||||
crc ^= (bit << n);
|
||||
if (crc & ((uint64_t)1 << n)) {
|
||||
crc <<= 1;
|
||||
crc ^= poly;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
crc &= ((uint64_t)1 << code->bits) - 1;
|
||||
}
|
||||
|
||||
crc ^= code->remainder;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Checks the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits with the alleged CRC
|
||||
* \returns 0 if CRC matches. 1 in case of error.
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
int
|
||||
osmo_crc64gen_check_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits)
|
||||
{
|
||||
uint64_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc64gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Computes and writes the CRC value of a given array of bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits to write the computed CRC to
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
void
|
||||
osmo_crc64gen_set_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits)
|
||||
{
|
||||
uint64_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc64gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* crc64gen.h
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc64gen.h
|
||||
* Osmocom generic CRC routines (for max 64 bits poly) header
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
|
||||
/*! \brief structure describing a given CRC code of max 64 bits */
|
||||
struct osmo_crc64gen_code {
|
||||
int bits; /*!< \brief Actual number of bits of the CRC */
|
||||
uint64_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
|
||||
uint64_t init; /*!< \brief Initialization value of the CRC state */
|
||||
uint64_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
|
||||
};
|
||||
|
||||
uint64_t osmo_crc64gen_compute_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len);
|
||||
int osmo_crc64gen_check_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits);
|
||||
void osmo_crc64gen_set_bits(const struct osmo_crc64gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits);
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* crc8gen.c
|
||||
*
|
||||
* Generic CRC routines (for max 8 bits poly)
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc8gen.c
|
||||
* Osmocom generic CRC routines (for max 8 bits poly)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/core/crc8gen.h>
|
||||
|
||||
|
||||
/*! \brief Compute the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \returns The CRC value
|
||||
*/
|
||||
uint8_t
|
||||
osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len)
|
||||
{
|
||||
const uint8_t poly = code->poly;
|
||||
uint8_t crc = code->init;
|
||||
int i, n = code->bits-1;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
uint8_t bit = in[i] & 1;
|
||||
crc ^= (bit << n);
|
||||
if (crc & ((uint8_t)1 << n)) {
|
||||
crc <<= 1;
|
||||
crc ^= poly;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
crc &= ((uint8_t)1 << code->bits) - 1;
|
||||
}
|
||||
|
||||
crc ^= code->remainder;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Checks the CRC value of a given array of hard-bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits with the alleged CRC
|
||||
* \returns 0 if CRC matches. 1 in case of error.
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
int
|
||||
osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits)
|
||||
{
|
||||
uint8_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc8gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Computes and writes the CRC value of a given array of bits
|
||||
* \param[in] code The CRC code description to apply
|
||||
* \param[in] in Array of hard bits
|
||||
* \param[in] len Length of the array of hard bits
|
||||
* \param[in] crc_bits Array of hard bits to write the computed CRC to
|
||||
*
|
||||
* The crc_bits array must have a length of code->len
|
||||
*/
|
||||
void
|
||||
osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits)
|
||||
{
|
||||
uint8_t crc;
|
||||
int i;
|
||||
|
||||
crc = osmo_crc8gen_compute_bits(code, in, len);
|
||||
|
||||
for (i=0; i<code->bits; i++)
|
||||
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* crc8gen.h
|
||||
*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \addtogroup crcgen
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \file crc8gen.h
|
||||
* Osmocom generic CRC routines (for max 8 bits poly) header
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
|
||||
/*! \brief structure describing a given CRC code of max 8 bits */
|
||||
struct osmo_crc8gen_code {
|
||||
int bits; /*!< \brief Actual number of bits of the CRC */
|
||||
uint8_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
|
||||
uint8_t init; /*!< \brief Initialization value of the CRC state */
|
||||
uint8_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
|
||||
};
|
||||
|
||||
uint8_t osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len);
|
||||
int osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len, const ubit_t *crc_bits);
|
||||
void osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
|
||||
const ubit_t *in, int len, ubit_t *crc_bits);
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* vim: set syntax=c: */
|
|
@ -1,34 +0,0 @@
|
|||
/*! \file crcgen.h
|
||||
* Osmocom generic CRC routines global header. */
|
||||
/*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \defgroup crc Osmocom CRC routines
|
||||
* @{
|
||||
* \file crcgen.h */
|
||||
|
||||
#include <osmocom/core/crc8gen.h>
|
||||
#include <osmocom/core/crc16gen.h>
|
||||
#include <osmocom/core/crc32gen.h>
|
||||
#include <osmocom/core/crc64gen.h>
|
||||
|
||||
/*! @} */
|
|
@ -1,53 +0,0 @@
|
|||
/*! \file defs.h
|
||||
* General definitions that are meant to be included from header files.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \defgroup utils General-purpose utility functions
|
||||
* @{
|
||||
* \file defs.h */
|
||||
|
||||
/*! Check for gcc and version.
|
||||
*
|
||||
* \note Albeit glibc provides a features.h file that contains a similar
|
||||
* definition (__GNUC_PREREQ), this definition has been copied from there
|
||||
* to have it available with other libraries, too.
|
||||
*
|
||||
* \return != 0 iff gcc is used and it's version is at least maj.min.
|
||||
*/
|
||||
#if defined __GNUC__ && defined __GNUC_MINOR__
|
||||
# define OSMO_GNUC_PREREQ(maj, min) \
|
||||
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||
#else
|
||||
# define OSMO_GNUC_PREREQ(maj, min) 0
|
||||
#endif
|
||||
|
||||
/*! Set the deprecated attribute with a message.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED __has_attribute(deprecated)
|
||||
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE __has_extension(attribute_deprecated_with_message)
|
||||
#elif defined(__GNUC__)
|
||||
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED 1
|
||||
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE OSMO_GNUC_PREREQ(4,5)
|
||||
#endif
|
||||
|
||||
#if _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
|
||||
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__(text)))
|
||||
#elif _OSMO_HAS_ATTRIBUTE_DEPRECATED
|
||||
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__))
|
||||
#else
|
||||
# define OSMO_DEPRECATED(text)
|
||||
#endif
|
||||
|
||||
#if BUILDING_LIBOSMOCORE
|
||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE
|
||||
#else
|
||||
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE OSMO_DEPRECATED("For internal use inside libosmocore only.")
|
||||
#endif
|
||||
|
||||
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
|
||||
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED
|
||||
|
||||
/*! @} */
|
|
@ -1,62 +0,0 @@
|
|||
/*! \file endian.h
|
||||
*
|
||||
* GNU and FreeBSD have various ways to express the
|
||||
* endianess but none of them is similiar enough. This
|
||||
* will create two defines that allows to decide on the
|
||||
* endian. The following will be defined to either 0 or
|
||||
* 1 at the end of the file.
|
||||
*
|
||||
* OSMO_IS_LITTLE_ENDIAN
|
||||
* OSMO_IS_BIG_ENDIAN
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define OSMO_IS_LITTLE_ENDIAN 1
|
||||
#define OSMO_IS_BIG_ENDIAN 0
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define OSMO_IS_LITTLE_ENDIAN 0
|
||||
#define OSMO_IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#error "Unknown endian"
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#include <machine/endian.h>
|
||||
#if defined(__DARWIN_LITTLE_ENDIAN)
|
||||
#define OSMO_IS_LITTLE_ENDIAN 1
|
||||
#define OSMO_IS_BIG_ENDIAN 0
|
||||
#elif defined(__DARWIN_BIG_ENDIAN)
|
||||
#define OSMO_IS_LITTLE_ENDIAN 0
|
||||
#define OSMO_IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#error "Unknown endian"
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#include <endian.h>
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define OSMO_IS_LITTLE_ENDIAN 1
|
||||
#define OSMO_IS_BIG_ENDIAN 0
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define OSMO_IS_LITTLE_ENDIAN 0
|
||||
#define OSMO_IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#error "Unknown endian"
|
||||
#endif
|
||||
#else
|
||||
/* let's try to rely on the compiler. GCC and CLANG/LLVM seem
|
||||
* to support this ... */
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define OSMO_IS_LITTLE_ENDIAN 1
|
||||
#define OSMO_IS_BIG_ENDIAN 0
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define OSMO_IS_LITTLE_ENDIAN 0
|
||||
#define OSMO_IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#error "Unknown endian"
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,409 +0,0 @@
|
|||
/*! \file linuxlist.h
|
||||
*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole llists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \defgroup linuxlist Simple doubly linked list implementation
|
||||
* @{
|
||||
* \file linuxlist.h */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
||||
# define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifndef inline
|
||||
# ifndef __WINDOWS__
|
||||
# define inline __inline__
|
||||
# else
|
||||
# define inline __inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static inline void prefetch(const void *x) {;}
|
||||
|
||||
/*! cast a member of a structure out to the containing structure
|
||||
*
|
||||
* \param[in] ptr the pointer to the member.
|
||||
* \param[in] type the type of the container struct this is embedded in.
|
||||
* \param[in] member the name of the member within the struct.
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type, member) );})
|
||||
|
||||
|
||||
/*!
|
||||
* These are non-NULL pointers that will result in page faults
|
||||
* under normal circumstances, used to verify that nobody uses
|
||||
* non-initialized llist entries.
|
||||
*/
|
||||
#define LLIST_POISON1 ((void *) 0x00100100)
|
||||
#define LLIST_POISON2 ((void *) 0x00200200)
|
||||
|
||||
/*! (double) linked list header structure */
|
||||
struct llist_head {
|
||||
/*! Pointer to next and previous item */
|
||||
struct llist_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LLIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
/*! define a statically-initialized \ref llist_head
|
||||
* \param[in] name Variable name
|
||||
*
|
||||
* This is a helper macro that will define a named variable of type
|
||||
* \ref llist_head and initialize it */
|
||||
#define LLIST_HEAD(name) \
|
||||
struct llist_head name = LLIST_HEAD_INIT(name)
|
||||
|
||||
/*! initialize a \ref llist_head to point back to self */
|
||||
#define INIT_LLIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*! Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal llist manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __llist_add(struct llist_head *_new,
|
||||
struct llist_head *prev,
|
||||
struct llist_head *next)
|
||||
{
|
||||
next->prev = _new;
|
||||
_new->next = next;
|
||||
_new->prev = prev;
|
||||
prev->next = _new;
|
||||
}
|
||||
|
||||
/*! add a new entry into a linked list (at head)
|
||||
* \param _new New entry to be added
|
||||
* \param head \ref llist_head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void llist_add(struct llist_head *_new, struct llist_head *head)
|
||||
{
|
||||
__llist_add(_new, head, head->next);
|
||||
}
|
||||
|
||||
/*! add a new entry into a linked list (at tail)
|
||||
* \param _new New entry to be added
|
||||
* \param head Head of linked list to whose tail we shall add \a _new
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
|
||||
{
|
||||
__llist_add(_new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a llist entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal llist manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/*! Delete entry from linked list
|
||||
* \param entry The element to delete from the llist
|
||||
*
|
||||
* Note: llist_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void llist_del(struct llist_head *entry)
|
||||
{
|
||||
__llist_del(entry->prev, entry->next);
|
||||
entry->next = (struct llist_head *)LLIST_POISON1;
|
||||
entry->prev = (struct llist_head *)LLIST_POISON2;
|
||||
}
|
||||
|
||||
/*! Delete entry from linked list and reinitialize it
|
||||
* \param entry The element to delete from the list
|
||||
*/
|
||||
static inline void llist_del_init(struct llist_head *entry)
|
||||
{
|
||||
__llist_del(entry->prev, entry->next);
|
||||
INIT_LLIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/*! Delete from one llist and add as another's head
|
||||
* \param llist The entry to move
|
||||
* \param head The head that will precede our entry
|
||||
*/
|
||||
static inline void llist_move(struct llist_head *llist, struct llist_head *head)
|
||||
{
|
||||
__llist_del(llist->prev, llist->next);
|
||||
llist_add(llist, head);
|
||||
}
|
||||
|
||||
/*! Delete from one llist and add as another's tail
|
||||
* \param llist The entry to move
|
||||
* \param head The head that will follow our entry
|
||||
*/
|
||||
static inline void llist_move_tail(struct llist_head *llist,
|
||||
struct llist_head *head)
|
||||
{
|
||||
__llist_del(llist->prev, llist->next);
|
||||
llist_add_tail(llist, head);
|
||||
}
|
||||
|
||||
/*! Test whether a linked list is empty
|
||||
* \param[in] head The llist to test.
|
||||
* \returns 1 if the list is empty, 0 otherwise
|
||||
*/
|
||||
static inline int llist_empty(const struct llist_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void __llist_splice(struct llist_head *llist,
|
||||
struct llist_head *head)
|
||||
{
|
||||
struct llist_head *first = llist->next;
|
||||
struct llist_head *last = llist->prev;
|
||||
struct llist_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/*! Join two llists
|
||||
* \param llist The new linked list to add
|
||||
* \param head The place to add \a llist in the other list
|
||||
*/
|
||||
static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
|
||||
{
|
||||
if (!llist_empty(llist))
|
||||
__llist_splice(llist, head);
|
||||
}
|
||||
|
||||
/*! join two llists and reinitialise the emptied llist.
|
||||
* \param llist The new linked list to add.
|
||||
* \param head The place to add it in the first llist.
|
||||
*
|
||||
* The llist at @llist is reinitialised
|
||||
*/
|
||||
static inline void llist_splice_init(struct llist_head *llist,
|
||||
struct llist_head *head)
|
||||
{
|
||||
if (!llist_empty(llist)) {
|
||||
__llist_splice(llist, head);
|
||||
INIT_LLIST_HEAD(llist);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Get the struct containing this list entry
|
||||
* \param ptr The \ref llist_head pointer
|
||||
* \param type The type of the struct this is embedded in
|
||||
* \param @member The name of the \ref llist_head within the struct
|
||||
*/
|
||||
#define llist_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/*! Get the first element from a list
|
||||
* \param ptr the list head to take the element from.
|
||||
* \param type the type of the struct this is embedded in.
|
||||
* \param member the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define llist_first_entry(ptr, type, member) \
|
||||
llist_entry((ptr)->next, type, member)
|
||||
|
||||
/*! Get the last element from a list
|
||||
* \param ptr the list head to take the element from.
|
||||
* \param type the type of the struct this is embedded in.
|
||||
* \param member the name of the llist_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define llist_last_entry(ptr, type, member) \
|
||||
llist_entry((ptr)->prev, type, member)
|
||||
|
||||
/*! Get the first element from a list, or NULL
|
||||
* \param ptr the list head to take the element from.
|
||||
* \param type the type of the struct this is embedded in.
|
||||
* \param member the name of the list_head within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*/
|
||||
#define llist_first_entry_or_null(ptr, type, member) \
|
||||
(!llist_empty(ptr) ? llist_first_entry(ptr, type, member) : NULL)
|
||||
|
||||
/*! Iterate over a linked list
|
||||
* \param pos The \ref llist_head to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
*/
|
||||
#define llist_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/*! Iterate over a llist (no prefetch)
|
||||
* \param pos The \ref llist_head to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
*
|
||||
* This variant differs from llist_for_each() in that it's the
|
||||
* simplest possible llist iteration code, no prefetching is done.
|
||||
* Use this for code that knows the llist to be very short (empty
|
||||
* or 1 entry) most of the time.
|
||||
*/
|
||||
#define __llist_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/*! Iterate over a llist backwards
|
||||
* \param pos The \ref llist_head to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
*/
|
||||
#define llist_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
|
||||
pos = pos->prev, prefetch(pos->prev))
|
||||
|
||||
/*! Iterate over a list; safe against removal of llist entry
|
||||
* \param pos The \ref llist_head to use as a loop counter
|
||||
* \param n Another \ref llist_head to use as temporary storage
|
||||
* \param head The head of the list over which to iterate
|
||||
*/
|
||||
#define llist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/*! Iterate over llist of given type
|
||||
* \param pos The 'type *' to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
* \param member The name of the \ref llist_head within struct \a pos
|
||||
*/
|
||||
#define llist_for_each_entry(pos, head, member) \
|
||||
for (pos = llist_entry((head)->next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = llist_entry(pos->member.next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next))
|
||||
|
||||
/*! Iterate backwards over llist of given type.
|
||||
* \param pos The 'type *' to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
* \param member The name of the \ref llist_head within struct \a pos
|
||||
*/
|
||||
#define llist_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = llist_entry((head)->prev, typeof(*pos), member), \
|
||||
prefetch(pos->member.prev); \
|
||||
&pos->member != (head); \
|
||||
pos = llist_entry(pos->member.prev, typeof(*pos), member), \
|
||||
prefetch(pos->member.prev))
|
||||
|
||||
/*! iterate over llist of given type continuing after existing
|
||||
* point
|
||||
* \param pos The 'type *' to use as a loop counter
|
||||
* \param head The head of the list over which to iterate
|
||||
* \param member The name of the \ref llist_head within struct \a pos
|
||||
*/
|
||||
#define llist_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = llist_entry(pos->member.next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next))
|
||||
|
||||
/*! iterate over llist of given type, safe against removal of
|
||||
* non-consecutive(!) llist entries
|
||||
* \param pos The 'type *' to use as a loop counter
|
||||
* \param n Another type * to use as temporary storage
|
||||
* \param head The head of the list over which to iterate
|
||||
* \param member The name of the \ref llist_head within struct \a pos
|
||||
*/
|
||||
#define llist_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = llist_entry((head)->next, typeof(*pos), member), \
|
||||
n = llist_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = llist_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* llist_for_each_rcu - iterate over an rcu-protected llist
|
||||
* @pos: the &struct llist_head to use as a loop counter.
|
||||
* @head: the head for your llist.
|
||||
*/
|
||||
#define llist_for_each_rcu(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
|
||||
|
||||
#define __llist_for_each_rcu(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); \
|
||||
pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
|
||||
|
||||
/**
|
||||
* llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
|
||||
* against removal of llist entry
|
||||
* @pos: the &struct llist_head to use as a loop counter.
|
||||
* @n: another &struct llist_head to use as temporary storage
|
||||
* @head: the head for your llist.
|
||||
*/
|
||||
#define llist_for_each_safe_rcu(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
|
||||
|
||||
/**
|
||||
* llist_for_each_entry_rcu - iterate over rcu llist of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your llist.
|
||||
* @member: the name of the llist_struct within the struct.
|
||||
*/
|
||||
#define llist_for_each_entry_rcu(pos, head, member) \
|
||||
for (pos = llist_entry((head)->next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = llist_entry(pos->member.next, typeof(*pos), member), \
|
||||
({ smp_read_barrier_depends(); 0;}), \
|
||||
prefetch(pos->member.next))
|
||||
|
||||
|
||||
/**
|
||||
* llist_for_each_continue_rcu - iterate over an rcu-protected llist
|
||||
* continuing after existing point.
|
||||
* @pos: the &struct llist_head to use as a loop counter.
|
||||
* @head: the head for your llist.
|
||||
*/
|
||||
#define llist_for_each_continue_rcu(pos, head) \
|
||||
for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
|
||||
(pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
|
||||
|
||||
/*! count nr of llist items by iterating.
|
||||
* \param head The llist head to count items of.
|
||||
* \returns Number of items.
|
||||
*
|
||||
* This function is not efficient, mostly useful for small lists and non time
|
||||
* critical cases like unit tests.
|
||||
*/
|
||||
static inline unsigned int llist_count(struct llist_head *head)
|
||||
{
|
||||
struct llist_head *entry;
|
||||
unsigned int i = 0;
|
||||
llist_for_each(entry, head)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
|
@ -1,100 +0,0 @@
|
|||
/*! \file panic.c
|
||||
* Routines for panic handling. */
|
||||
/*
|
||||
* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \addtogroup utils
|
||||
* @{
|
||||
* \file panic.c */
|
||||
|
||||
#include <osmocom/core/panic.h>
|
||||
//#include <osmocom/core/backtrace.h>
|
||||
|
||||
//#include "../config.h"
|
||||
|
||||
|
||||
static osmo_panic_handler_t osmo_panic_handler = (void*)0;
|
||||
|
||||
|
||||
#ifndef PANIC_INFLOOP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void osmo_panic_default(const char *fmt, va_list args)
|
||||
{
|
||||
vfprintf(stderr, fmt, args);
|
||||
//osmo_generate_backtrace();
|
||||
abort();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void osmo_panic_default(const char *fmt, va_list args)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*! Terminate the current program with a panic
|
||||
*
|
||||
* You can call this function in case some severely unexpected situation
|
||||
* is detected and the program is supposed to terminate in a way that
|
||||
* reports the fact that it terminates.
|
||||
*
|
||||
* The application can register a panic handler function using \ref
|
||||
* osmo_set_panic_handler. If it doesn't, a default panic handler
|
||||
* function is called automatically.
|
||||
*
|
||||
* The default function on most systems will generate a backtrace and
|
||||
* then abort() the process.
|
||||
*/
|
||||
void osmo_panic(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
if (osmo_panic_handler)
|
||||
osmo_panic_handler(fmt, args);
|
||||
else
|
||||
osmo_panic_default(fmt, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
/*! Set the panic handler
|
||||
* \param[in] h New panic handler function
|
||||
*
|
||||
* This changes the panic handling function from the currently active
|
||||
* function to a new call-back function supplied by the caller.
|
||||
*/
|
||||
void osmo_set_panic_handler(osmo_panic_handler_t h)
|
||||
{
|
||||
osmo_panic_handler = h;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/*! \addtogroup utils
|
||||
* @{
|
||||
* \file panic.h */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*! panic handler callback function type */
|
||||
typedef void (*osmo_panic_handler_t)(const char *fmt, va_list args);
|
||||
|
||||
extern void osmo_panic(const char *fmt, ...);
|
||||
extern void osmo_set_panic_handler(osmo_panic_handler_t h);
|
||||
|
||||
/*! @} */
|
|
@ -1,135 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
||||
# define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
# define __attribute__(_arg_)
|
||||
# define __deprecated__
|
||||
#endif
|
||||
|
||||
//#include <osmocom/core/backtrace.h>
|
||||
//#include <osmocom/core/talloc.h>
|
||||
|
||||
/*! \defgroup utils General-purpose utility functions
|
||||
* @{
|
||||
* \file utils.h */
|
||||
|
||||
/*! Determine number of elements in an array of static size */
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
/*! Return the maximum of two specified values */
|
||||
#define OSMO_MAX(a, b) ((a) >= (b) ? (a) : (b))
|
||||
/*! Return the minimum of two specified values */
|
||||
#define OSMO_MIN(a, b) ((a) >= (b) ? (b) : (a))
|
||||
/*! Stringify the name of a macro x, e.g. an FSM event name.
|
||||
* Note: if nested within another preprocessor macro, this will
|
||||
* stringify the value of x instead of its name. */
|
||||
#define OSMO_STRINGIFY(x) #x
|
||||
/*! Stringify the value of a macro x, e.g. a port number. */
|
||||
#define OSMO_STRINGIFY_VAL(x) OSMO_STRINGIFY(x)
|
||||
/*! Make a value_string entry from an enum value name */
|
||||
#define OSMO_VALUE_STRING(x) { x, #x }
|
||||
/*! Number of bytes necessary to store given BITS */
|
||||
#define OSMO_BYTES_FOR_BITS(BITS) ((BITS + 8 - 1) / 8)
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*! A mapping between human-readable string and numeric value */
|
||||
struct value_string {
|
||||
unsigned int value; /*!< numeric value */
|
||||
const char *str; /*!< human-readable string */
|
||||
};
|
||||
|
||||
//const char *get_value_string(const struct value_string *vs, uint32_t val);
|
||||
const char *get_value_string_or_null(const struct value_string *vs,
|
||||
uint32_t val);
|
||||
|
||||
int get_string_value(const struct value_string *vs, const char *str);
|
||||
|
||||
char osmo_bcd2char(uint8_t bcd);
|
||||
/* only works for numbers in ascci */
|
||||
uint8_t osmo_char2bcd(char c);
|
||||
|
||||
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
|
||||
|
||||
char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
|
||||
char *osmo_hexdump(const unsigned char *buf, int len);
|
||||
char *osmo_hexdump_nospc(const unsigned char *buf, int len);
|
||||
char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len) __attribute__((__deprecated__));
|
||||
|
||||
#define osmo_static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1] __attribute__((__unused__));
|
||||
|
||||
void osmo_str2lower(char *out, const char *in);
|
||||
void osmo_str2upper(char *out, const char *in);
|
||||
|
||||
#define OSMO_SNPRINTF_RET(ret, rem, offset, len) \
|
||||
do { \
|
||||
len += ret; \
|
||||
if (ret > rem) \
|
||||
ret = rem; \
|
||||
offset += ret; \
|
||||
rem -= ret; \
|
||||
} while (0)
|
||||
|
||||
/*! Helper macro to terminate when an assertion failes
|
||||
* \param[in] exp Predicate to verify
|
||||
* This function will generate a backtrace and terminate the program if
|
||||
* the predicate evaluates to false (0).
|
||||
*/
|
||||
#define OSMO_ASSERT(exp) \
|
||||
if (!(exp)) { \
|
||||
fprintf(stderr, "Assert failed %s %s:%d\n", #exp, __BASE_FILE__, __LINE__); \
|
||||
/*osmo_generate_backtrace(); \ */\
|
||||
abort(); \
|
||||
}
|
||||
|
||||
/*! duplicate a string using talloc and release its prior content (if any)
|
||||
* \param[in] ctx Talloc context to use for allocation
|
||||
* \param[out] dst pointer to string, will be updated with ptr to new string
|
||||
* \param[in] newstr String that will be copieed to newly allocated string */
|
||||
/*static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)*/
|
||||
/*{*/
|
||||
/* if (*dst)*/
|
||||
/* talloc_free(*dst);*/
|
||||
/* *dst = talloc_strdup(ctx, newstr);*/
|
||||
/*}*/
|
||||
|
||||
/*! Append to a string and re-/allocate if necessary.
|
||||
* \param[in] ctx Talloc context to use for initial allocation.
|
||||
* \param[in,out] dest char* to re-/allocate and append to.
|
||||
* \param[in] fmt printf-like string format.
|
||||
* \param[in] args Arguments for fmt.
|
||||
*
|
||||
* \a dest may be passed in NULL, or a string previously allocated by talloc.
|
||||
* If an existing string is passed in, it will remain associated with whichever
|
||||
* ctx it was allocated before, regardless whether it matches \a ctx or not.
|
||||
*/
|
||||
/*#define osmo_talloc_asprintf(ctx, dest, fmt, args ...) \*/
|
||||
/* do { \*/
|
||||
/* if (!dest) \*/
|
||||
/* dest = talloc_asprintf(ctx, fmt, ## args); \*/
|
||||
/* else \*/
|
||||
/* dest = talloc_asprintf_append((char*)dest, fmt, ## args); \*/
|
||||
/* } while (0)*/
|
||||
|
||||
int osmo_constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count);
|
||||
uint64_t osmo_decode_big_endian(const uint8_t *data, size_t data_len);
|
||||
uint8_t *osmo_encode_big_endian(uint64_t value, size_t data_len);
|
||||
|
||||
size_t osmo_strlcpy(char *dst, const char *src, size_t siz);
|
||||
|
||||
bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,
|
||||
bool require_even);
|
||||
|
||||
bool osmo_identifier_valid(const char *str);
|
||||
bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars);
|
||||
|
||||
const char *osmo_escape_str(const char *str, int len);
|
||||
const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
|
||||
|
||||
/*! @} */
|
|
@ -1,111 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
/*! \defgroup auth GSM/GPRS/3G Authentication
|
||||
* @{
|
||||
* \file auth.h */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#define OSMO_A5_MAX_KEY_LEN_BYTES (128/8)
|
||||
#define OSMO_MILENAGE_IND_BITLEN_MAX 28
|
||||
|
||||
/*! Authentication Type (GSM/UMTS) */
|
||||
enum osmo_sub_auth_type {
|
||||
OSMO_AUTH_TYPE_NONE = 0x00,
|
||||
OSMO_AUTH_TYPE_GSM = 0x01,
|
||||
OSMO_AUTH_TYPE_UMTS = 0x02,
|
||||
};
|
||||
|
||||
extern const struct value_string osmo_sub_auth_type_names[];
|
||||
/*static inline const char *osmo_sub_auth_type_name(enum osmo_sub_auth_type val)
|
||||
{ return get_value_string(osmo_sub_auth_type_names, val); }
|
||||
*/
|
||||
|
||||
/*! Authentication Algorithm.
|
||||
* See also osmo_auth_alg_name() and osmo_auth_alg_parse(). */
|
||||
enum osmo_auth_algo {
|
||||
OSMO_AUTH_ALG_NONE,
|
||||
OSMO_AUTH_ALG_COMP128v1,
|
||||
OSMO_AUTH_ALG_COMP128v2,
|
||||
OSMO_AUTH_ALG_COMP128v3,
|
||||
OSMO_AUTH_ALG_XOR,
|
||||
OSMO_AUTH_ALG_MILENAGE,
|
||||
_OSMO_AUTH_ALG_NUM,
|
||||
};
|
||||
|
||||
/*! permanent (secret) subscriber auth data */
|
||||
struct osmo_sub_auth_data {
|
||||
enum osmo_sub_auth_type type;
|
||||
enum osmo_auth_algo algo;
|
||||
union {
|
||||
struct {
|
||||
uint8_t opc[16]; /*!< operator invariant value */
|
||||
uint8_t k[16]; /*!< secret key of the subscriber */
|
||||
uint8_t amf[2];
|
||||
uint64_t sqn; /*!< sequence number (in: prev sqn; out: used sqn) */
|
||||
int opc_is_op; /*!< is the OPC field OPC (0) or OP (1) ? */
|
||||
unsigned int ind_bitlen; /*!< nr of bits not in SEQ, only SQN */
|
||||
unsigned int ind; /*!< which IND slot to use an SQN from */
|
||||
uint64_t sqn_ms; /*!< sqn from AUTS (output value only) */
|
||||
} umts;
|
||||
struct {
|
||||
uint8_t ki[OSMO_A5_MAX_KEY_LEN_BYTES]; /*!< secret key */
|
||||
} gsm;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* data structure describing a computed auth vector, generated by AuC */
|
||||
struct osmo_auth_vector {
|
||||
uint8_t rand[16]; /*!< random challenge */
|
||||
uint8_t autn[16]; /*!< authentication nonce */
|
||||
uint8_t ck[16]; /*!< ciphering key */
|
||||
uint8_t ik[16]; /*!< integrity key */
|
||||
uint8_t res[16]; /*!< authentication result */
|
||||
uint8_t res_len; /*!< length (in bytes) of res */
|
||||
uint8_t kc[8]; /*!< Kc for GSM encryption (A5) */
|
||||
uint8_t sres[4]; /*!< authentication result for GSM */
|
||||
uint32_t auth_types; /*!< bitmask of OSMO_AUTH_TYPE_* */
|
||||
};
|
||||
|
||||
/* An implementation of an authentication algorithm */
|
||||
struct osmo_auth_impl {
|
||||
struct llist_head list;
|
||||
enum osmo_auth_algo algo; /*!< algorithm we implement */
|
||||
const char *name; /*!< name of the implementation */
|
||||
unsigned int priority; /*!< priority value (resp. othe implementations */
|
||||
|
||||
/*! callback for generate authentication vectors */
|
||||
int (*gen_vec)(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud,
|
||||
const uint8_t *_rand);
|
||||
|
||||
/* callback for generationg auth vectors + re-sync */
|
||||
int (*gen_vec_auts)(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud,
|
||||
const uint8_t *auts, const uint8_t *rand_auts,
|
||||
const uint8_t *_rand);
|
||||
};
|
||||
|
||||
int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud, const uint8_t *_rand);
|
||||
|
||||
int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud,
|
||||
const uint8_t *auts, const uint8_t *rand_auts,
|
||||
const uint8_t *_rand);
|
||||
|
||||
int osmo_auth_register(struct osmo_auth_impl *impl);
|
||||
|
||||
int osmo_auth_load(const char *path);
|
||||
|
||||
int osmo_auth_supported(enum osmo_auth_algo algo);
|
||||
void osmo_c4(uint8_t *ck, const uint8_t *kc);
|
||||
const char *osmo_auth_alg_name(enum osmo_auth_algo alg);
|
||||
//enum osmo_auth_algo osmo_auth_alg_parse(const char *name);
|
||||
|
||||
void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[]);
|
||||
|
||||
/* @} */
|
|
@ -1,6 +0,0 @@
|
|||
add_sources(
|
||||
a5.c
|
||||
auth_core.c
|
||||
gsm48_ie.c
|
||||
kasumi.c
|
||||
)
|
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*! \addtogroup a5
|
||||
* @{
|
||||
* Osmocom GSM ciphering algorithm implementation
|
||||
*
|
||||
* Full reimplementation of A5/1,2,3,4 (split and threadsafe).
|
||||
*
|
||||
* The logic behind the algorithm is taken from "A pedagogical implementation
|
||||
* of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by
|
||||
* Marc Briceno, Ian Goldberg, and David Wagner.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/gsm/a5.h>
|
||||
#include <osmocom/gsm/kasumi.h>
|
||||
#include <osmocom/crypt/auth.h>
|
||||
|
||||
/* Somme OS (like Nuttx) don't have ENOTSUP */
|
||||
#ifndef ENOTSUP
|
||||
#define ENOTSUP EINVAL
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* A5/3&4 */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/*! Generate a GSM A5/4 cipher stream
|
||||
* \param[in] key 16 byte array for the key (as received from the SIM)
|
||||
* \param[in] fn Frame number
|
||||
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
|
||||
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
|
||||
* \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
|
||||
*
|
||||
* Either (or both) of dl/ul should be NULL if not needed.
|
||||
*
|
||||
* Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
|
||||
* with slight simplifications (CE hardcoded to 0).
|
||||
*/
|
||||
void
|
||||
_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
|
||||
{
|
||||
uint8_t i, gamma[32], uplink[15];
|
||||
uint32_t fn_count = (fn_correct) ? osmo_a5_fn_count(fn) : fn;
|
||||
|
||||
if (ul) {
|
||||
_kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 228);
|
||||
for(i = 0; i < 15; i++) uplink[i] = (gamma[i + 14] << 2) + (gamma[i + 15] >> 6);
|
||||
osmo_pbit2ubit(ul, uplink, 114);
|
||||
}
|
||||
if (dl) {
|
||||
_kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 114);
|
||||
osmo_pbit2ubit(dl, gamma, 114);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Generate a GSM A5/3 cipher stream
|
||||
* \param[in] key 8 byte array for the key (as received from the SIM)
|
||||
* \param[in] fn Frame number
|
||||
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
|
||||
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
|
||||
* \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
|
||||
*
|
||||
* Either (or both) of dl/ul should be NULL if not needed.
|
||||
*
|
||||
* Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
|
||||
* with slight simplifications (CE hardcoded to 0).
|
||||
*/
|
||||
void
|
||||
_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
|
||||
{
|
||||
uint8_t ck[16];
|
||||
osmo_c4(ck, key);
|
||||
/* internal function require 128 bit key so we expand by concatenating supplied 64 bit key */
|
||||
_a5_4(ck, fn, dl, ul, fn_correct);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* A5/1&2 common stuff */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define A5_R1_LEN 19
|
||||
#define A5_R2_LEN 22
|
||||
#define A5_R3_LEN 23
|
||||
#define A5_R4_LEN 17 /* A5/2 only */
|
||||
|
||||
#define A5_R1_MASK ((1<<A5_R1_LEN)-1)
|
||||
#define A5_R2_MASK ((1<<A5_R2_LEN)-1)
|
||||
#define A5_R3_MASK ((1<<A5_R3_LEN)-1)
|
||||
#define A5_R4_MASK ((1<<A5_R4_LEN)-1)
|
||||
|
||||
#define A5_R1_TAPS 0x072000 /* x^19 + x^18 + x^17 + x^14 + 1 */
|
||||
#define A5_R2_TAPS 0x300000 /* x^22 + x^21 + 1 */
|
||||
#define A5_R3_TAPS 0x700080 /* x^23 + x^22 + x^21 + x^8 + 1 */
|
||||
#define A5_R4_TAPS 0x010800 /* x^17 + x^12 + 1 */
|
||||
|
||||
/*! Computes parity of a 32-bit word
|
||||
* \param[in] x 32 bit word
|
||||
* \return Parity bit (xor of all bits) as 0 or 1
|
||||
*/
|
||||
static inline uint32_t
|
||||
_a5_12_parity(uint32_t x)
|
||||
{
|
||||
x ^= x >> 16;
|
||||
x ^= x >> 8;
|
||||
x ^= x >> 4;
|
||||
x &= 0xf;
|
||||
return (0x6996 >> x) & 1;
|
||||
}
|
||||
|
||||
/*! Compute majority bit from 3 taps
|
||||
* \param[in] v1 LFSR state ANDed with tap-bit
|
||||
* \param[in] v2 LFSR state ANDed with tap-bit
|
||||
* \param[in] v3 LFSR state ANDed with tap-bit
|
||||
* \return The majority bit (0 or 1)
|
||||
*/
|
||||
static inline uint32_t
|
||||
_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
|
||||
{
|
||||
return (!!v1 + !!v2 + !!v3) >= 2;
|
||||
}
|
||||
|
||||
/*! Compute the next LFSR state
|
||||
* \param[in] r Current state
|
||||
* \param[in] mask LFSR mask
|
||||
* \param[in] taps LFSR taps
|
||||
* \return Next state
|
||||
*/
|
||||
static inline uint32_t
|
||||
_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
|
||||
{
|
||||
return ((r << 1) & mask) | _a5_12_parity(r & taps);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* A5/1 */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define A51_R1_CLKBIT 0x000100
|
||||
#define A51_R2_CLKBIT 0x000400
|
||||
#define A51_R3_CLKBIT 0x000400
|
||||
|
||||
/*! GSM A5/1 Clocking function
|
||||
* \param[in] r Register state
|
||||
* \param[in] force Non-zero value disable conditional clocking
|
||||
*/
|
||||
static inline void
|
||||
_a5_1_clock(uint32_t r[], int force)
|
||||
{
|
||||
int cb[3], maj;
|
||||
|
||||
cb[0] = !!(r[0] & A51_R1_CLKBIT);
|
||||
cb[1] = !!(r[1] & A51_R2_CLKBIT);
|
||||
cb[2] = !!(r[2] & A51_R3_CLKBIT);
|
||||
|
||||
maj = _a5_12_majority(cb[0], cb[1], cb[2]);
|
||||
|
||||
if (force || (maj == cb[0]))
|
||||
r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
|
||||
|
||||
if (force || (maj == cb[1]))
|
||||
r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
|
||||
|
||||
if (force || (maj == cb[2]))
|
||||
r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
|
||||
}
|
||||
|
||||
/*! GSM A5/1 Output function
|
||||
* \param[in] r Register state
|
||||
* \return The A5/1 output function bit
|
||||
*/
|
||||
static inline uint8_t
|
||||
_a5_1_get_output(uint32_t r[])
|
||||
{
|
||||
return (r[0] >> (A5_R1_LEN-1)) ^
|
||||
(r[1] >> (A5_R2_LEN-1)) ^
|
||||
(r[2] >> (A5_R3_LEN-1));
|
||||
}
|
||||
|
||||
/*! Generate a GSM A5/1 cipher stream
|
||||
* \param[in] key 8 byte array for the key (as received from the SIM)
|
||||
* \param[in] fn Frame number
|
||||
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
|
||||
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
|
||||
*
|
||||
* Either (or both) of dl/ul can be NULL if not needed.
|
||||
*/
|
||||
void
|
||||
_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
|
||||
{
|
||||
uint32_t r[3] = {0, 0, 0};
|
||||
uint32_t fn_count;
|
||||
uint32_t b;
|
||||
int i;
|
||||
|
||||
/* Key load */
|
||||
for (i=0; i<64; i++)
|
||||
{
|
||||
b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
|
||||
|
||||
_a5_1_clock(r, 1);
|
||||
|
||||
r[0] ^= b;
|
||||
r[1] ^= b;
|
||||
r[2] ^= b;
|
||||
}
|
||||
|
||||
/* Frame count load */
|
||||
fn_count = osmo_a5_fn_count(fn);
|
||||
|
||||
for (i=0; i<22; i++)
|
||||
{
|
||||
b = (fn_count >> i) & 1;
|
||||
|
||||
_a5_1_clock(r, 1);
|
||||
|
||||
r[0] ^= b;
|
||||
r[1] ^= b;
|
||||
r[2] ^= b;
|
||||
}
|
||||
|
||||
/* Mix */
|
||||
for (i=0; i<100; i++)
|
||||
{
|
||||
_a5_1_clock(r, 0);
|
||||
}
|
||||
|
||||
/* Output */
|
||||
for (i=0; i<114; i++) {
|
||||
_a5_1_clock(r, 0);
|
||||
if (dl)
|
||||
dl[i] = _a5_1_get_output(r);
|
||||
}
|
||||
|
||||
for (i=0; i<114; i++) {
|
||||
_a5_1_clock(r, 0);
|
||||
if (ul)
|
||||
ul[i] = _a5_1_get_output(r);
|
||||
}
|
||||
}
|
||||
|
||||
void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
|
||||
{
|
||||
osmo_a5(1, key, fn, dl, ul);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* A5/2 */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define A52_R4_CLKBIT0 0x000400
|
||||
#define A52_R4_CLKBIT1 0x000008
|
||||
#define A52_R4_CLKBIT2 0x000080
|
||||
|
||||
/*! GSM A5/2 Clocking function
|
||||
* \param[in] r Register state
|
||||
* \param[in] force Non-zero value disable conditional clocking
|
||||
*/
|
||||
static inline void
|
||||
_a5_2_clock(uint32_t r[], int force)
|
||||
{
|
||||
int cb[3], maj;
|
||||
|
||||
cb[0] = !!(r[3] & A52_R4_CLKBIT0);
|
||||
cb[1] = !!(r[3] & A52_R4_CLKBIT1);
|
||||
cb[2] = !!(r[3] & A52_R4_CLKBIT2);
|
||||
|
||||
maj = (cb[0] + cb[1] + cb[2]) >= 2;
|
||||
|
||||
if (force || (maj == cb[0]))
|
||||
r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
|
||||
|
||||
if (force || (maj == cb[1]))
|
||||
r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
|
||||
|
||||
if (force || (maj == cb[2]))
|
||||
r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
|
||||
|
||||
r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
|
||||
}
|
||||
|
||||
/*! GSM A5/2 Output function
|
||||
* \param[in] r Register state
|
||||
* \return The A5/2 output function bit
|
||||
*/
|
||||
static inline uint8_t
|
||||
_a5_2_get_output(uint32_t r[])
|
||||
{
|
||||
uint8_t b;
|
||||
|
||||
b = (r[0] >> (A5_R1_LEN-1)) ^
|
||||
(r[1] >> (A5_R2_LEN-1)) ^
|
||||
(r[2] >> (A5_R3_LEN-1)) ^
|
||||
_a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
|
||||
_a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
|
||||
_a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/*! Generate a GSM A5/1 cipher stream
|
||||
* \param[in] key 8 byte array for the key (as received from the SIM)
|
||||
* \param[in] fn Frame number
|
||||
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
|
||||
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
|
||||
*
|
||||
* Either (or both) of dl/ul can be NULL if not needed.
|
||||
*/
|
||||
void
|
||||
_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
|
||||
{
|
||||
uint32_t r[4] = {0, 0, 0, 0};
|
||||
uint32_t fn_count;
|
||||
uint32_t b;
|
||||
int i;
|
||||
|
||||
/* Key load */
|
||||
for (i=0; i<64; i++)
|
||||
{
|
||||
b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
|
||||
|
||||
_a5_2_clock(r, 1);
|
||||
|
||||
r[0] ^= b;
|
||||
r[1] ^= b;
|
||||
r[2] ^= b;
|
||||
r[3] ^= b;
|
||||
}
|
||||
|
||||
/* Frame count load */
|
||||
fn_count = osmo_a5_fn_count(fn);
|
||||
|
||||
for (i=0; i<22; i++)
|
||||
{
|
||||
b = (fn_count >> i) & 1;
|
||||
|
||||
_a5_2_clock(r, 1);
|
||||
|
||||
r[0] ^= b;
|
||||
r[1] ^= b;
|
||||
r[2] ^= b;
|
||||
r[3] ^= b;
|
||||
}
|
||||
|
||||
r[0] |= 1 << 15;
|
||||
r[1] |= 1 << 16;
|
||||
r[2] |= 1 << 18;
|
||||
r[3] |= 1 << 10;
|
||||
|
||||
/* Mix */
|
||||
for (i=0; i<99; i++)
|
||||
{
|
||||
_a5_2_clock(r, 0);
|
||||
}
|
||||
|
||||
/* Output */
|
||||
for (i=0; i<114; i++) {
|
||||
_a5_2_clock(r, 0);
|
||||
if (dl)
|
||||
dl[i] = _a5_2_get_output(r);
|
||||
}
|
||||
|
||||
for (i=0; i<114; i++) {
|
||||
_a5_2_clock(r, 0);
|
||||
if (ul)
|
||||
ul[i] = _a5_2_get_output(r);
|
||||
}
|
||||
}
|
||||
|
||||
void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
|
||||
{
|
||||
osmo_a5(2, key, fn, dl, ul);
|
||||
}
|
||||
|
||||
/*! Main method to generate a A5/x cipher stream
|
||||
* \param[in] n Which A5/x method to use
|
||||
* \param[in] key 8 or 16 (for a5/4) byte array for the key (as received from the SIM)
|
||||
* \param[in] fn Frame number
|
||||
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
|
||||
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
|
||||
* \returns 0 for success, -ENOTSUP for invalid cipher selection.
|
||||
*
|
||||
* Currently A5/[0-4] are supported.
|
||||
* Either (or both) of dl/ul can be NULL if not needed.
|
||||
*/
|
||||
int
|
||||
osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0:
|
||||
if (dl)
|
||||
memset(dl, 0x00, 114);
|
||||
if (ul)
|
||||
memset(ul, 0x00, 114);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_a5_1(key, fn, dl, ul);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_a5_2(key, fn, dl, ul);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_a5_3(key, fn, dl, ul, true);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
_a5_4(key, fn, dl, ul, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* a5/[5..7] not supported here/yet */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <osmocom/core/defs.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
|
||||
/*! \defgroup a5 GSM A5 ciphering algorithm
|
||||
* @{
|
||||
* \file a5.h */
|
||||
|
||||
/*! Converts a frame number into the 22 bit number used in A5/x
|
||||
* \param[in] fn The true framenumber
|
||||
* \return 22 bit word
|
||||
*/
|
||||
static inline uint32_t
|
||||
osmo_a5_fn_count(uint32_t fn)
|
||||
{
|
||||
int t1 = fn / (26 * 51);
|
||||
int t2 = fn % 26;
|
||||
int t3 = fn % 51;
|
||||
return (t1 << 11) | (t3 << 5) | t2;
|
||||
}
|
||||
|
||||
/* Notes:
|
||||
* - key must be 8 or 16 (for a5/4) bytes long (or NULL for A5/0)
|
||||
* - the dl and ul pointer must be either NULL or 114 bits long
|
||||
* - fn is the _real_ GSM frame number.
|
||||
* (converted internally to fn_count)
|
||||
*/
|
||||
int osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
|
||||
void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) OSMO_DEPRECATED("Use generic osmo_a5() instead");
|
||||
void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) OSMO_DEPRECATED("Use generic osmo_a5() instead");
|
||||
|
||||
/*! @} */
|
|
@ -1,252 +0,0 @@
|
|||
/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
//#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
//#include <osmocom/core/plugin.h>
|
||||
|
||||
#include <osmocom/crypt/auth.h>
|
||||
|
||||
/*! \addtogroup auth
|
||||
* @{
|
||||
* GSM/GPRS/3G authentication core infrastructure
|
||||
*
|
||||
* \file auth_core.c */
|
||||
|
||||
static LLIST_HEAD(osmo_auths);
|
||||
|
||||
static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM];
|
||||
|
||||
/*! Register an authentication algorithm implementation with the core
|
||||
* \param[in] impl Structure describing implementation and it's callbacks
|
||||
* \returns 0 on success, or a negative error code on failure
|
||||
*
|
||||
* This function is called by an authentication implementation plugin to
|
||||
* register itself with the authentication core.
|
||||
*/
|
||||
int osmo_auth_register(struct osmo_auth_impl *impl)
|
||||
{
|
||||
if (impl->algo >= ARRAY_SIZE(selected_auths))
|
||||
return -ERANGE;
|
||||
|
||||
llist_add_tail(&impl->list, &osmo_auths);
|
||||
|
||||
/* check if we want to select this implementation over others */
|
||||
if (!selected_auths[impl->algo] ||
|
||||
(selected_auths[impl->algo]->priority > impl->priority))
|
||||
selected_auths[impl->algo] = impl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Load all available authentication plugins from the given path
|
||||
* \param[in] path Path name of the directory containing the plugins
|
||||
* \returns number of plugins loaded in case of success, negative in case of error
|
||||
*
|
||||
* This function will load all plugins contained in the specified path.
|
||||
*/
|
||||
int osmo_auth_load(const char *path)
|
||||
{
|
||||
/* load all plugins available from path */
|
||||
/*#if !defined(EMBEDDED)
|
||||
return osmo_plugin_load_all(path);
|
||||
#else*/
|
||||
return -1;
|
||||
/*#endif*/
|
||||
}
|
||||
|
||||
/*! Determine if a given authentication algorithm is supported
|
||||
* \param[in] algo Algorithm which should be checked
|
||||
* \returns 1 if algo is supported, 0 if not, negative error on failure
|
||||
*
|
||||
* This function is used by an application to determine at runtime if a
|
||||
* given authentication algorithm is supported or not.
|
||||
*/
|
||||
int osmo_auth_supported(enum osmo_auth_algo algo)
|
||||
{
|
||||
if (algo >= ARRAY_SIZE(selected_auths))
|
||||
return -ERANGE;
|
||||
|
||||
if (selected_auths[algo])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* C5 function to derive UMTS IK from GSM Kc */
|
||||
static inline void c5_function(uint8_t *ik, const uint8_t *kc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ik[i] = kc[i] ^ kc[i+4];
|
||||
memcpy(ik+4, kc, 8);
|
||||
for (i = 12; i < 16; i++)
|
||||
ik[i] = ik[i-12];
|
||||
}
|
||||
|
||||
/* C4 function to derive UMTS CK from GSM Kc */
|
||||
void osmo_c4(uint8_t *ck, const uint8_t *kc)
|
||||
{
|
||||
memcpy(ck, kc, 8);
|
||||
memcpy(ck+8, kc, 8);
|
||||
}
|
||||
|
||||
/*! Generate 3G CK + IK from 2G authentication vector
|
||||
* \param vec Authentication Vector to be modified
|
||||
* \returns 1 if the vector was changed, 0 otherwise
|
||||
*
|
||||
* This function performs the C5 and C4 functions to derive the UMTS key
|
||||
* material from the GSM key material in the supplied vector, _if_ the input
|
||||
* vector doesn't yet have UMTS authentication capability.
|
||||
*/
|
||||
int osmo_auth_3g_from_2g(struct osmo_auth_vector *vec)
|
||||
{
|
||||
if ((vec->auth_types & OSMO_AUTH_TYPE_GSM) &&
|
||||
!(vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
|
||||
c5_function(vec->ik, vec->kc);
|
||||
osmo_c4(vec->ck, vec->kc);
|
||||
/* We cannot actually set OSMO_AUTH_TYPE_UMTS as we have no
|
||||
* AUTN and no RES, and thus can only perform GSM
|
||||
* authentication with this tuple.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Generate authentication vector
|
||||
* \param[out] vec Generated authentication vector
|
||||
* \param[in] aud Subscriber-specific key material
|
||||
* \param[in] _rand Random challenge to be used
|
||||
* \returns 0 on success, negative error on failure
|
||||
*
|
||||
* This function performs the core cryptographic function of the AUC,
|
||||
* computing authentication triples/quintuples based on the permanent
|
||||
* subscriber data and a random value. The result is what is forwarded
|
||||
* by the AUC via HLR and VLR to the MSC which will then be able to
|
||||
* invoke authentication with the MS
|
||||
*/
|
||||
int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud,
|
||||
const uint8_t *_rand)
|
||||
{
|
||||
struct osmo_auth_impl *impl = selected_auths[aud->algo];
|
||||
int rc;
|
||||
|
||||
if (!impl)
|
||||
return -ENOENT;
|
||||
|
||||
rc = impl->gen_vec(vec, aud, _rand);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
memcpy(vec->rand, _rand, sizeof(vec->rand));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Generate authentication vector and re-sync sequence
|
||||
* \param[out] vec Generated authentication vector
|
||||
* \param[in] aud Subscriber-specific key material
|
||||
* \param[in] auts AUTS value sent by the SIM/MS
|
||||
* \param[in] rand_auts RAND value sent by the SIM/MS
|
||||
* \param[in] _rand Random challenge to be used to generate vector
|
||||
* \returns 0 on success, negative error on failure
|
||||
*
|
||||
* This function performs a special variant of the core cryptographic
|
||||
* function of the AUC: computing authentication triples/quintuples
|
||||
* based on the permanent subscriber data, a random value as well as the
|
||||
* AUTS and RAND values returned by the SIM/MS. This special variant is
|
||||
* needed if the sequence numbers between MS and AUC have for some
|
||||
* reason become different.
|
||||
*/
|
||||
int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec,
|
||||
struct osmo_sub_auth_data *aud,
|
||||
const uint8_t *auts, const uint8_t *rand_auts,
|
||||
const uint8_t *_rand)
|
||||
{
|
||||
struct osmo_auth_impl *impl = selected_auths[aud->algo];
|
||||
int rc;
|
||||
|
||||
if (!impl || !impl->gen_vec_auts)
|
||||
return -ENOENT;
|
||||
|
||||
rc = impl->gen_vec_auts(vec, aud, auts, rand_auts, _rand);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
memcpy(vec->rand, _rand, sizeof(vec->rand));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct value_string auth_alg_vals[] = {
|
||||
{ OSMO_AUTH_ALG_NONE, "None" },
|
||||
{ OSMO_AUTH_ALG_COMP128v1, "COMP128v1" },
|
||||
{ OSMO_AUTH_ALG_COMP128v2, "COMP128v2" },
|
||||
{ OSMO_AUTH_ALG_COMP128v3, "COMP128v3" },
|
||||
{ OSMO_AUTH_ALG_XOR, "XOR" },
|
||||
{ OSMO_AUTH_ALG_MILENAGE, "MILENAGE" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/*! Get human-readable name of authentication algorithm *
|
||||
const char *osmo_auth_alg_name(enum osmo_auth_algo alg)
|
||||
{
|
||||
return get_value_string(auth_alg_vals, alg);
|
||||
}
|
||||
|
||||
/*! Parse human-readable name of authentication algorithm */
|
||||
/*enum osmo_auth_algo osmo_auth_alg_parse(const char *name)
|
||||
{
|
||||
return get_string_value(auth_alg_vals, name);
|
||||
}
|
||||
*/
|
||||
const struct value_string osmo_sub_auth_type_names[] = {
|
||||
{ OSMO_AUTH_TYPE_NONE, "None" },
|
||||
{ OSMO_AUTH_TYPE_GSM, "GSM" },
|
||||
{ OSMO_AUTH_TYPE_UMTS, "UMTS" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Derive GSM AKA ciphering key Kc from UMTS AKA CK and IK (auth function c3 from 3GPP TS 33.103 §
|
||||
* 4.6.1).
|
||||
* \param[out] kc GSM AKA Kc, 8 byte target buffer.
|
||||
* \param[in] ck UMTS AKA CK, 16 byte input buffer.
|
||||
* \param[in] ik UMTS AKA IK, 16 byte input buffer.
|
||||
*/
|
||||
void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
|
||||
}
|
||||
|
||||
/*! @} */
|
|
@ -1,285 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) 2011-2016 Sylvain Munaut <tnt@246tNt.com>
|
||||
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/conv.h>
|
||||
|
||||
/*! structure describing xCCH convolutional code:.
|
||||
* 228 bits blocks, rate 1/2, k = 5
|
||||
* G0 = 1 + D3 + D4
|
||||
* G1 = 1 + D + D3 + D4
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_xcch;
|
||||
|
||||
/*! structure describing RACH convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_rach;
|
||||
|
||||
/*! structure describing Extended RACH (11 bit) convolutional code.
|
||||
*/
|
||||
//extern const struct osmo_conv_code gsm0503_rach_ext;
|
||||
|
||||
/*! structure describing SCH convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_sch;
|
||||
|
||||
/*! structure describing CS2 convolutional code:.
|
||||
* G0 = 1 + D3 + D4
|
||||
* G1 = 1 + D + D3 + D4
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_cs2;
|
||||
|
||||
/*! structure describing CS3 convolutional code:.
|
||||
* G0 = 1 + D3 + D4
|
||||
* G1 = 1 + D + D3 + D4
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_cs3;
|
||||
|
||||
/*! structure describing CS2 convolutional code (non-punctured):.
|
||||
* G0 = 1 + D3 + D4
|
||||
* G1 = 1 + D + D3 + D4
|
||||
*/
|
||||
//extern const struct osmo_conv_code gsm0503_cs2_np;
|
||||
|
||||
/*! structure describing CS3 convolutional code (non-punctured):.
|
||||
* G0 = 1 + D3 + D4
|
||||
* G1 = 1 + D + D3 + D4
|
||||
*/
|
||||
//extern const struct osmo_conv_code gsm0503_cs3_np;
|
||||
|
||||
/*! structure describing TCH/AFS 12.2 kbits convolutional code:.
|
||||
* 250 bits block, rate 1/2, punctured
|
||||
* G0/G0 = 1
|
||||
* G1/G0 = 1 + D + D3 + D4 / 1 + D3 + D4
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_12_2;
|
||||
|
||||
/*! structure describing TCH/AFS 10.2 kbits convolutional code:.
|
||||
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G3/G3 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_10_2;
|
||||
|
||||
/*! structure describing TCH/AFS 7.95 kbits convolutional code:.
|
||||
* G4/G4 = 1
|
||||
* G5/G4 = 1 + D + D4 + D6 / 1 + D2 + D3 + D5 + D6
|
||||
* G6/G4 = 1 + D + D2 + D3 + D4 + D6 / 1 + D2 + D3 + D5 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_7_95;
|
||||
|
||||
/*! structure describing TCH/AFS 7.4 kbits convolutional code:.
|
||||
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G3/G3 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_7_4;
|
||||
|
||||
/*! structure describing TCH/AFS 6.7 kbits convolutional code:.
|
||||
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G3/G3 = 1
|
||||
* G3/G3 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_6_7;
|
||||
|
||||
/*! structure describing TCH/AFS 5.9 kbits convolutional code:.
|
||||
* 124 bits
|
||||
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
|
||||
* G5/G6 = 1 + D + D4 + D6 / 1 + D + D2 + D3 + D4 + D6
|
||||
* G6/G6 = 1
|
||||
* G6/G6 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_5_9;
|
||||
|
||||
/*! structure describing TCH/AFS 5.15 kbits convolutional code:.
|
||||
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
|
||||
* G3/G3 = 1
|
||||
* G3/G3 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_5_15;
|
||||
|
||||
/*! structure describing TCH/AFS 4.75 kbits convolutional code:.
|
||||
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
|
||||
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
|
||||
* G5/G6 = 1 + D + D4 + D6 / 1 + D + D2 + D3 + D4 + D6
|
||||
* G6/G6 = 1
|
||||
* G6/G6 = 1
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_afs_4_75;
|
||||
|
||||
/*! structure describing TCH/F convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_fr;
|
||||
|
||||
/*! structure describing TCH/H convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_hr;
|
||||
|
||||
/*! structure describing TCH/AHS 7.95 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_7_95;
|
||||
|
||||
/*! structure describing TCH/AHS 7.4 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_7_4;
|
||||
|
||||
/*! structure describing TCH/AHS 6.7 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_6_7;
|
||||
|
||||
/*! structure describing TCH/AHS 5.9 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_5_9;
|
||||
|
||||
/*! structure describing TCH/AHS 5.15 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_5_15;
|
||||
|
||||
/*! structure describing TCH/AHS 4.75 kbits convolutional code.
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_tch_ahs_4_75;
|
||||
|
||||
/*! structure describing EDGE MCS-1 DL header convolutional code:.
|
||||
* 42 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs1_dl_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-1 UL header convolutional code:.
|
||||
* 45 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs1_ul_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-1 data convolutional code:.
|
||||
* 196 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs1;
|
||||
|
||||
/*! structure describing EDGE MCS-2 data convolutional code:.
|
||||
* 244 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs2;
|
||||
|
||||
/*! structure describing EDGE MCS-3 data convolutional code:.
|
||||
* 316 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs3;
|
||||
|
||||
/*! structure describing EDGE MCS-4 data convolutional code:.
|
||||
* 372 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs4;
|
||||
|
||||
/*! structure describing EDGE MCS-5 DL header convolutional code:.
|
||||
* 39 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs5_dl_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-5 UL header convolutional code:.
|
||||
* 51 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs5_ul_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-5 data convolutional code:.
|
||||
* 468 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs5;
|
||||
|
||||
/*! structure describing EDGE MCS-6 data convolutional code:.
|
||||
* 612 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs6;
|
||||
|
||||
/*! structure describing EDGE MCS-7 DL header convolutional code:.
|
||||
* 51 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs7_dl_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-7 UL header convolutional code:.
|
||||
* 60 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs7_ul_hdr;
|
||||
|
||||
/*! structure describing EDGE MCS-7 data convolutional code:.
|
||||
* 468 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs7;
|
||||
|
||||
/*! structure describing EDGE MCS-8 data convolutional code:.
|
||||
* 564 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs8;
|
||||
|
||||
/*! structure describing EDGE MCS-9 data convolutional code:.
|
||||
* 612 bits blocks, rate 1/3, k = 7
|
||||
* G4 = 1 + D2 + D3 + D5 + D6
|
||||
* G7 = 1 + D + D2 + D3 + D6
|
||||
* G5 = 1 + D + D4 + D6
|
||||
*/
|
||||
extern const struct osmo_conv_code gsm0503_mcs9;
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,116 +0,0 @@
|
|||
/*! \file gsm48_ie.h */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* #include <osmocom/core/msgb.h> */
|
||||
/* #include <osmocom/gsm/tlv.h> */
|
||||
/* #include <osmocom/gsm/mncc.h> */
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
|
||||
/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
|
||||
//int gsm48_decode_bcd_number(char *output, int output_len,
|
||||
// const uint8_t *bcd_lv, int h_len);
|
||||
|
||||
///* convert a ASCII phone number to 'called/calling/connect party BCD number' */
|
||||
//int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
|
||||
// int h_len, const char *input);
|
||||
///* decode 'bearer capability' */
|
||||
//int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'bearer capability' */
|
||||
//int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
|
||||
// const struct gsm_mncc_bearer_cap *bcap);
|
||||
///* decode 'call control cap' */
|
||||
//int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv);
|
||||
///* encode 'call control cap' */
|
||||
//int gsm48_encode_cccap(struct msgb *msg,
|
||||
// const struct gsm_mncc_cccap *ccap);
|
||||
///* decode 'called party BCD number' */
|
||||
//int gsm48_decode_called(struct gsm_mncc_number *called,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'called party BCD number' */
|
||||
//int gsm48_encode_called(struct msgb *msg,
|
||||
// const struct gsm_mncc_number *called);
|
||||
///* decode callerid of various IEs */
|
||||
//int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
|
||||
// const uint8_t *lv);
|
||||
///* encode callerid of various IEs */
|
||||
//int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
|
||||
// const struct gsm_mncc_number *callerid);
|
||||
///* decode 'cause' */
|
||||
//int gsm48_decode_cause(struct gsm_mncc_cause *cause,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'cause' */
|
||||
//int gsm48_encode_cause(struct msgb *msg, int lv_only,
|
||||
// const struct gsm_mncc_cause *cause);
|
||||
///* decode 'calling number' */
|
||||
//int gsm48_decode_calling(struct gsm_mncc_number *calling,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'calling number' */
|
||||
//int gsm48_encode_calling(struct msgb *msg,
|
||||
// const struct gsm_mncc_number *calling);
|
||||
///* decode 'connected number' */
|
||||
//int gsm48_decode_connected(struct gsm_mncc_number *connected,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'connected number' */
|
||||
//int gsm48_encode_connected(struct msgb *msg,
|
||||
// const struct gsm_mncc_number *connected);
|
||||
///* decode 'redirecting number' */
|
||||
//int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'redirecting number' */
|
||||
//int gsm48_encode_redirecting(struct msgb *msg,
|
||||
// const struct gsm_mncc_number *redirecting);
|
||||
///* decode 'facility' */
|
||||
//int gsm48_decode_facility(struct gsm_mncc_facility *facility,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'facility' */
|
||||
//int gsm48_encode_facility(struct msgb *msg, int lv_only,
|
||||
// const struct gsm_mncc_facility *facility);
|
||||
///* decode 'notify' */
|
||||
//int gsm48_decode_notify(int *notify, const uint8_t *v);
|
||||
///* encode 'notify' */
|
||||
//int gsm48_encode_notify(struct msgb *msg, int notify);
|
||||
///* decode 'signal' */
|
||||
//int gsm48_decode_signal(int *signal, const uint8_t *v);
|
||||
///* encode 'signal' */
|
||||
//int gsm48_encode_signal(struct msgb *msg, int signal);
|
||||
///* decode 'keypad' */
|
||||
//int gsm48_decode_keypad(int *keypad, const uint8_t *lv);
|
||||
///* encode 'keypad' */
|
||||
//int gsm48_encode_keypad(struct msgb *msg, int keypad);
|
||||
///* decode 'progress' */
|
||||
//int gsm48_decode_progress(struct gsm_mncc_progress *progress,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'progress' */
|
||||
//int gsm48_encode_progress(struct msgb *msg, int lv_only,
|
||||
// const struct gsm_mncc_progress *p);
|
||||
///* decode 'user-user' */
|
||||
//int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'useruser' */
|
||||
//int gsm48_encode_useruser(struct msgb *msg, int lv_only,
|
||||
// const struct gsm_mncc_useruser *uu);
|
||||
///* decode 'ss version' */
|
||||
//int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
|
||||
// const uint8_t *lv);
|
||||
///* encode 'ss version' */
|
||||
//int gsm48_encode_ssversion(struct msgb *msg,
|
||||
// const struct gsm_mncc_ssversion *ssv);
|
||||
///* decode 'more data' does not require a function, because it has no value */
|
||||
///* encode 'more data' */
|
||||
//int gsm48_encode_more(struct msgb *msg);
|
||||
|
||||
/* structure of one frequency */
|
||||
struct gsm_sysinfo_freq {
|
||||
/* if the frequency included in the sysinfo */
|
||||
uint8_t mask;
|
||||
};
|
||||
|
||||
/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
|
||||
int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd,
|
||||
uint8_t len, uint8_t mask, uint8_t frqt);
|
|
@ -1,188 +0,0 @@
|
|||
/*! \file kasumi.c
|
||||
* Kasumi cipher and KGcore functions. */
|
||||
/*
|
||||
* (C) 2013 by Max <Max.Suraev@fairwaves.ru>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/bits.h>
|
||||
#include <osmocom/gsm/kasumi.h>
|
||||
|
||||
/* See TS 135 202 for constants and full Kasumi spec. */
|
||||
inline static uint16_t kasumi_FI(uint16_t I, uint16_t skey)
|
||||
{
|
||||
static const uint16_t S7[] = {
|
||||
54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, 123, 33,
|
||||
55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, 25, 111, 124, 81,
|
||||
53, 9, 121, 79, 52, 60, 58, 48, 101, 127, 40, 120, 104, 70, 71, 43,
|
||||
20, 122, 72, 61, 23, 109, 13, 100, 77, 1, 16, 7, 82, 10, 105, 98,
|
||||
117, 116, 76, 11, 89, 106, 0,125,118, 99, 86, 69, 30, 57, 126, 87,
|
||||
112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66,
|
||||
102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44,
|
||||
64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, 59, 3
|
||||
};
|
||||
static const uint16_t S9[] = {
|
||||
167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, 90, 397,
|
||||
183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, 216, 159, 356, 177,
|
||||
175, 241, 489, 37, 206, 17, 0, 333, 44, 254, 378, 58, 143, 220, 81, 400,
|
||||
95, 3, 315, 245, 54, 235, 218, 405, 472, 264, 172, 494, 371, 290, 399, 76,
|
||||
165, 197, 395, 121, 257, 480, 423, 212, 240, 28, 462, 176, 406, 507, 288, 223,
|
||||
501, 407, 249, 265, 89, 186, 221, 428,164, 74, 440, 196, 458, 421, 350, 163,
|
||||
232, 158, 134, 354, 13, 250, 491, 142,191, 69, 193, 425, 152, 227, 366, 135,
|
||||
344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, 496, 27,
|
||||
487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, 39, 115, 442, 124,
|
||||
475, 384, 508, 53, 112, 170, 479, 151, 126, 169, 73, 268, 279, 321, 168, 364,
|
||||
363, 292, 46, 499, 393, 327, 324, 24, 456, 267, 157, 460, 488, 426, 309, 229,
|
||||
439, 506, 208, 271, 349, 401, 434, 236, 16, 209, 359, 52, 56, 120, 199, 277,
|
||||
465, 416, 252, 287, 246, 6, 83, 305, 420, 345, 153,502, 65, 61, 244, 282,
|
||||
173, 222, 418, 67, 386, 368, 261, 101, 476, 291, 195,430, 49, 79, 166, 330,
|
||||
280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, 62, 454,
|
||||
132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, 347, 307, 140, 374,
|
||||
35, 103, 125, 427, 19, 214, 453, 146, 498, 314, 444, 230, 256, 329, 198, 285,
|
||||
50, 116, 78, 410, 10, 205, 510, 171, 231, 45, 139, 467, 29, 86, 505, 32,
|
||||
72, 26, 342, 150, 313, 490, 431, 238, 411, 325, 149, 473, 40, 119, 174, 355,
|
||||
185, 233, 389, 71, 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190,
|
||||
1, 109, 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111,
|
||||
336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, 483, 18,
|
||||
47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, 31, 104, 433, 84,
|
||||
414, 486, 394, 96, 99, 154, 511, 148, 413, 361, 409, 255, 162, 215, 302, 201,
|
||||
266, 351, 343, 144, 441, 365, 108, 298, 251, 34, 182, 509, 138, 210, 335, 133,
|
||||
311, 352, 328, 141, 396, 346, 123, 319, 450, 281, 429, 228, 443, 481, 92, 404,
|
||||
485, 422, 248, 297, 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127,
|
||||
312, 377, 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398,
|
||||
284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, 33, 451,
|
||||
97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, 189, 207, 114, 402,
|
||||
438, 477, 387, 122, 192, 42, 381, 5, 145, 118, 180, 449, 293, 323, 136, 380,
|
||||
43, 66, 60, 455, 341, 445, 202, 432, 8, 237, 15, 376, 436, 464, 59, 461
|
||||
};
|
||||
uint16_t L, R;
|
||||
|
||||
/* Split 16 bit input into two unequal halves: 9 and 7 bits, same for subkey */
|
||||
L = I >> 7; /* take 9 bits */
|
||||
R = I & 0x7F; /* take 7 bits */
|
||||
|
||||
L = S9[L] ^ R;
|
||||
R = S7[R] ^ (L & 0x7F);
|
||||
|
||||
L ^= (skey & 0x1FF);
|
||||
R ^= (skey >> 9);
|
||||
|
||||
L = S9[L] ^ R;
|
||||
R = S7[R] ^ (L & 0x7F);
|
||||
|
||||
return (R << 9) + L;
|
||||
}
|
||||
|
||||
inline static uint32_t kasumi_FO(uint32_t I, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3, unsigned i)
|
||||
{
|
||||
uint16_t L = I >> 16, R = I; /* Split 32 bit input into Left and Right parts */
|
||||
|
||||
L ^= KOi1[i];
|
||||
L = kasumi_FI(L, KIi1[i]);
|
||||
L ^= R;
|
||||
|
||||
R ^= KOi2[i];
|
||||
R = kasumi_FI(R, KIi2[i]);
|
||||
R ^= L;
|
||||
|
||||
L ^= KOi3[i];
|
||||
L = kasumi_FI(L, KIi3[i]);
|
||||
L ^= R;
|
||||
|
||||
return (((uint32_t)R) << 16) + L;
|
||||
}
|
||||
|
||||
inline static uint32_t kasumi_FL(uint32_t I, const uint16_t *KLi1, const uint16_t *KLi2, unsigned i)
|
||||
{
|
||||
uint16_t L = I >> 16, R = I, tmp; /* Split 32 bit input into Left and Right parts */
|
||||
|
||||
tmp = L & KLi1[i];
|
||||
R ^= osmo_rol16(tmp, 1);
|
||||
|
||||
tmp = R | KLi2[i];
|
||||
L ^= osmo_rol16(tmp, 1);
|
||||
|
||||
return (((uint32_t)L) << 16) + R;
|
||||
}
|
||||
|
||||
uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3)
|
||||
{
|
||||
uint32_t i, L = P >> 32, R = P; /* Split 64 bit input into Left and Right parts */
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
R ^= kasumi_FO(kasumi_FL(L, KLi1, KLi2, i), KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i); /* odd round */
|
||||
i++;
|
||||
L ^= kasumi_FL(kasumi_FO(R, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i), KLi1, KLi2, i); /* even round */
|
||||
}
|
||||
return (((uint64_t)L) << 32) + R; /* Concatenate Left and Right 32 bits into 64 bit ciphertext */
|
||||
}
|
||||
|
||||
void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3)
|
||||
{
|
||||
uint16_t i, C[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210 };
|
||||
|
||||
/* Work with 16 bit subkeys and create prime subkeys */
|
||||
for (i = 0; i < 8; i++)
|
||||
C[i] ^= osmo_load16be(key + i * 2);
|
||||
/* C[] now stores K-prime[] */
|
||||
|
||||
/* Create round-specific subkeys */
|
||||
for (i = 0; i < 8; i++) {
|
||||
KLi1[i] = osmo_rol16(osmo_load16be(key + i * 2), 1);
|
||||
KLi2[i] = C[(i + 2) & 0x7];
|
||||
|
||||
KOi1[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 1)) & 0xE)), 5);
|
||||
KOi2[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 5)) & 0xE)), 8);
|
||||
KOi3[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 6)) & 0xE)), 13);
|
||||
|
||||
KIi1[i] = C[(i + 4) & 0x7];
|
||||
KIi2[i] = C[(i + 3) & 0x7];
|
||||
KIi3[i] = C[(i + 7) & 0x7];
|
||||
}
|
||||
}
|
||||
|
||||
void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl)
|
||||
{
|
||||
uint16_t KLi1[8], KLi2[8], KOi1[8], KOi2[8], KOi3[8], KIi1[8], KIi2[8], KIi3[8], i;
|
||||
uint64_t A = ((uint64_t)cc) << 32, BLK = 0, _ca = ((uint64_t)CA << 16) ;
|
||||
A |= _ca;
|
||||
_ca = (uint64_t)((cb << 3) | (cd << 2)) << 24;
|
||||
A |= _ca;
|
||||
/* Register loading complete: see TR 55.919 8.2 and TS 55.216 3.2 */
|
||||
|
||||
uint8_t ck_km[16];
|
||||
for (i = 0; i < 16; i++)
|
||||
ck_km[i] = ck[i] ^ 0x55;
|
||||
/* Modified key established */
|
||||
|
||||
/* preliminary round with modified key */
|
||||
_kasumi_key_expand(ck_km, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
|
||||
A = _kasumi(A, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
|
||||
|
||||
/* Run Kasumi in OFB to obtain enough data for gamma. */
|
||||
_kasumi_key_expand(ck, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
|
||||
|
||||
/* i is a block counter */
|
||||
for (i = 0; i < cl / 64 + 1; i++) {
|
||||
BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
|
||||
osmo_store64be(BLK, co + (i * 8));
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*! \file kasumi.h
|
||||
* KASUMI header.
|
||||
*
|
||||
* See kasumi.c for details
|
||||
* The parameters are described in TS 135 202.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*! Single iteration of KASUMI cipher
|
||||
* \param[in] P Block, 64 bits to be processed in this round
|
||||
* \param[in] KLi1 Expanded subkeys
|
||||
* \param[in] KLi2 Expanded subkeys
|
||||
* \param[in] KOi1 Expanded subkeys
|
||||
* \param[in] KOi2 Expanded subkeys
|
||||
* \param[in] KOi3 Expanded subkeys
|
||||
* \param[in] KIi1 Expanded subkeys
|
||||
* \param[in] KIi2 Expanded subkeys
|
||||
* \param[in] KIi3 Expanded subkeys
|
||||
* \returns processed block of 64 bits
|
||||
*/
|
||||
uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3);
|
||||
|
||||
/*! Implementation of the KGCORE algorithm (used by A5/3, A5/4, GEA3, GEA4 and ECSD)
|
||||
* \param[in] CA
|
||||
* \param[in] cb
|
||||
* \param[in] cc
|
||||
* \param[in] cd
|
||||
* \param[in] ck 8-bytes long key
|
||||
* \param[out] co cl-dependent
|
||||
* \param[in] cl
|
||||
*/
|
||||
void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl);
|
||||
|
||||
/*! Expand key into set of subkeys - see TS 135 202 for details
|
||||
* \param[in] key (128 bits) as array of bytes
|
||||
* \param[out] KLi1 Expanded subkeys
|
||||
* \param[out] KLi2 Expanded subkeys
|
||||
* \param[out] KOi1 Expanded subkeys
|
||||
* \param[out] KOi2 Expanded subkeys
|
||||
* \param[out] KOi3 Expanded subkeys
|
||||
* \param[out] KIi1 Expanded subkeys
|
||||
* \param[out] KIi2 Expanded subkeys
|
||||
* \param[out] KIi3 Expanded subkeys
|
||||
*/
|
||||
void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue