blob: da1b090726e59e8b47a5172dbedbeeb55d23126b [file] [log] [blame]
Harald Welte54bd94d2009-01-05 19:00:01 +00001/* A E1 sub-channel demultiplexer with TRAU frame sync */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <unistd.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <errno.h>
27
28#include <openbsc/subchan_demux.h>
29
30static inline void append_bit(struct subch *sch, u_int8_t bit)
31{
32 sch->out_bitbuf[sch->out_idx++] = bit;
33}
34
35#define SYNC_HDR_BITS 16
36static const u_int8_t nullbytes[SYNC_HDR_BITS];
37
38/* check if we have just completed the 16 bit zero sync header,
39 * in accordance with GSM TS 08.60 Chapter 4.8.1 */
40static int sync_hdr_complete(struct subch *sch)
41{
42 int rc;
43 int bits_at_end = 0;
44 int bits_at_front;
45
46 if (sch->out_idx < SYNC_HDR_BITS)
47 bits_at_end = SYNC_HDR_BITS - sch->out_idx;
48 bits_at_front = sch->out_idx;
49
50 if (bits_at_end) {
51 rc = memcmp(sch->out_bitbuf + sizeof(sch->out_bitbuf) - bits_at_end,
52 nullbytes, bits_at_end);
53 if (rc)
54 return 0;
55 }
56 rc = memcmp(sch->out_bitbuf + sch->out_idx, nullbytes,
57 bits_at_front);
58 if (rc)
59 return 0;
60
61 return 1;
62}
63
64/* resynchronize to current location */
65static void resync_to_here(struct subch *sch)
66{
67#if 0
68 u_int8_t tmp[TRAU_FRAME_BITS];
69 int sync_hdr_start = sch->out_idx - SYNC_HDR_BITS;
70 int bytes_at_end;
71
72 /* first make copy of old bitbuf */
73 memcpy(tmp, sch->out_bitbuf, sizeof(tmp));
74
75 if (sync_hdr_start < 0)
76 sync_hdr_start += TRAU_FRAME_BITS;
77
78 bytes_at_end = TRAU_FRAME_BITS - sync_hdr_start;
79
80 /* copy part after sync_hdr_start */
81 memcpy(sch->out_bitbuf, tmp + sync_hdr_start, bytes_at_end);
82
83 /* copy part before sync_hdr_start */
84 memcpy(sch->out_bitbuf + bytes_at_end, tmp,
85 SYNC_HDR_BITS - bytes_at_end);
86#else
87 memset(sch->out_bitbuf, 0, SYNC_HDR_BITS);
88#endif
89
90 /* set index in a way that we can continue receiving bits after
91 * the end of the SYNC header */
92 sch->out_idx = SYNC_HDR_BITS;
93}
94
Harald Weltece281c02009-01-05 20:14:14 +000095int subch_demux_init(struct subch_demux *dmx)
96{
97 int i;
98
99 dmx->chan_activ = 0;
100 for (i = 0; i < NR_SUBCH; i++) {
101 struct subch *sch = &dmx->subch[i];
102 sch->out_idx = 0;
103 memset(sch->out_bitbuf, 0xff, sizeof(sch->out_bitbuf));
104 }
105 return 0;
106}
107
Harald Welte54bd94d2009-01-05 19:00:01 +0000108/* input some arbitrary (modulo 4) number of bytes of a 64k E1 channel,
109 * split it into the 16k subchannels */
110int subch_demux_in(struct subch_demux *dmx, u_int8_t *data, int len)
111{
112 int i, c;
113
114 /* we avoid partially filled bytes in outbuf */
115 if (len % 4)
116 return -EINVAL;
117
118 for (i = 0; i < len; i++) {
119 u_int8_t inbyte = data[i];
120
121 for (c = 0; c < NR_SUBCH; c++) {
122 struct subch *sch = &dmx->subch[c];
123 u_int8_t bit;
124
125 /* ignore inactive subchannels */
126 if (!(dmx->chan_activ & (1 << c)))
127 continue;
128
129 /* two bits for each subchannel */
130 if ((inbyte >> (c * 2)) & 0x01)
131 bit = 1;
132 else
133 bit = 0;
134 append_bit(sch, bit);
135
136 if (sync_hdr_complete(sch))
137 resync_to_here(sch);
138
139 if ((inbyte >> (c * 2)) & 0x02)
140 bit = 1;
141 else
142 bit = 0;
143 append_bit(sch, bit);
144
145 if (sync_hdr_complete(sch))
146 resync_to_here(sch);
147
148 /* FIXME: verify the first bit in octet 2, 4, 6, ...
149 * according to TS 08.60 4.8.1 */
150
151 /* once we have reached TRAU_FRAME_BITS, call
152 * the TRAU frame handler callback function */
153 if (sch->out_idx >= TRAU_FRAME_BITS) {
154 dmx->out_cb(dmx, c, sch->out_bitbuf,
155 sch->out_idx, dmx->data);
156 sch->out_idx = 0;
157 }
158 }
159 }
160 return i;
161}
162
163int subch_demux_activate(struct subch_demux *dmx, int subch)
164{
165 if (subch >= NR_SUBCH)
166 return -EINVAL;
167
168 dmx->chan_activ |= (1 << subch);
169 return 0;
170}
171
172int subch_demux_deactivate(struct subch_demux *dmx, int subch)
173{
174 if (subch >= NR_SUBCH)
175 return -EINVAL;
176
177 dmx->chan_activ &= ~(1 << subch);
178 return 0;
179}