blob: 9558b3f56095073e5bb2329483511ee7e84d04d0 [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);
88 /* D6 .. D245 */
89 for (i = 48; i < 304; i += 16) {
90 memcpy(fr->d_bits + d_idx, trau_bits+i+1, 15);
91 d_idx += 15;
92 }
93 /* D246 .. D256 */
94 memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
95}
96
Harald Welte6913b9a2020-05-07 23:11:50 +020097static void decode_data(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Tobias Engelf6849762012-10-08 23:06:44 +020098{
99 /* C1 .. C15 */
100 memcpy(fr->c_bits+0, trau_bits+17, 15);
101 /* octets 4 .. 39 */
102 memcpy(fr->d_bits, trau_bits+32, 288);
103}
104
Harald Welte6913b9a2020-05-07 23:11:50 +0200105int decode_trau_frame(struct decoded_trau_frame *fr, const ubit_t *trau_bits)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200106{
107 uint8_t cbits5 = get_bits(trau_bits, 17, 5);
108
109 switch (cbits5) {
110 case TRAU_FT_FR_UP:
111 case TRAU_FT_FR_DOWN:
112 case TRAU_FT_IDLE_UP:
113 case TRAU_FT_IDLE_DOWN:
114 case TRAU_FT_EFR:
115 decode_fr(fr, trau_bits);
116 break;
117 case TRAU_FT_AMR:
118 decode_amr(fr, trau_bits);
119 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200120 case TRAU_FT_DATA_UP:
121 case TRAU_FT_DATA_DOWN:
Tobias Engelf6849762012-10-08 23:06:44 +0200122 decode_data(fr, trau_bits);
123 break;
124 case TRAU_FT_OM_UP:
125 case TRAU_FT_OM_DOWN:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200126 case TRAU_FT_D145_SYNC:
127 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200128 LOGP(DLMUX, LOGL_NOTICE, "can't decode unimplemented TRAU "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200129 "Frame Type 0x%02x\n", cbits5);
130 return -1;
131 break;
132 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200133 LOGP(DLMUX, LOGL_NOTICE, "can't decode unknown TRAU "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200134 "Frame Type 0x%02x\n", cbits5);
135 return -1;
136 break;
137 }
138
139 return 0;
140}
141
Harald Welte6913b9a2020-05-07 23:11:50 +0200142const ubit_t ft_fr_down_bits[] = { 1, 1, 1, 0, 0 };
143const ubit_t ft_idle_down_bits[] = { 0, 1, 1, 1, 0 };
144const ubit_t ft_data_down_bits[] = { 1, 0, 1, 1, 0 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200145
Harald Welte2f69b892011-08-21 11:13:50 +0200146/*! \brief modify an uplink TRAU frame so we can send it downlink
147 * \param[in,out] fr the uplink TRAU frame that is to be converted
148 * \returns 0 in case of success, < 0 in caes of error
149 */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200150int trau_frame_up2down(struct decoded_trau_frame *fr)
151{
152 uint8_t cbits5 = get_bits(fr->c_bits, 0, 5);
153
154 switch (cbits5) {
155 case TRAU_FT_FR_UP:
156 memcpy(fr->c_bits, ft_fr_down_bits, 5);
157 /* clear time alignment */
158 memset(fr->c_bits+5, 0, 6);
159 /* FIXME: SP / BFI in case of DTx */
160 /* C12 .. C21 are spare and coded as '1' */
161 memset(fr->c_bits+11, 0x01, 10);
162 break;
163 case TRAU_FT_EFR:
164 /* clear time alignment */
165 memset(fr->c_bits+5, 0, 6);
Dieter Spaaraa494242011-07-27 23:52:36 +0200166 /* set UFE appropriately */
167 fr->c_bits[11] = 1; /* C12 (UFE), good frame (TODO) */
168 /* C13 .. C15 are spare and coded as '1' */
169 memset(fr->c_bits+12, 0x01, 3);
170 /* SP / BFI in case of DTx */
171 fr->c_bits[15] = 1; /* C16 (SP), no DTX (TODO) */
172 /* C17 .. C21 are spare and coded as '1' */
173 memset(fr->c_bits+16, 0x01, 5);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200174 break;
175 case TRAU_FT_IDLE_UP:
176 memcpy(fr->c_bits, ft_idle_down_bits, 5);
177 /* clear time alignment */
178 memset(fr->c_bits+5, 0, 6);
179 /* FIXME: SP / BFI in case of DTx */
180 /* C12 .. C21 are spare and coded as '1' */
181 memset(fr->c_bits+11, 0x01, 10);
182 break;
Tobias Engelf6849762012-10-08 23:06:44 +0200183 case TRAU_FT_DATA_UP:
184 memcpy(fr->c_bits, ft_data_down_bits, 5);
185 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200186 case TRAU_FT_FR_DOWN:
187 case TRAU_FT_IDLE_DOWN:
188 case TRAU_FT_OM_DOWN:
189 case TRAU_FT_DATA_DOWN:
190 /* we cannot convert a downlink to a downlink frame */
191 return -EINVAL;
192 break;
193 case TRAU_FT_AMR:
194 case TRAU_FT_OM_UP:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200195 case TRAU_FT_D145_SYNC:
196 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200197 LOGP(DLMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200198 "0x%02x\n", cbits5);
199 return -1;
200 break;
201 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200202 LOGP(DLMUX, LOGL_NOTICE, "unknown TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200203 "0x%02x\n", cbits5);
204 return -1;
205 break;
206 }
207
208 return 0;
209
210}
211
Harald Welte6913b9a2020-05-07 23:11:50 +0200212static void encode_fr(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200213{
214 int i;
215 int d_idx = 0;
216
217 trau_bits[16] = 1;
218 /* C1 .. C15 */
219 memcpy(trau_bits+17, fr->c_bits+0, 15);
220 /* D1 .. D255 */
221 for (i = 32; i < 304; i+= 16) {
222 trau_bits[i] = 1;
223 memcpy(trau_bits+i+1, fr->d_bits + d_idx, 15);
224 d_idx += 15;
225 }
226 /* D256 .. D260 */
227 trau_bits[304] = 1;
228 memcpy(trau_bits + 305, fr->d_bits + d_idx, 5);
229 /* C16 .. C21 */
230 memcpy(trau_bits+310, fr->c_bits+15, 6);
231
232 /* FIXME: handle timing adjustment */
233
234 /* T1 .. T4 */
235 memcpy(trau_bits+316, fr->t_bits+0, 4);
236}
237
Harald Welte6913b9a2020-05-07 23:11:50 +0200238static void encode_data(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Tobias Engelf6849762012-10-08 23:06:44 +0200239{
240 trau_bits[16] = 1;
241 /* C1 .. C15 */
242 memcpy(trau_bits+17, fr->c_bits+0, 15);
243 /* octets 4 .. 39 */
244 memcpy(trau_bits+32, fr->d_bits, 288);
245}
246
Harald Welte2f69b892011-08-21 11:13:50 +0200247/*! \brief encode a TRAU frame from the decoded bits
248 * \param[out] trau_bits output buffer, will contain encoded bits
249 * \param[in] fr decoded trau frame structure
250 * \returns 0 in case of success, < 0 in case of error
251 */
Harald Welte6913b9a2020-05-07 23:11:50 +0200252int encode_trau_frame(ubit_t *trau_bits, const struct decoded_trau_frame *fr)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200253{
254 uint8_t cbits5 = get_bits(fr->c_bits, 0, 5);
255
256 /* 16 bits of sync header */
257 memset(trau_bits, 0, 16);
258
259 switch (cbits5) {
260 case TRAU_FT_FR_UP:
261 case TRAU_FT_FR_DOWN:
262 case TRAU_FT_IDLE_UP:
263 case TRAU_FT_IDLE_DOWN:
264 case TRAU_FT_EFR:
265 encode_fr(trau_bits, fr);
266 break;
Tobias Engelf6849762012-10-08 23:06:44 +0200267 case TRAU_FT_DATA_UP:
268 case TRAU_FT_DATA_DOWN:
269 encode_data(trau_bits, fr);
270 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200271 case TRAU_FT_AMR:
272 case TRAU_FT_OM_UP:
273 case TRAU_FT_OM_DOWN:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200274 case TRAU_FT_D145_SYNC:
275 case TRAU_FT_EDATA:
Harald Weltecc2241b2011-07-19 16:06:06 +0200276 LOGP(DLMUX, LOGL_NOTICE, "unimplemented TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200277 "0x%02x\n", cbits5);
278 return -1;
279 break;
280 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200281 LOGP(DLMUX, LOGL_NOTICE, "unknown TRAU Frame Type "
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200282 "0x%02x\n", cbits5);
283 return -1;
284 break;
285 }
286
287 return 0;
288}
289
290static struct decoded_trau_frame fr_idle_frame = {
291 .c_bits = { 0, 1, 1, 1, 0 }, /* IDLE DOWNLINK 3.5.5 */
292 .t_bits = { 1, 1, 1, 1 },
293};
Harald Welte6913b9a2020-05-07 23:11:50 +0200294static ubit_t encoded_idle_frame[TRAU_FRAME_BITS];
Dieter Spaaraa494242011-07-27 23:52:36 +0200295static int dbits_initted = 0;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200296
Harald Welte2f69b892011-08-21 11:13:50 +0200297/*! \brief return pointer to global buffer containing a TRAU idle frame
298 */
Harald Welte6913b9a2020-05-07 23:11:50 +0200299ubit_t *trau_idle_frame(void)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200300{
301 /* only initialize during the first call */
302 if (!dbits_initted) {
303 /* set all D-bits to 1 */
304 memset(&fr_idle_frame.d_bits, 0x01, 260);
Dieter Spaaraa494242011-07-27 23:52:36 +0200305
306 memset(&fr_idle_frame.c_bits, 0x01, 25); /* spare are set to 1 */
307 /* set Downlink Idle Speech Frame pattern */
308 fr_idle_frame.c_bits[0] = 0; /* C1 */
309 fr_idle_frame.c_bits[1] = 1; /* C2 */
310 fr_idle_frame.c_bits[2] = 1; /* C3 */
311 fr_idle_frame.c_bits[3] = 1; /* C4 */
312 fr_idle_frame.c_bits[4] = 0; /* C5 */
313 /* set no Time Alignment pattern */
314 fr_idle_frame.c_bits[5] = 0; /* C6 */
315 fr_idle_frame.c_bits[6] = 0; /* C7 */
316 fr_idle_frame.c_bits[7] = 0; /* C8 */
317 fr_idle_frame.c_bits[8] = 0; /* C9 */
318 fr_idle_frame.c_bits[9] = 0; /* C10 */
319 fr_idle_frame.c_bits[10] = 0; /* C11 */
320 /* already set to 1, but maybe we need to modify it in the future */
321 fr_idle_frame.c_bits[11] = 1; /* C12 (UFE), good frame */
322 fr_idle_frame.c_bits[15] = 1; /* C16 (SP), no DTX */
323
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200324 encode_fr(encoded_idle_frame, &fr_idle_frame);
Dieter Spaaraa494242011-07-27 23:52:36 +0200325 dbits_initted = 1; /* set it to 1 to not call it again */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200326 }
327 return encoded_idle_frame;
328}
Harald Welte2f69b892011-08-21 11:13:50 +0200329
330/* }@ */