/* A E1 sub-channel demultiplexer with TRAU frame sync */ /* (C) 2009 by Harald Welte * 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. * */ #include #include #include #include #include #include static inline void append_bit(struct subch *sch, u_int8_t bit) { sch->out_bitbuf[sch->out_idx++] = bit; } #define SYNC_HDR_BITS 16 static const u_int8_t nullbytes[SYNC_HDR_BITS]; /* check if we have just completed the 16 bit zero sync header, * in accordance with GSM TS 08.60 Chapter 4.8.1 */ static int sync_hdr_complete(struct subch *sch) { int rc; int bits_at_end = 0; int bits_at_front; if (sch->out_idx < SYNC_HDR_BITS) bits_at_end = SYNC_HDR_BITS - sch->out_idx; bits_at_front = sch->out_idx; if (bits_at_end) { rc = memcmp(sch->out_bitbuf + sizeof(sch->out_bitbuf) - bits_at_end, nullbytes, bits_at_end); if (rc) return 0; } rc = memcmp(sch->out_bitbuf + sch->out_idx, nullbytes, bits_at_front); if (rc) return 0; return 1; } /* resynchronize to current location */ static void resync_to_here(struct subch *sch) { #if 0 u_int8_t tmp[TRAU_FRAME_BITS]; int sync_hdr_start = sch->out_idx - SYNC_HDR_BITS; int bytes_at_end; /* first make copy of old bitbuf */ memcpy(tmp, sch->out_bitbuf, sizeof(tmp)); if (sync_hdr_start < 0) sync_hdr_start += TRAU_FRAME_BITS; bytes_at_end = TRAU_FRAME_BITS - sync_hdr_start; /* copy part after sync_hdr_start */ memcpy(sch->out_bitbuf, tmp + sync_hdr_start, bytes_at_end); /* copy part before sync_hdr_start */ memcpy(sch->out_bitbuf + bytes_at_end, tmp, SYNC_HDR_BITS - bytes_at_end); #else memset(sch->out_bitbuf, 0, SYNC_HDR_BITS); #endif /* set index in a way that we can continue receiving bits after * the end of the SYNC header */ sch->out_idx = SYNC_HDR_BITS; } int subch_demux_init(struct subch_demux *dmx) { int i; dmx->chan_activ = 0; for (i = 0; i < NR_SUBCH; i++) { struct subch *sch = &dmx->subch[i]; sch->out_idx = 0; memset(sch->out_bitbuf, 0xff, sizeof(sch->out_bitbuf)); } return 0; } /* input some arbitrary (modulo 4) number of bytes of a 64k E1 channel, * split it into the 16k subchannels */ int subch_demux_in(struct subch_demux *dmx, u_int8_t *data, int len) { int i, c; /* we avoid partially filled bytes in outbuf */ if (len % 4) return -EINVAL; for (i = 0; i < len; i++) { u_int8_t inbyte = data[i]; for (c = 0; c < NR_SUBCH; c++) { struct subch *sch = &dmx->subch[c]; u_int8_t bit; /* ignore inactive subchannels */ if (!(dmx->chan_activ & (1 << c))) continue; /* two bits for each subchannel */ if ((inbyte >> (c * 2)) & 0x01) bit = 1; else bit = 0; append_bit(sch, bit); if (sync_hdr_complete(sch)) resync_to_here(sch); if ((inbyte >> (c * 2)) & 0x02) bit = 1; else bit = 0; append_bit(sch, bit); if (sync_hdr_complete(sch)) resync_to_here(sch); /* FIXME: verify the first bit in octet 2, 4, 6, ... * according to TS 08.60 4.8.1 */ /* once we have reached TRAU_FRAME_BITS, call * the TRAU frame handler callback function */ if (sch->out_idx >= TRAU_FRAME_BITS) { dmx->out_cb(dmx, c, sch->out_bitbuf, sch->out_idx, dmx->data); sch->out_idx = 0; } } } return i; } int subch_demux_activate(struct subch_demux *dmx, int subch) { if (subch >= NR_SUBCH) return -EINVAL; dmx->chan_activ |= (1 << subch); return 0; } int subch_demux_deactivate(struct subch_demux *dmx, int subch) { if (subch >= NR_SUBCH) return -EINVAL; dmx->chan_activ &= ~(1 << subch); return 0; }