blob: ac373aa80e0f4e9979a8207430305070f03ff151 [file] [log] [blame]
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02001/* TRAU frame handling according to GSM TS 08.60 */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
Harald Welte323d39d2017-11-13 01:09:21 +09006 * SPDX-License-Identifier: AGPL-3.0+
7 *
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22#include "internal.h"
23
24#include <unistd.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
29
Pablo Neira Ayuso177094b2011-06-07 12:21:51 +020030#include <osmocom/abis/trau_frame.h>
31#include <osmocom/abis/subchan_demux.h>
Pablo Neira Ayuso7b2d18b2011-06-05 18:38:43 +020032#include <osmocom/core/logging.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020033
Harald Welte2f69b892011-08-21 11:13:50 +020034/*! \addtogroup trau_frame
35 * @{
36 *
37 * \file trau_frame.c
38 */
39
Harald Welte5226e5b2020-05-07 23:09:16 +020040static uint32_t get_bits(const ubit_t *bitbuf, int offset, int num)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020041{
42 int i;
43 uint32_t ret = 0;
44
45 for (i = offset; i < offset + num; i++) {
46 ret = ret << 1;
47 if (bitbuf[i])
48 ret |= 1;
49 }
50 return ret;
51}
52
53/* Decode according to 3.1.1 */
Harald Welte6913b9a2020-05-07 23:11:50 +020054static void decode_fr(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020055{
56 int i;
57 int d_idx = 0;
58
59 /* C1 .. C15 */
60 memcpy(fr->c_bits+0, trau_bits+17, 15);
61 /* C16 .. C21 */
62 memcpy(fr->c_bits+15, trau_bits+310, 6);
63 /* T1 .. T4 */
64 memcpy(fr->t_bits+0, trau_bits+316, 4);
65 /* D1 .. D255 */
66 for (i = 32; i < 304; i+= 16) {
67 memcpy(fr->d_bits + d_idx, trau_bits+i+1, 15);
68 d_idx += 15;
69 }
70 /* D256 .. D260 */
71 memcpy(fr->d_bits + d_idx, trau_bits + 305, 5);
72}
73
74/* Decode according to 3.1.2 */
Harald Welte6913b9a2020-05-07 23:11:50 +020075static void decode_amr(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020076{
77 int i;
78 int d_idx = 0;
79
80 /* C1 .. C15 */
81 memcpy(fr->c_bits+0, trau_bits+17, 15);
82 /* C16 .. C25 */
83 memcpy(fr->c_bits+15, trau_bits+33, 10);
84 /* T1 .. T4 */
85 memcpy(fr->t_bits+0, trau_bits+316, 4);
86 /* D1 .. D5 */
87 memcpy(fr->d_bits, trau_bits+43, 5);
Harald Weltedb1bc212020-05-10 20:59:43 +020088 d_idx += 5;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020089 /* D6 .. D245 */
90 for (i = 48; i < 304; i += 16) {
91 memcpy(fr->d_bits + d_idx, trau_bits+i+1, 15);
92 d_idx += 15;
93 }
94 /* D246 .. D256 */
95 memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
96}
97
Harald Welte6913b9a2020-05-07 23:11:50 +020098static void decode_data(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Tobias Engelf6849762012-10-08 23:06:44 +020099{
100 /* C1 .. C15 */
101 memcpy(fr->c_bits+0, trau_bits+17, 15);
102 /* octets 4 .. 39 */
103 memcpy(fr->d_bits, trau_bits+32, 288);
104}
105
Harald Welte6913b9a2020-05-07 23:11:50 +0200106int decode_trau_frame(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200107{
108 uint8_t cbits5 = get_bits(trau_bits, 17, 5);
109
110 switch (cbits5) {
111 case TRAU_FT_FR_UP:
112 case TRAU_FT_FR_DOWN:
113 case TRAU_FT_IDLE_UP:
114 case TRAU_FT_IDLE_DOWN:
115 case TRAU_FT_EFR:
116 decode_fr(fr, trau_bits);
117 break;
118 case TRAU_FT_AMR:
119 decode_amr(fr, trau_bits);
120 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200121 case TRAU_FT_DATA_UP:
122 case TRAU_FT_DATA_DOWN:
Tobias Engelf6849762012-10-08 23:06:44 +0200123 decode_data(fr, trau_bits);
124 break;
125 case TRAU_FT_OM_UP:
126 case TRAU_FT_OM_DOWN:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200127 case TRAU_FT_D145_SYNC:
128 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200129 LOGP(DLMUX, LOGL_NOTICE, "can't decode unimplemented TRAU "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200130 "Frame Type 0x%02x\n", cbits5);
131 return -1;
132 break;
133 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200134 LOGP(DLMUX, LOGL_NOTICE, "can't decode unknown TRAU "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200135 "Frame Type 0x%02x\n", cbits5);
136 return -1;
137 break;
138 }
139
140 return 0;
141}
142
Harald Welte6913b9a2020-05-07 23:11:50 +0200143const ubit_t ft_fr_down_bits[] = { 1, 1, 1, 0, 0 };
144const ubit_t ft_idle_down_bits[] = { 0, 1, 1, 1, 0 };
145const ubit_t ft_data_down_bits[] = { 1, 0, 1, 1, 0 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200146
Harald Welte2f69b892011-08-21 11:13:50 +0200147/*! \brief modify an uplink TRAU frame so we can send it downlink
148 * \param[in,out] fr the uplink TRAU frame that is to be converted
149 * \returns 0 in case of success, < 0 in caes of error
150 */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200151int trau_frame_up2down(struct decoded_trau_frame *fr)
152{
153 uint8_t cbits5 = get_bits(fr->c_bits, 0, 5);
154
155 switch (cbits5) {
156 case TRAU_FT_FR_UP:
157 memcpy(fr->c_bits, ft_fr_down_bits, 5);
158 /* clear time alignment */
159 memset(fr->c_bits+5, 0, 6);
160 /* FIXME: SP / BFI in case of DTx */
161 /* C12 .. C21 are spare and coded as '1' */
162 memset(fr->c_bits+11, 0x01, 10);
163 break;
164 case TRAU_FT_EFR:
165 /* clear time alignment */
166 memset(fr->c_bits+5, 0, 6);
Dieter Spaaraa494242011-07-27 23:52:36 +0200167 /* set UFE appropriately */
168 fr->c_bits[11] = 1; /* C12 (UFE), good frame (TODO) */
169 /* C13 .. C15 are spare and coded as '1' */
170 memset(fr->c_bits+12, 0x01, 3);
171 /* SP / BFI in case of DTx */
172 fr->c_bits[15] = 1; /* C16 (SP), no DTX (TODO) */
173 /* C17 .. C21 are spare and coded as '1' */
174 memset(fr->c_bits+16, 0x01, 5);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200175 break;
176 case TRAU_FT_IDLE_UP:
177 memcpy(fr->c_bits, ft_idle_down_bits, 5);
178 /* clear time alignment */
179 memset(fr->c_bits+5, 0, 6);
180 /* FIXME: SP / BFI in case of DTx */
181 /* C12 .. C21 are spare and coded as '1' */
182 memset(fr->c_bits+11, 0x01, 10);
183 break;
Tobias Engelf6849762012-10-08 23:06:44 +0200184 case TRAU_FT_DATA_UP:
185 memcpy(fr->c_bits, ft_data_down_bits, 5);
186 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200187 case TRAU_FT_FR_DOWN:
188 case TRAU_FT_IDLE_DOWN:
189 case TRAU_FT_OM_DOWN:
190 case TRAU_FT_DATA_DOWN:
191 /* we cannot convert a downlink to a downlink frame */
192 return -EINVAL;
193 break;
194 case TRAU_FT_AMR:
195 case TRAU_FT_OM_UP:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200196 case TRAU_FT_D145_SYNC:
197 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200198 LOGP(DLMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200199 "0x%02x\n", cbits5);
200 return -1;
201 break;
202 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200203 LOGP(DLMUX, LOGL_NOTICE, "unknown TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200204 "0x%02x\n", cbits5);
205 return -1;
206 break;
207 }
208
209 return 0;
210
211}
212
Harald Welte6913b9a2020-05-07 23:11:50 +0200213static void encode_fr(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200214{
215 int i;
216 int d_idx = 0;
217
218 trau_bits[16] = 1;
219 /* C1 .. C15 */
220 memcpy(trau_bits+17, fr->c_bits+0, 15);
221 /* D1 .. D255 */
222 for (i = 32; i < 304; i+= 16) {
223 trau_bits[i] = 1;
224 memcpy(trau_bits+i+1, fr->d_bits + d_idx, 15);
225 d_idx += 15;
226 }
227 /* D256 .. D260 */
228 trau_bits[304] = 1;
229 memcpy(trau_bits + 305, fr->d_bits + d_idx, 5);
230 /* C16 .. C21 */
231 memcpy(trau_bits+310, fr->c_bits+15, 6);
232
233 /* FIXME: handle timing adjustment */
234
235 /* T1 .. T4 */
236 memcpy(trau_bits+316, fr->t_bits+0, 4);
237}
238
Harald Welte6913b9a2020-05-07 23:11:50 +0200239static void encode_data(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Tobias Engelf6849762012-10-08 23:06:44 +0200240{
241 trau_bits[16] = 1;
242 /* C1 .. C15 */
243 memcpy(trau_bits+17, fr->c_bits+0, 15);
244 /* octets 4 .. 39 */
245 memcpy(trau_bits+32, fr->d_bits, 288);
246}
247
Harald Welte2f69b892011-08-21 11:13:50 +0200248/*! \brief encode a TRAU frame from the decoded bits
249 * \param[out] trau_bits output buffer, will contain encoded bits
250 * \param[in] fr decoded trau frame structure
251 * \returns 0 in case of success, < 0 in case of error
252 */
Harald Welte6913b9a2020-05-07 23:11:50 +0200253int encode_trau_frame(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200254{
255 uint8_t cbits5 = get_bits(fr->c_bits, 0, 5);
256
257 /* 16 bits of sync header */
258 memset(trau_bits, 0, 16);
259
260 switch (cbits5) {
261 case TRAU_FT_FR_UP:
262 case TRAU_FT_FR_DOWN:
263 case TRAU_FT_IDLE_UP:
264 case TRAU_FT_IDLE_DOWN:
265 case TRAU_FT_EFR:
266 encode_fr(trau_bits, fr);
267 break;
Tobias Engelf6849762012-10-08 23:06:44 +0200268 case TRAU_FT_DATA_UP:
269 case TRAU_FT_DATA_DOWN:
270 encode_data(trau_bits, fr);
271 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200272 case TRAU_FT_AMR:
273 case TRAU_FT_OM_UP:
274 case TRAU_FT_OM_DOWN:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200275 case TRAU_FT_D145_SYNC:
276 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200277 LOGP(DLMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200278 "0x%02x\n", cbits5);
279 return -1;
280 break;
281 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200282 LOGP(DLMUX, LOGL_NOTICE, "unknown TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200283 "0x%02x\n", cbits5);
284 return -1;
285 break;
286 }
287
288 return 0;
289}
290
291static struct decoded_trau_frame fr_idle_frame = {
292 .c_bits = { 0, 1, 1, 1, 0 }, /* IDLE DOWNLINK 3.5.5 */
293 .t_bits = { 1, 1, 1, 1 },
294};
Harald Welte6913b9a2020-05-07 23:11:50 +0200295static ubit_t encoded_idle_frame[TRAU_FRAME_BITS];
Dieter Spaaraa494242011-07-27 23:52:36 +0200296static int dbits_initted = 0;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200297
Harald Welte2f69b892011-08-21 11:13:50 +0200298/*! \brief return pointer to global buffer containing a TRAU idle frame
299 */
Harald Welte6913b9a2020-05-07 23:11:50 +0200300ubit_t *trau_idle_frame(void)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200301{
302 /* only initialize during the first call */
303 if (!dbits_initted) {
304 /* set all D-bits to 1 */
305 memset(&fr_idle_frame.d_bits, 0x01, 260);
Dieter Spaaraa494242011-07-27 23:52:36 +0200306
307 memset(&fr_idle_frame.c_bits, 0x01, 25); /* spare are set to 1 */
308 /* set Downlink Idle Speech Frame pattern */
309 fr_idle_frame.c_bits[0] = 0; /* C1 */
310 fr_idle_frame.c_bits[1] = 1; /* C2 */
311 fr_idle_frame.c_bits[2] = 1; /* C3 */
312 fr_idle_frame.c_bits[3] = 1; /* C4 */
313 fr_idle_frame.c_bits[4] = 0; /* C5 */
314 /* set no Time Alignment pattern */
315 fr_idle_frame.c_bits[5] = 0; /* C6 */
316 fr_idle_frame.c_bits[6] = 0; /* C7 */
317 fr_idle_frame.c_bits[7] = 0; /* C8 */
318 fr_idle_frame.c_bits[8] = 0; /* C9 */
319 fr_idle_frame.c_bits[9] = 0; /* C10 */
320 fr_idle_frame.c_bits[10] = 0; /* C11 */
321 /* already set to 1, but maybe we need to modify it in the future */
322 fr_idle_frame.c_bits[11] = 1; /* C12 (UFE), good frame */
323 fr_idle_frame.c_bits[15] = 1; /* C16 (SP), no DTX */
324
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200325 encode_fr(encoded_idle_frame, &fr_idle_frame);
Dieter Spaaraa494242011-07-27 23:52:36 +0200326 dbits_initted = 1; /* set it to 1 to not call it again */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200327 }
328 return encoded_idle_frame;
329}
Harald Welte2f69b892011-08-21 11:13:50 +0200330
331/* }@ */