blob: 34a5af010925b8fcda9ac7aab91c30f74f88d714 [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
95/* input some arbitrary (modulo 4) number of bytes of a 64k E1 channel,
96 * split it into the 16k subchannels */
97int subch_demux_in(struct subch_demux *dmx, u_int8_t *data, int len)
98{
99 int i, c;
100
101 /* we avoid partially filled bytes in outbuf */
102 if (len % 4)
103 return -EINVAL;
104
105 for (i = 0; i < len; i++) {
106 u_int8_t inbyte = data[i];
107
108 for (c = 0; c < NR_SUBCH; c++) {
109 struct subch *sch = &dmx->subch[c];
110 u_int8_t bit;
111
112 /* ignore inactive subchannels */
113 if (!(dmx->chan_activ & (1 << c)))
114 continue;
115
116 /* two bits for each subchannel */
117 if ((inbyte >> (c * 2)) & 0x01)
118 bit = 1;
119 else
120 bit = 0;
121 append_bit(sch, bit);
122
123 if (sync_hdr_complete(sch))
124 resync_to_here(sch);
125
126 if ((inbyte >> (c * 2)) & 0x02)
127 bit = 1;
128 else
129 bit = 0;
130 append_bit(sch, bit);
131
132 if (sync_hdr_complete(sch))
133 resync_to_here(sch);
134
135 /* FIXME: verify the first bit in octet 2, 4, 6, ...
136 * according to TS 08.60 4.8.1 */
137
138 /* once we have reached TRAU_FRAME_BITS, call
139 * the TRAU frame handler callback function */
140 if (sch->out_idx >= TRAU_FRAME_BITS) {
141 dmx->out_cb(dmx, c, sch->out_bitbuf,
142 sch->out_idx, dmx->data);
143 sch->out_idx = 0;
144 }
145 }
146 }
147 return i;
148}
149
150int subch_demux_activate(struct subch_demux *dmx, int subch)
151{
152 if (subch >= NR_SUBCH)
153 return -EINVAL;
154
155 dmx->chan_activ |= (1 << subch);
156 return 0;
157}
158
159int subch_demux_deactivate(struct subch_demux *dmx, int subch)
160{
161 if (subch >= NR_SUBCH)
162 return -EINVAL;
163
164 dmx->chan_activ &= ~(1 << subch);
165 return 0;
166}